diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
commit | ef962f6008f25ab7cbd4ca21bcc72b97a1e2d76f (patch) | |
tree | 8149bee93d1a3f91d4503bfb3853adac4af0a85e /hyp2mat/lib/exec_padstack.cc |
Imported Upstream version 0.0.34
Diffstat (limited to 'hyp2mat/lib/exec_padstack.cc')
-rw-r--r-- | hyp2mat/lib/exec_padstack.cc | 269 |
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 */ |