diff options
Diffstat (limited to 'hyp2mat/lib/exec_net.cc')
-rw-r--r-- | hyp2mat/lib/exec_net.cc | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/hyp2mat/lib/exec_net.cc b/hyp2mat/lib/exec_net.cc new file mode 100644 index 0000000..50000b3 --- /dev/null +++ b/hyp2mat/lib/exec_net.cc @@ -0,0 +1,502 @@ + +/* + * 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 <cmath> +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'NET' record. + * Specifies a net. + */ + +bool HypFile::Hyp::exec_net(parse_param& h) +{ + if (trace_hyp) cerr << "net: net_name = " << h.net_name << endl; + + Net n; + n.net_name = h.net_name; + n.plane_separation = -1.0; + net.push_back(n); + + return false; +} + +/* + * Hyperlynx 'PS' subrecord of 'NET' record. + * Specifies plane separation of a net. + */ + +bool HypFile::Hyp::exec_net_plane_separation(parse_param& h) +{ + if (trace_hyp) cerr << "net_plane_separation: plane_separation = " << h.plane_separation << endl; + h.plane_separation *= unit; + + net.back().plane_separation = h.plane_separation; + + return false; +} + +/* + * Hyperlynx 'SEG' subrecord of 'NET' record. + * Draws straight metal trace segment. + */ + +bool HypFile::Hyp::exec_seg(parse_param& h) +{ + if (trace_hyp) { + cerr << "seg: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2; + cerr << " width = " << h.width << " layer_name = " << h.layer_name; + if (h.plane_separation_set) cerr << " plane_separation = " << h.plane_separation; + if (h.left_plane_separation_set) cerr << " left_plane_separation = " << h.left_plane_separation; + cerr << endl; + } + + Polygon p; + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.width *= unit; + h.plane_separation *= unit; + if (!h.plane_separation_set) h.plane_separation = -1.0; + h.left_plane_separation *= unit; + if (!h.left_plane_separation_set) h.left_plane_separation = -1.0; + + p = segment2poly(h.x1 , h.y1, h.x2, h.y2, h.width); + p.layer_name = h.layer_name; + p.width = 0; + p.positive = true; + p.plane_separation = h.plane_separation; /* distance to other copper; -1 if not set */ + p.left_plane_separation = h.left_plane_separation; + + add_polygon(p); + + return false; +} + +/* + * Hyperlynx 'ARC' subrecord of 'NET' record. + * Draws arc metal trace segment. + */ + +bool HypFile::Hyp::exec_arc(parse_param& h) +{ + if (trace_hyp) { + cerr << "arc: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2; + cerr << " xc = " << h.xc << " yc = " << h.yc << " r = " << h.r; + cerr << " width = " << h.width << " layer_name = " << h.layer_name; + if (h.plane_separation_set) cerr << " plane_separation = " << h.plane_separation; + if (h.left_plane_separation_set) cerr << " left_plane_separation = " << h.left_plane_separation; + cerr << endl; + } + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.xc *= unit; + h.yc *= unit; + h.r *= unit; + h.width *= unit; + h.plane_separation *= unit; + if (!h.plane_separation_set) h.plane_separation = -1.0; + h.left_plane_separation *= unit; + if (!h.left_plane_separation_set) h.left_plane_separation = -1.0; + + /* 'ARC' draws arc clockwise */ + Polygon arc = arc2poly(h.x1, h.y1, h.x2, h.y2, h.xc, h.yc, h.r, true); + + /* draw arc segments */ + for (PointList::iterator i = arc.vertex.begin(); (i != arc.vertex.end()) && (i != --arc.vertex.end()); ++i) { + Polygon line_segment; + PointList::iterator j = i + 1; + line_segment = segment2poly(i->x, i->y, j->x, j->y, h.width); + line_segment.positive = true; + line_segment.layer_name = h.layer_name; + line_segment.width = 0; + line_segment.plane_separation = h.plane_separation; + line_segment.left_plane_separation = h.left_plane_separation; + add_polygon(line_segment); + } + + return false; +} + +/* + * Hyperlynx 'VIA' subrecord of 'NET' record. + * Draws via as defined in padstack. + */ + +bool HypFile::Hyp::exec_via(parse_param& h) +{ + if (trace_hyp) { + cerr << "via: x = " << h.x << " y = " << h.y; + if (h.layer1_name_set) cerr << " layer1_name = " << h.layer1_name; + if (h.layer2_name_set) cerr << " layer2_name = " << h.layer2_name; + cerr << " padstack_name = " << h.padstack_name; + cerr << endl; + } + + h.x *= unit; + h.y *= unit; + + /* lookup padstack */ + for (PadstackList::iterator i = padstack.begin(); i != padstack.end(); ++i) + if (i->padstack_name == h.padstack_name) { + + /* set via begin layer */ + if (!h.layer1_name_set) + h.layer1_name = i->pads.front().layer_name; + + /* set via end layer */ + if (!h.layer2_name_set) + h.layer2_name = i->pads.back().layer_name; + + /* add to list of via holes */ + add_via(h.x, h.y, h.layer2_name, h.layer1_name, i->drill_size/2); + + /* loop over padstack and generate pads */ + for (PadList::iterator j = i->pads.begin(); j != i->pads.end(); ++j) + add_pad(h.x, h.y, *j); + + return false; + } + + /* padstack not found */ + + return false; +} + +/* + * Hyperlynx 'VIA' subrecord of 'NET' record. + * Draws deprecated v1.x via. + */ + +bool HypFile::Hyp::exec_via_v1(parse_param& h) +{ + if (trace_hyp) { + cerr << "via: x = " << h.x << " y = " << h.y; + cerr << " drill_size = " << h.drill_size; + if (h.layer1_name_set) cerr << " layer1_name = " << h.layer1_name; + if (h.layer2_name_set) cerr << " layer2_name = " << h.layer2_name; + cerr << " pad1_shape = " << h.pad1_shape << " pad1_sx = " << h.pad1_sx << " pad1_sy = " << h.pad1_sy << " pad1_angle = " << h.pad1_angle; + cerr << " pad2_shape = " << h.pad2_shape << " pad2_sx = " << h.pad2_sx << " pad2_sy = " << h.pad2_sy << " pad2_angle = " << h.pad2_angle; + cerr << endl; + } + + h.drill_size *= unit; + h.x *= unit; + h.y *= unit; + h.pad1_sx *= unit; + h.pad1_sy *= unit; + h.pad2_sx *= unit; + h.pad2_sy *= unit; + + /* add to list of via holes */ + add_via(h.x, h.y, stackup.back().layer_name /* bottom */, stackup.front().layer_name /* top */ , h.drill_size/2); + + /* add top pad */ + Pad pad; + pad.layer_name = stackup.front().layer_name; /* Top layer */ + if (h.pad1_shape == "OVAL") pad.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad1_shape == "RECT") pad.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad1_shape == "OBLONG") pad.pad_shape = PAD_SHAPE_OBLONG; + else pad.pad_shape = PAD_SHAPE_OVAL; + pad.pad_type = PAD_TYPE_METAL; + pad.pad_sx = h.pad1_sx; + pad.pad_sy = h.pad1_sy; + pad.pad_angle = h.pad1_angle; + pad.thermal_clear_shape = PAD_SHAPE_OVAL; + pad.thermal_clear_sx = 0; + pad.thermal_clear_sy= 0; + pad.thermal_clear_angle= 0; + add_pad(h.x, h.y, pad); + + /* add bottom pad */ + pad.layer_name = stackup.back().layer_name; /* Top layer */ + if (h.pad2_shape == "OVAL") pad.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad2_shape == "RECT") pad.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad2_shape == "OBLONG") pad.pad_shape = PAD_SHAPE_OBLONG; + else pad.pad_shape = PAD_SHAPE_OVAL; + pad.pad_type = PAD_TYPE_METAL; + pad.pad_sx = h.pad2_sx; + pad.pad_sy = h.pad2_sy; + pad.pad_angle = h.pad2_angle; + add_pad(h.x, h.y, pad); + + return false; +} + +/* + * Hyperlynx 'PIN' subrecord of 'NET' record. + * Draws PIN as defined in padstack. + */ + +bool HypFile::Hyp::exec_pin(parse_param& h) +{ + if (trace_hyp) { + cerr << "pin: x = " << h.x << " y = " << h.y; + cerr << " pin_reference = " << h.pin_reference; + cerr << " padstack_name = " << h.padstack_name; + if (h.pin_function_set) cerr << " pin_function = " << h.pin_function; + cerr << endl; + } + + h.x *= unit; + h.y *= unit; + + /* add to list of pins */ + Pin p; + p.x = h.x; + p.y = h.y; + p.pin_reference = h.pin_reference; + p.padstack_name = h.padstack_name; + p.pin_function = PIN_SIM_BOTH; + if (h.pin_function_set) p.pin_function = h.pin_function; + net.back().pin.push_back(p); + + /* lookup padstack */ + if (h.padstack_name_set) + for (PadstackList::iterator i = padstack.begin(); i != padstack.end(); ++i) + if (i->padstack_name == h.padstack_name) { + /* add to list of via holes */ + add_via(h.x, h.y, stackup.back().layer_name /* bottom */, stackup.front().layer_name /* top */, i->drill_size/2); + + /* loop over padstack and generate pads */ + for (PadList::iterator j = i->pads.begin(); j != i->pads.end(); ++j) + add_pad(h.x, h.y, *j); + return false; + } + + /* padstack not found or not set */ + + return false; +} + +/* + * Hyperlynx 'PAD' subrecord of 'NET' record. + * Draws deprecated v1.x pad. + */ + +bool HypFile::Hyp::exec_pad(parse_param& h) +{ + if (trace_hyp) { + cerr << "pad: x = " << h.x << " y = " << h.y; + if (h.layer_name_set) cerr << " layer_name = " << h.layer_name; + cerr << " pad1_shape = " << h.pad1_shape << " pad1_sx = " << h.pad1_sx << " pad1_sy = " << h.pad1_sy << " pad1_angle = " << h.pad1_angle; + cerr << endl; + } + + h.x *= unit; + h.y *= unit; + h.pad1_sx *= unit; + h.pad1_sy *= unit; + + /* add pad */ + Pad pad; + pad.layer_name = h.layer_name; + if (h.pad1_shape == "OVAL") pad.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad1_shape == "RECT") pad.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad1_shape == "OBLONG") pad.pad_shape = PAD_SHAPE_OBLONG; + else pad.pad_shape = PAD_SHAPE_OVAL; + pad.pad_type = PAD_TYPE_METAL; + pad.pad_sx = h.pad1_sx; + pad.pad_sy = h.pad1_sy; + pad.pad_angle = h.pad1_angle; + pad.thermal_clear_shape = PAD_SHAPE_OVAL; + pad.thermal_clear_sx = 0; + pad.thermal_clear_sy= 0; + pad.thermal_clear_angle= 0; + add_pad(h.x, h.y, pad); + + return false; +} + +/* + * Hyperlynx 'USEG' subrecord of 'NET' record. + * Designates unrouted metal trace segment + */ + +bool HypFile::Hyp::exec_useg(parse_param& h) +{ + if (trace_hyp) { + cerr << "useg: x1 = " << h.x1 << " y1 = " << h.y1 << " layer1_name = " << h.layer1_name; + cerr << " x2 = " << h.x2 << " y2 = " << h.y2 << " layer2_name = " << h.layer2_name; + if (h.zlayer_name_set) cerr << " zlayer_name = " << h.zlayer_name << " width = " << h.width << " length = " << h.length; + if (h.impedance_set) cerr << " impedance = " << h.impedance << " delay = " << h.delay; + if (h.resistance_set) cerr << " resistance = " << h.resistance; + cerr << endl; + } + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.width *= unit; + h.length *= unit; + if (!h.resistance_set) h.resistance = 0; + + UnroutedSegment u; + u.x1 = h.x1; + u.y1 = h.y1; + u.layer1_name = h.layer1_name; + u.x2 = h.x2; + u.y2 = h.y2; + u.layer2_name = h.layer2_name; + u.zlayer_name = h.zlayer_name; + u.zlayer_name_set = h.zlayer_name_set; + u.width = h.width; + u.impedance = h.impedance; + u.impedance_set = h.impedance_set; + u.delay = h.delay; + u.resistance = h.resistance; + net.back().unrouted_segment.push_back(u); + + return false; +} + +/* + * Hyperlynx 'A' attribute subrecord of 'NET' record. + * Defines net attributes as name/value pairs. + */ + +bool HypFile::Hyp::exec_net_attribute(parse_param& h) +{ + if (trace_hyp) cerr << "net_attribute: name = " << h.name << " value = " << h.value << endl; + + Attribute a; + a.name = h.name; + a.value = h.value; + + net.back().attribute.push_back(a); + + return false; +} + +/* + * Add a polygon to the current net + */ + +void HypFile::Hyp::add_polygon(Polygon poly) +{ + if (poly.vertex.empty()) return; + add_polygon_to_net(net.back(), poly); +} + +/* + * Add polygon poly to net pnet + */ + +void HypFile::Hyp::add_polygon_to_net(Net& pnet, Polygon poly) { + + /* set net name of polygon to net */ + poly.net_name = pnet.net_name; + + /* The polygon id is a positive number if the polygon has been assigned a polygon id. + * If the polygon has not been assigned a polygon id, the id is -1. + * An polygon which has not been assigned a polygon id has a single, outer edge, no holes. + * (the polygon does not have an id a POLYVOID could refer to). + */ + + if (poly.id < 0) { + /* + * If a polygon has id -1, assign the polygon an arbitrary negative id, different from -1. + * Make sure all polygons of the same net do not clash/have different ids. + */ + int new_id = 0; + if (!pnet.metal.empty()) + new_id = pnet.metal.begin()->first - 1; /* new id is one less than the smallest existing id */ + if (new_id >= -1) new_id = -2; /* does not clash with an assigned id (positive) or the default (-1) */ + poly.id = new_id; + } + + /* check if polygons with this id already exist */ + PolygonMap::iterator i = pnet.metal.find(poly.id); + if (i == pnet.metal.end()) { + PolygonList empty_list; + pnet.metal[poly.id] = empty_list; + } + + /* add polygon to net */ + pnet.metal[poly.id].push_back(poly); + + return; +} + +/* + * Add a pad at coordinates (x, y) + */ + +void HypFile::Hyp::add_pad(double pad_x, double pad_y, Pad pad) +{ + /* convert to polygon */ + Polygon pad_poly = pad2poly(pad_x, pad_y, pad); + + /* add pad to copper */ + add_polygon(pad_poly); + + return; +} + +/* + * Add via to list of via holes + */ + +void HypFile::Hyp::add_via(double x, double y, std::string layer0_name, std::string layer1_name, double radius) +{ + if (radius != 0.0) { + + /* lookup drill vertical begin and end */ + double z0 = stackup.back().z0; /* defaults to bottom */ + double z1 = stackup.front().z1; /* defaults to top */ + + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) + if (layer0_name == l->layer_name) { + z0 = l->z0; + z1 = l->z1; + } + + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) + if (layer1_name == l->layer_name) { + if (l->z1 > z1) z1 = l->z1; + if (l->z0 < z0) z0 = l->z0; + } + + Via v; + v.x = x; + v.y = y; + v.layer0_name = layer0_name; + v.layer1_name = layer1_name; + v.z0 = z0; + v.z1 = z1; + v.radius = radius; + net.back().via.push_back(v); + } + + return; +} + +/* not truncated */ |