summaryrefslogtreecommitdiff
path: root/hyp2mat/lib/exec_padstack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'hyp2mat/lib/exec_padstack.cc')
-rw-r--r--hyp2mat/lib/exec_padstack.cc269
1 files changed, 269 insertions, 0 deletions
diff --git a/hyp2mat/lib/exec_padstack.cc b/hyp2mat/lib/exec_padstack.cc
new file mode 100644
index 0000000..0c2435e
--- /dev/null
+++ b/hyp2mat/lib/exec_padstack.cc
@@ -0,0 +1,269 @@
+/*
+ * hyp2mat - convert hyperlynx files to matlab scripts
+ * Copyright 2012 Koen De Vleeschauwer.
+ *
+ * This file is part of hyp2mat.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <iostream>
+#include "hypfile.h"
+
+using namespace std;
+using namespace HypFile;
+
+/*
+ * Hyperlynx 'PADSTACK' record.
+ * Defines a padstack.
+ */
+
+/*
+ * Hyperlynx padstack-element subrecord of 'PADSTACK' record.
+ * Defines an individual pad in a padstack.
+ */
+
+bool HypFile::Hyp::exec_padstack_element(parse_param& h)
+{
+ if (trace_hyp) {
+ cerr << "padstack_element:";
+ if (h.padstack_name_set) cerr << " padstack_name = " << h.padstack_name;
+ if (h.drill_size_set) cerr << " drill_size = " << h.drill_size;
+ cerr << " layer_name = " << h.layer_name;
+ cerr << " pad_shape = " << h.pad_shape;
+ cerr << " pad_sx = " << h.pad_sx;
+ cerr << " pad_sy = " << h.pad_sy;
+ cerr << " pad_angle = " << h.pad_angle;
+ if (h.pad_type_set & (h.pad_type == PAD_TYPE_THERMAL_RELIEF)) {
+ cerr << " thermal_clear_shape = " << h.thermal_clear_shape;
+ cerr << " thermal_clear_sx = " << h.thermal_clear_sx;
+ cerr << " thermal_clear_sy = " << h.thermal_clear_sy;
+ cerr << " thermal_clear_angle = " << h.thermal_clear_angle;
+ }
+ if (h.pad_type_set) cerr << " pad_type = " << h.pad_type;
+ cerr << endl;
+ }
+
+ h.drill_size *= unit;
+ h.pad_sx *= unit;
+ h.pad_sy *= unit;
+ h.thermal_clear_sx *= unit;
+ h.thermal_clear_sy *= unit;
+
+ /* new padstack */
+ if (h.padstack_name_set) {
+ Padstack pdstack;
+ pdstack.padstack_name = h.padstack_name;
+ if (h.drill_size_set)
+ pdstack.drill_size = h.drill_size;
+ else
+ pdstack.drill_size = 0;
+
+ /* add new padstack to list of padstacks */
+ padstack.push_back(pdstack);
+ }
+
+ /* new pad */
+ Pad p;
+
+ p.layer_name = h.layer_name;
+
+ /* pad type */
+ if (h.pad_type_set) p.pad_type = h.pad_type;
+ else if (p.layer_name == "ADEF") p.pad_type = PAD_TYPE_ANTIPAD;
+ else p.pad_type = PAD_TYPE_METAL;
+
+ if (h.pad_shape == 0)
+ p.pad_shape = PAD_SHAPE_OVAL;
+ else if (h.pad_shape == 1)
+ p.pad_shape = PAD_SHAPE_RECTANGULAR;
+ else if (h.pad_shape == 2)
+ p.pad_shape = PAD_SHAPE_OBLONG;
+ else if (h.pad_shape == -1)
+ p.pad_shape = PAD_SHAPE_OVAL; /* workaround for Altium bug */
+ else {
+ error("unknown pad shape");
+ return true;
+ }
+
+ p.pad_sx = h.pad_sx;
+ p.pad_sy = h.pad_sy;
+ p.pad_angle = h.pad_angle;
+
+ if (p.pad_type == PAD_TYPE_THERMAL_RELIEF) {
+ if (h.thermal_clear_shape == 0)
+ p.thermal_clear_shape = PAD_SHAPE_OVAL;
+ else if (h.thermal_clear_shape == 1)
+ p.thermal_clear_shape = PAD_SHAPE_RECTANGULAR;
+ else if (h.thermal_clear_shape == 2)
+ p.thermal_clear_shape = PAD_SHAPE_OBLONG;
+ else {
+ error("unknown thermal clear shape");
+ return true;
+ }
+
+ p.thermal_clear_sx = h.thermal_clear_sx;
+ p.thermal_clear_sy = h.thermal_clear_sy;
+ p.thermal_clear_angle = h.thermal_clear_angle;
+ }
+ else {
+ p.thermal_clear_shape = PAD_SHAPE_OVAL;
+ p.thermal_clear_sx = 0;
+ p.thermal_clear_sy = 0;
+ p.thermal_clear_angle = 0;
+ }
+
+ /* add new pad to list of pads of current padstack */
+ padstack.back().pads.push_back(p);
+
+ return false;
+}
+
+/*
+ * Note:
+ * MDEF and ADEF layer names have special meaning.
+ * MDEF specified the default pad for signal or plane layers.
+ * If a signal or plane layer has no metal pad, and an MDEF default pad is specified, the MDEF pad is applied to the layer.
+ * ADEF specifies the default anti-pad (non-conducting hole in the copper) for plane layers.
+ * If a plane layer has no anti-pad, and an ADEF default pad is specified, the ADEF pad is applied to the layer.
+ */
+
+bool HypFile::Hyp::exec_padstack_end(parse_param& h)
+{
+ if (trace_hyp) {
+ cerr << "padstack_end:";
+ cerr << endl;
+ };
+
+ PadList new_pads;
+
+ /*
+ * Loop through stackup.
+ * Calculate new padstack, where all MDEF and ADEF pads have been expanded into one or more metal layers.
+ */
+
+ for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) {
+ /* Loop through pad list */
+ bool layer_has_pad = false;
+ bool layer_has_antipad = false;
+ for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) {
+ if (l->layer_name == p->layer_name) {
+ new_pads.push_back(*p);
+ layer_has_pad = layer_has_pad || (p->pad_type == PAD_TYPE_METAL);
+ layer_has_antipad = layer_has_antipad || (p->pad_type == PAD_TYPE_ANTIPAD);
+ }
+ }
+
+ /* If a plane layer has no antipad, add ADEF pad if specified */
+ if (!layer_has_antipad && (l->layer_type == LAYER_PLANE))
+ for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p)
+ if (p->layer_name == "ADEF") {
+ Pad new_pad = *p;
+ new_pad.layer_name = l->layer_name; /* change ADEF into current layer name */
+ new_pads.push_back(new_pad);
+ }
+
+ /* If a signal or plane layer has no pad, add MDEF pad if specified */
+ if (!layer_has_pad && ((l->layer_type == LAYER_SIGNAL) || (l->layer_type == LAYER_PLANE)) )
+ for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p)
+ if (p->layer_name == "MDEF") {
+ Pad new_pad = *p;
+ new_pad.layer_name = l->layer_name; /* change MDEF into current layer name */
+ new_pads.push_back(new_pad);
+ layer_has_pad = true;
+ }
+
+ /*
+ * Determine begin and end layers of via
+ */
+
+ /* via is from top to bottom if at least one pad is metal MDEF */
+ bool is_through_hole_via = false;
+ for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p)
+ if ((p->layer_name == "MDEF") && (p->pad_type == PAD_TYPE_METAL)) is_through_hole_via = true;
+
+ /* determine via top and bottom layers */
+ std::string pad_top_layer;
+ std::string pad_bottom_layer;
+
+ if (is_through_hole_via) {
+ pad_top_layer = stackup.front().layer_name; /* via begins at top layer */
+ pad_bottom_layer = stackup.back().layer_name; /* via ends at bottom layer */
+ }
+ else {
+ /* via begins at highest layer with metal pad, and ends at lowest layer with a metal pad */
+ bool layer_found = false;
+ for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l)
+ for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p)
+ if ((l->layer_name == p->layer_name) && (p->pad_type == PAD_TYPE_METAL)) {
+ if (!layer_found) {
+ pad_top_layer = l->layer_name;
+ layer_found = true;
+ }
+ pad_bottom_layer = l->layer_name;
+ };
+
+ if (!layer_found) std::cerr << "warning: padstack without metal:" << h.padstack_name << std::endl;
+
+ }
+
+ /*
+ * Fill in missing via pads
+ */
+
+ // XXX Fixme
+ // XXX Check if loops need to begin at pad_top_layer / end at pad_bottom_layer
+ // XXX Check if pad_top_layer / pad_bottom_layer need visibility
+ // XXX Check if need mechanism to remove pads?
+
+ /* If a signal or plane layer has no pad, and no MDEF pad, copy an existing pad */
+ bool is_through_hole_pad = is_through_hole_via && (padstack.back().drill_size > 0);
+ if (!layer_has_pad && is_through_hole_pad && ((l->layer_type == LAYER_SIGNAL) || (l->layer_type == LAYER_PLANE)) ) {
+ Pad new_pad;
+ bool pad_found = false;
+ for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) {
+ if (p->pad_type != PAD_TYPE_METAL) continue;
+ if (!pad_found) {
+ /* if all padstack pads are equal, create a pad on this layer which is like the others */
+ new_pad = *p;
+ new_pad.layer_name = l->layer_name;
+ pad_found = true;
+ }
+ else if ((p->pad_shape != new_pad.pad_shape) || (p->pad_sx != new_pad.pad_sx) || (p->pad_sy != new_pad.pad_sy) || (p->pad_angle != new_pad.pad_angle)) {
+ /* if padstack pads are different, create a circular pad with a diameter equal to the smallest pad dimension */
+ double radius = new_pad.pad_sx;
+ if (radius > new_pad.pad_sy) radius = new_pad.pad_sy;
+ if (radius > p->pad_sx) radius = p->pad_sx;
+ if (radius > p->pad_sy) radius = p->pad_sy;
+ new_pad.pad_shape = PAD_SHAPE_OVAL;
+ new_pad.pad_sx = radius;
+ new_pad.pad_sy = radius;
+ new_pad.pad_angle = 0;
+ }
+ }
+ /* add newly created pad to padstack */
+ if (pad_found) new_pads.push_back(new_pad);
+ }
+
+ }
+
+ /* put new padstack in place. */
+
+ padstack.back().pads = new_pads;
+
+ return false;
+
+}
+
+/* not truncated */