/* destroy an "empty space" representation. */ void mtspace_destroy (mtspace_t ** mtspacep) { assert (mtspacep); r_destroy_tree (&(*mtspacep)->ftree); r_destroy_tree (&(*mtspacep)->etree); r_destroy_tree (&(*mtspacep)->otree); free (*mtspacep); *mtspacep = NULL; }
/* --------------------------------------------------------------------------- * get next slot for an element, allocates memory if necessary */ ElementTypePtr GetElementMemory (DataTypePtr Data) { ElementTypePtr element = Data->Element; int i; /* realloc new memory if necessary and clear it */ if (Data->ElementN >= Data->ElementMax) { Data->ElementMax += STEP_ELEMENT; if (Data->element_tree) r_destroy_tree (&Data->element_tree); element = MyRealloc (element, Data->ElementMax * sizeof (ElementType), "GetElementMemory()"); Data->Element = element; memset (element + Data->ElementN, 0, STEP_ELEMENT * sizeof (ElementType)); Data->element_tree = r_create_tree (NULL, 0, 0); for (i = 0; i < MAX_ELEMENTNAMES; i++) { if (Data->name_tree[i]) r_destroy_tree (&Data->name_tree[i]); Data->name_tree[i] = r_create_tree (NULL, 0, 0); } ELEMENT_LOOP (Data); { r_insert_entry (Data->element_tree, (BoxType *) element, 0); PIN_LOOP (element); { pin->Element = element; } END_LOOP; PAD_LOOP (element); { pad->Element = element; } END_LOOP; ELEMENTTEXT_LOOP (element); { text->Element = element; r_insert_entry (Data->name_tree[n], (BoxType *) text, 0); } END_LOOP; } END_LOOP; } return (element + Data->ElementN++); }
/* --------------------------------------------------------------------------- * get next slot for a polygon object, allocates memory if necessary */ PolygonTypePtr GetPolygonMemory (LayerTypePtr Layer) { PolygonTypePtr polygon = Layer->Polygon; /* realloc new memory if necessary and clear it */ if (Layer->PolygonN >= Layer->PolygonMax) { Layer->PolygonMax += STEP_POLYGON; if (Layer->polygon_tree) r_destroy_tree (&Layer->polygon_tree); polygon = MyRealloc (polygon, Layer->PolygonMax * sizeof (PolygonType), "GetPolygonMemory()"); Layer->Polygon = polygon; memset (polygon + Layer->PolygonN, 0, STEP_POLYGON * sizeof (PolygonType)); Layer->polygon_tree = r_create_tree (NULL, 0, 0); POLYGON_LOOP (Layer); { r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0); } END_LOOP; } return (polygon + Layer->PolygonN++); }
/* --------------------------------------------------------------------------- * get next slot for a line, allocates memory if necessary */ LineTypePtr GetLineMemory (LayerTypePtr Layer) { LineTypePtr line = Layer->Line; /* realloc new memory if necessary and clear it */ if (Layer->LineN >= Layer->LineMax) { Layer->LineMax += STEP_LINE; /* all of the pointers move, so rebuild the whole tree */ if (Layer->line_tree) r_destroy_tree (&Layer->line_tree); line = MyRealloc (line, Layer->LineMax * sizeof (LineType), "GetLineMemory()"); Layer->Line = line; memset (line + Layer->LineN, 0, STEP_LINE * sizeof (LineType)); Layer->line_tree = r_create_tree (NULL, 0, 0); LINE_LOOP (Layer); { r_insert_entry (Layer->line_tree, (BoxTypePtr) line, 0); } END_LOOP; } return (line + Layer->LineN++); }
/* --------------------------------------------------------------------------- * get next slot for a Rat, allocates memory if necessary */ RatTypePtr GetRatMemory (DataTypePtr Data) { RatTypePtr rat = Data->Rat; /* realloc new memory if necessary and clear it */ if (Data->RatN >= Data->RatMax) { Data->RatMax += STEP_RAT; /* all of the pointers move, so rebuild the whole tree */ if (Data->rat_tree) r_destroy_tree (&Data->rat_tree); rat = MyRealloc (rat, Data->RatMax * sizeof (RatType), "GetRatMemory()"); Data->Rat = rat; memset (rat + Data->RatN, 0, STEP_RAT * sizeof (RatType)); Data->rat_tree = r_create_tree (NULL, 0, 0); RAT_LOOP (Data); { r_insert_entry (Data->rat_tree, (BoxTypePtr) line, 0); } END_LOOP; } return (rat + Data->RatN++); }
/* --------------------------------------------------------------------------- * get next slot for a text object, allocates memory if necessary */ TextTypePtr GetTextMemory (LayerTypePtr Layer) { TextTypePtr text = Layer->Text; /* realloc new memory if necessary and clear it */ if (Layer->TextN >= Layer->TextMax) { Layer->TextMax += STEP_TEXT; if (Layer->text_tree) r_destroy_tree (&Layer->text_tree); text = (TextTypePtr)realloc (text, Layer->TextMax * sizeof (TextType)); Layer->Text = text; memset (text + Layer->TextN, 0, STEP_TEXT * sizeof (TextType)); Layer->text_tree = r_create_tree (NULL, 0, 0); TEXT_LOOP (Layer); { r_insert_entry (Layer->text_tree, (BoxTypePtr) text, 0); } END_LOOP; } return (text + Layer->TextN++); }
/* --------------------------------------------------------------------------- * get next slot for an arc, allocates memory if necessary */ ArcTypePtr GetArcMemory (LayerTypePtr Layer) { ArcTypePtr arc = Layer->Arc; /* realloc new memory if necessary and clear it */ if (Layer->ArcN >= Layer->ArcMax) { Layer->ArcMax += STEP_ARC; if (Layer->arc_tree) r_destroy_tree (&Layer->arc_tree); arc = (ArcTypePtr)realloc (arc, Layer->ArcMax * sizeof (ArcType)); Layer->Arc = arc; memset (arc + Layer->ArcN, 0, STEP_ARC * sizeof (ArcType)); Layer->arc_tree = r_create_tree (NULL, 0, 0); ARC_LOOP (Layer); { r_insert_entry (Layer->arc_tree, (BoxTypePtr) arc, 0); } END_LOOP; } return (arc + Layer->ArcN++); }
/* --------------------------------------------------------------------------- * get next slot for a via, allocates memory if necessary */ PinTypePtr GetViaMemory (DataTypePtr Data) { PinTypePtr via = Data->Via; /* realloc new memory if necessary and clear it */ if (Data->ViaN >= Data->ViaMax) { Data->ViaMax += STEP_VIA; if (Data->via_tree) r_destroy_tree (&Data->via_tree); via = (PinTypePtr)realloc (via, Data->ViaMax * sizeof (PinType)); Data->Via = via; memset (via + Data->ViaN, 0, STEP_VIA * sizeof (PinType)); Data->via_tree = r_create_tree (NULL, 0, 0); VIA_LOOP (Data); { r_insert_entry (Data->via_tree, (BoxType *) via, 0); } END_LOOP; } return (via + Data->ViaN++); }
/* --------------------------------------------------------------------------- * Compute cost function. * note that area overlap cost is correct for SMD devices: SMD devices on * opposite sides of the board don't overlap. * * Algorithms follow those described in sections 4.1 of * "Placement and Routing of Electronic Modules" edited by Michael Pecht * Marcel Dekker, Inc. 1993. ISBN: 0-8247-8916-4 TK7868.P7.P57 1993 */ static double ComputeCost (NetListTypePtr Nets, double T0, double T) { double W = 0; /* wire cost */ double delta1 = 0; /* wire congestion penalty function */ double delta2 = 0; /* module overlap penalty function */ double delta3 = 0; /* out of bounds penalty */ double delta4 = 0; /* alignment bonus */ double delta5 = 0; /* total area penalty */ Cardinal i, j; LocationType minx, maxx, miny, maxy; bool allpads, allsameside; Cardinal thegroup; BoxListType bounds = { 0, 0, NULL }; /* save bounding rectangles here */ BoxListType solderside = { 0, 0, NULL }; /* solder side component bounds */ BoxListType componentside = { 0, 0, NULL }; /* component side bounds */ /* make sure the NetList have the proper updated X and Y coords */ UpdateXY (Nets); /* wire length term. approximated by half-perimeter of minimum * rectangle enclosing the net. Note that we penalize vias in * all-SMD nets by making the rectangle a cube and weighting * the "layer height" of the net. */ for (i = 0; i < Nets->NetN; i++) { NetTypePtr n = &Nets->Net[i]; if (n->ConnectionN < 2) continue; /* no cost to go nowhere */ minx = maxx = n->Connection[0].X; miny = maxy = n->Connection[0].Y; thegroup = n->Connection[0].group; allpads = (n->Connection[0].type == PAD_TYPE); allsameside = true; for (j = 1; j < n->ConnectionN; j++) { ConnectionTypePtr c = &(n->Connection[j]); MAKEMIN (minx, c->X); MAKEMAX (maxx, c->X); MAKEMIN (miny, c->Y); MAKEMAX (maxy, c->Y); if (c->type != PAD_TYPE) allpads = false; if (c->group != thegroup) allsameside = false; } /* save bounding rectangle */ { BoxTypePtr box = GetBoxMemory (&bounds); box->X1 = minx; box->Y1 = miny; box->X2 = maxx; box->Y2 = maxy; } /* okay, add half-perimeter to cost! */ W += (maxx - minx) / 100 + (maxy - miny) / 100 + ((allpads && !allsameside) ? CostParameter.via_cost : 0); } /* now compute penalty function Wc which is proportional to * amount of overlap and congestion. */ /* delta1 is congestion penalty function */ delta1 = CostParameter.congestion_penalty * sqrt (fabs (ComputeIntersectionArea (&bounds))); #if 0 printf ("Wire Congestion Area: %f\n", ComputeIntersectionArea (&bounds)); #endif /* free bounding rectangles */ FreeBoxListMemory (&bounds); /* now collect module areas (bounding rect of pins/pads) */ /* two lists for solder side / component side. */ ELEMENT_LOOP (PCB->Data); { BoxListTypePtr thisside; BoxListTypePtr otherside; BoxTypePtr box; BoxTypePtr lastbox = NULL; BDimension thickness; BDimension clearance; if (TEST_FLAG (ONSOLDERFLAG, element)) { thisside = &solderside; otherside = &componentside; } else { thisside = &componentside; otherside = &solderside; } box = GetBoxMemory (thisside); /* protect against elements with no pins/pads */ if (element->PinN == 0 && element->PadN == 0) continue; /* initialize box so that it will take the dimensions of * the first pin/pad */ box->X1 = MAX_COORD; box->Y1 = MAX_COORD; box->X2 = -MAX_COORD; box->Y2 = -MAX_COORD; PIN_LOOP (element); { thickness = pin->Thickness / 2; clearance = pin->Clearance * 2; EXPANDRECTXY (box, pin->X - (thickness + clearance), pin->Y - (thickness + clearance), pin->X + (thickness + clearance), pin->Y + (thickness + clearance))} END_LOOP; PAD_LOOP (element); { thickness = pad->Thickness / 2; clearance = pad->Clearance * 2; EXPANDRECTXY (box, MIN (pad->Point1.X, pad->Point2.X) - (thickness + clearance), MIN (pad->Point1.Y, pad->Point2.Y) - (thickness + clearance), MAX (pad->Point1.X, pad->Point2.X) + (thickness + clearance), MAX (pad->Point1.Y, pad->Point2.Y) + (thickness + clearance))} END_LOOP; /* add a box for each pin to the "opposite side": * surface mount components can't sit on top of pins */ if (!CostParameter.fast) PIN_LOOP (element); { box = GetBoxMemory (otherside); thickness = pin->Thickness / 2; clearance = pin->Clearance * 2; /* we ignore clearance here */ /* (otherwise pins don't fit next to each other) */ box->X1 = pin->X - thickness; box->Y1 = pin->Y - thickness; box->X2 = pin->X + thickness; box->Y2 = pin->Y + thickness; /* speed hack! coalesce with last box if we can */ if (lastbox != NULL && ((lastbox->X1 == box->X1 && lastbox->X2 == box->X2 && MIN (abs (lastbox->Y1 - box->Y2), abs (box->Y1 - lastbox->Y2)) < clearance) || (lastbox->Y1 == box->Y1 && lastbox->Y2 == box->Y2 && MIN (abs (lastbox->X1 - box->X2), abs (box->X1 - lastbox->X2)) < clearance))) { EXPANDRECT (lastbox, box); otherside->BoxN--; } else lastbox = box; } END_LOOP; /* assess out of bounds penalty */ if (element->VBox.X1 < 0 || element->VBox.Y1 < 0 || element->VBox.X2 > PCB->MaxWidth || element->VBox.Y2 > PCB->MaxHeight) delta3 += CostParameter.out_of_bounds_penalty; } END_LOOP; /* compute intersection area of module areas box list */ delta2 = sqrt (fabs (ComputeIntersectionArea (&solderside) + ComputeIntersectionArea (&componentside))) * (CostParameter.overlap_penalty_min + (1 - (T / T0)) * CostParameter.overlap_penalty_max); #if 0 printf ("Module Overlap Area (solder): %f\n", ComputeIntersectionArea (&solderside)); printf ("Module Overlap Area (component): %f\n", ComputeIntersectionArea (&componentside)); #endif FreeBoxListMemory (&solderside); FreeBoxListMemory (&componentside); /* reward pin/pad x/y alignment */ /* score higher if pins/pads belong to same *type* of component */ /* XXX: subkey should be *distance* from thing aligned with, so that * aligning to something far away isn't profitable */ { /* create r tree */ PointerListType seboxes = { 0, 0, NULL } , ceboxes = { 0, 0, NULL}; struct ebox { BoxType box; ElementTypePtr element; }; direction_t dir[4] = { NORTH, EAST, SOUTH, WEST }; struct ebox **boxpp, *boxp; rtree_t *rt_s, *rt_c; int factor; ELEMENT_LOOP (PCB->Data); { boxpp = (struct ebox **) GetPointerMemory (TEST_FLAG (ONSOLDERFLAG, element) ? &seboxes : &ceboxes); *boxpp = malloc (sizeof (**boxpp)); if (*boxpp == NULL ) { fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__); exit (1); } (*boxpp)->box = element->VBox; (*boxpp)->element = element; } END_LOOP; rt_s = r_create_tree ((const BoxType **) seboxes.Ptr, seboxes.PtrN, 1); rt_c = r_create_tree ((const BoxType **) ceboxes.Ptr, ceboxes.PtrN, 1); FreePointerListMemory (&seboxes); FreePointerListMemory (&ceboxes); /* now, for each element, find its neighbor on all four sides */ delta4 = 0; for (i = 0; i < 4; i++) ELEMENT_LOOP (PCB->Data); { boxp = (struct ebox *) r_find_neighbor (TEST_FLAG (ONSOLDERFLAG, element) ? rt_s : rt_c, &element->VBox, dir[i]); /* score bounding box alignments */ if (!boxp) continue; factor = 1; if (element->Name[0].TextString && boxp->element->Name[0].TextString && 0 == NSTRCMP (element->Name[0].TextString, boxp->element->Name[0].TextString)) { delta4 += CostParameter.matching_neighbor_bonus; factor++; } if (element->Name[0].Direction == boxp->element->Name[0].Direction) delta4 += factor * CostParameter.oriented_neighbor_bonus; if (element->VBox.X1 == boxp->element->VBox.X1 || element->VBox.X1 == boxp->element->VBox.X2 || element->VBox.X2 == boxp->element->VBox.X1 || element->VBox.X2 == boxp->element->VBox.X2 || element->VBox.Y1 == boxp->element->VBox.Y1 || element->VBox.Y1 == boxp->element->VBox.Y2 || element->VBox.Y2 == boxp->element->VBox.Y1 || element->VBox.Y2 == boxp->element->VBox.Y2) delta4 += factor * CostParameter.aligned_neighbor_bonus; } END_LOOP; /* free k-d tree memory */ r_destroy_tree (&rt_s); r_destroy_tree (&rt_c); } /* penalize total area used by this layout */ { LocationType minX = MAX_COORD, minY = MAX_COORD; LocationType maxX = -MAX_COORD, maxY = -MAX_COORD; ELEMENT_LOOP (PCB->Data); { MAKEMIN (minX, element->VBox.X1); MAKEMIN (minY, element->VBox.Y1); MAKEMAX (maxX, element->VBox.X2); MAKEMAX (maxY, element->VBox.Y2); } END_LOOP; if (minX < maxX && minY < maxY) delta5 = CostParameter.overall_area_penalty * sqrt ((double) (maxX - minX) * (maxY - minY) * 0.0001); } if (T == 5) { T = W + delta1 + delta2 + delta3 - delta4 + delta5; printf ("cost components are %.3f %.3f %.3f %.3f %.3f %.3f\n", W / T, delta1 / T, delta2 / T, delta3 / T, -delta4 / T, delta5 / T); } /* done! */ return W + (delta1 + delta2 + delta3 - delta4 + delta5); }
/* --------------------------------------------------------------------------- * free memory used by data struct */ void FreeDataMemory (DataType *data) { LayerType *layer; int i; if (data == NULL) return; VIA_LOOP (data); { free (via->Name); } END_LOOP; g_list_free_full (data->Via, (GDestroyNotify)FreeVia); ELEMENT_LOOP (data); { FreeElementMemory (element); } END_LOOP; g_list_free_full (data->Element, (GDestroyNotify)FreeElement); g_list_free_full (data->Rat, (GDestroyNotify)FreeRat); for (layer = data->Layer, i = 0; i < MAX_LAYER + 2; layer++, i++) { FreeAttributeListMemory (&layer->Attributes); TEXT_LOOP (layer); { free (text->TextString); } END_LOOP; if (layer->Name) free (layer->Name); LINE_LOOP (layer); { if (line->Number) free (line->Number); } END_LOOP; g_list_free_full (layer->Line, (GDestroyNotify)FreeLine); g_list_free_full (layer->Arc, (GDestroyNotify)FreeArc); g_list_free_full (layer->Text, (GDestroyNotify)FreeText); POLYGON_LOOP (layer); { FreePolygonMemory (polygon); } END_LOOP; g_list_free_full (layer->Polygon, (GDestroyNotify)FreePolygon); if (layer->line_tree) r_destroy_tree (&layer->line_tree); if (layer->arc_tree) r_destroy_tree (&layer->arc_tree); if (layer->text_tree) r_destroy_tree (&layer->text_tree); if (layer->polygon_tree) r_destroy_tree (&layer->polygon_tree); } if (data->element_tree) r_destroy_tree (&data->element_tree); for (i = 0; i < MAX_ELEMENTNAMES; i++) if (data->name_tree[i]) r_destroy_tree (&data->name_tree[i]); if (data->via_tree) r_destroy_tree (&data->via_tree); if (data->pin_tree) r_destroy_tree (&data->pin_tree); if (data->pad_tree) r_destroy_tree (&data->pad_tree); if (data->rat_tree) r_destroy_tree (&data->rat_tree); /* clear struct */ memset (data, 0, sizeof (DataType)); }
/* --------------------------------------------------------------------------- * free memory used by data struct */ void FreeDataMemory (DataTypePtr Data) { LayerTypePtr layer; int i; if (Data) { VIA_LOOP (Data); { MYFREE (via->Name); } END_LOOP; ELEMENT_LOOP (Data); { FreeElementMemory (element); } END_LOOP; for (layer = Data->Layer, i = 0; i < MAX_LAYER + 2; layer++, i++) { FreeAttributeListMemory (&layer->Attributes); TEXT_LOOP (layer); { MYFREE (text->TextString); } END_LOOP; if (layer->Name) MYFREE (layer->Name); LINE_LOOP (layer); { if (line->Number) MYFREE (line->Number); } END_LOOP; MYFREE (layer->Line); MYFREE (layer->Arc); MYFREE (layer->Text); POLYGON_LOOP (layer); { FreePolygonMemory (polygon); } END_LOOP; MYFREE (layer->Polygon); if (layer->line_tree) r_destroy_tree (&layer->line_tree); if (layer->arc_tree) r_destroy_tree (&layer->arc_tree); if (layer->text_tree) r_destroy_tree (&layer->text_tree); if (layer->polygon_tree) r_destroy_tree (&layer->polygon_tree); } if (Data->element_tree) r_destroy_tree (&Data->element_tree); for (i = 0; i < MAX_ELEMENTNAMES; i++) if (Data->name_tree[i]) r_destroy_tree (&Data->name_tree[i]); if (Data->via_tree) r_destroy_tree (&Data->via_tree); if (Data->pin_tree) r_destroy_tree (&Data->pin_tree); if (Data->pad_tree) r_destroy_tree (&Data->pad_tree); if (Data->rat_tree) r_destroy_tree (&Data->rat_tree); /* clear struct */ memset (Data, 0, sizeof (DataType)); } else { fprintf (stderr, "Warning: Tried to FreeDataMemory(null)\n"); } }