/* 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; }
/* %start-doc actions SmartDisperse The @code{SmartDisperse([All|Selected])} action is a special-purpose optimization for dispersing elements. Run with @code{:SmartDisperse()} or @code{:SmartDisperse(Selected)} (you can also say @code{:SmartDisperse(All)}, but that's the default). %end-doc */ static int smartdisperse (int argc, char **argv, Coord x, Coord y) { char *function = ARG(0); NetListType *Nets; char *visited; // PointerListType stack = { 0, 0, NULL }; int all; // int changed = 0; // int i; if (! function) { all = 1; } else if (strcmp(function, "All") == 0) { all = 1; } else if (strcmp(function, "Selected") == 0) { all = 0; } else { AFAIL (smartdisperse); } Nets = ProcNetlist (&PCB->NetlistLib); if (! Nets) { Message (_("Can't use SmartDisperse because no netlist is loaded.\n")); return 0; } /* remember which elements we finish with */ visited = calloc (PCB->Data->ElementN, sizeof(*visited)); /* if we're not doing all, mark the unselected elements as "visited" */ ELEMENT_LOOP (PCB->Data); { if (! (all || TEST_FLAG (SELECTEDFLAG, element))) { visited[n] = 1; } } END_LOOP; /* initialize variables for place() */ minx = GAP; miny = GAP; maxx = GAP; maxy = GAP; /* * Pick nets with two connections. This is the start of a more * elaborate algorithm to walk serial nets, but the datastructures * are too gross so I'm going with the 80% solution. */ NET_LOOP (Nets); { ConnectionType *conna, *connb; ElementType *ea, *eb; // ElementType *epp; if (net->ConnectionN != 2) continue; conna = &net->Connection[0]; connb = &net->Connection[1]; if (!IS_ELEMENT(conna) || !IS_ELEMENT(conna)) continue; ea = (ElementType *) conna->ptr1; eb = (ElementType *) connb->ptr1; /* place this pair if possible */ if (VISITED((GList *)ea) || VISITED((GList *)eb)) continue; VISITED ((GList *)ea) = 1; VISITED ((GList *)eb) = 1; /* a weak attempt to get the linked pads side-by-side */ if (padorder(conna, connb)) { place ((ElementType *) ea); place ((ElementType *) eb); } else { place (eb); place (ea); } } END_LOOP; /* Place larger nets, still grouping by net */ NET_LOOP (Nets); { CONNECTION_LOOP (net); { ElementType *element; if (! IS_ELEMENT(connection)) continue; element = (ElementType *) connection->ptr1; /* place this one if needed */ if (VISITED ((GList *) element)) continue; VISITED ((GList *) element) = 1; place (element); } END_LOOP; } END_LOOP; /* Place up anything else */ ELEMENT_LOOP (PCB->Data); { if (! visited[n]) { place (element); } } END_LOOP; free (visited); IncrementUndoSerialNumber (); Redraw (); SetChangedFlag (1); return 0; }
/* --------------------------------------------------------------------------- * Auto-place selected components. */ bool AutoPlaceSelected (void) { NetListTypePtr Nets; PointerListType Selected = { 0, 0, NULL }; PerturbationType pt; double C0, T0; bool changed = false; /* (initial netlist processing copied from AddAllRats) */ /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Nets = ProcNetlist (&PCB->NetlistLib); if (!Nets) { Message (_("Can't add rat lines because no netlist is loaded.\n")); goto done; } Selected = collectSelectedElements (); if (Selected.PtrN == 0) { Message (_("No elements selected to autoplace.\n")); goto done; } /* simulated annealing */ { /* compute T0 by doing a random series of moves. */ const int TRIALS = 10; const double Tx = 3e5, P = 0.95; double Cs = 0.0; int i; C0 = ComputeCost (Nets, Tx, Tx); for (i = 0; i < TRIALS; i++) { pt = createPerturbation (&Selected, 1e6); doPerturb (&pt, false); Cs += fabs (ComputeCost (Nets, Tx, Tx) - C0); doPerturb (&pt, true); } T0 = -(Cs / TRIALS) / log (P); printf ("Initial T: %f\n", T0); } /* now anneal in earnest */ { double T = T0; long steps = 0; int good_moves = 0, moves = 0; const int good_move_cutoff = CostParameter.m * Selected.PtrN; const int move_cutoff = 2 * good_move_cutoff; printf ("Starting cost is %.0f\n", ComputeCost (Nets, T0, 5)); C0 = ComputeCost (Nets, T0, T); while (1) { double Cprime; pt = createPerturbation (&Selected, T); doPerturb (&pt, false); Cprime = ComputeCost (Nets, T0, T); if (Cprime < C0) { /* good move! */ C0 = Cprime; good_moves++; steps++; } else if ((random () / (double) RAND_MAX) < exp (MIN (MAX (-20, (C0 - Cprime) / T), 20))) { /* not good but keep it anyway */ C0 = Cprime; steps++; } else doPerturb (&pt, true); /* undo last change */ moves++; /* are we at the end of a stage? */ if (good_moves >= good_move_cutoff || moves >= move_cutoff) { printf ("END OF STAGE: COST %.0f\t" "GOOD_MOVES %d\tMOVES %d\t" "T: %.1f\n", C0, good_moves, moves, T); /* is this the end? */ if (T < 5 || good_moves < moves / CostParameter.good_ratio) break; /* nope, adjust T and continue */ moves = good_moves = 0; T *= CostParameter.gamma; /* cost is T dependent, so recompute */ C0 = ComputeCost (Nets, T0, T); } } changed = (steps > 0); } done: if (changed) { DeleteRats (false); AddAllRats (false, NULL); ClearAndRedrawOutput (); } FreePointerListMemory (&Selected); return (changed); }
/*! * \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); }