/////////////////////////////////////////////////////////////////////////////// // BSD 3-Clause License // // Copyright (c) 2019, Nefelus Inc // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #include #include "db.h" #include "dbBlock.h" #include "dbNet.h" #include "dbTable.h" #include "dbTech.h" #include "dbTechLayerRule.h" #include "dbWire.h" #include "dbWireCodec.h" #include "dbWireOpcode.h" #include "logger.h" namespace odb { ////////////////////////////////////////////////////////////////////////////////// // // dbWireEncoder // ////////////////////////////////////////////////////////////////////////////////// #define DB_WIRE_ENCODER_INVALID_VIA_LAYER 0 inline unsigned char dbWireEncoder::getOp(int idx) { return _opcodes[idx]; } inline void dbWireEncoder::updateOp(int idx, unsigned char op) { _opcodes[idx] = op; } inline void dbWireEncoder::addOp(unsigned char op, int value) { _data.push_back(value); _opcodes.push_back(op); ++_idx; } inline unsigned char dbWireEncoder::getWireType(dbWireType type) { unsigned char wire_type = 0; switch (type.getValue()) { case dbWireType::NONE: wire_type = WOP_NONE; break; case dbWireType::COVER: wire_type = WOP_COVER; break; case dbWireType::FIXED: wire_type = WOP_FIXED; break; case dbWireType::ROUTED: wire_type = WOP_ROUTED; break; case dbWireType::NOSHIELD: wire_type = WOP_NOSHIELD; break; default: _wire_type = WOP_NONE; break; } return wire_type; } inline void dbWireEncoder::initPath(dbTechLayer* layer, dbWireType type) { initPath(layer, getWireType(type)); } inline void dbWireEncoder::initPath(dbTechLayer* layer, dbWireType type, dbTechLayerRule* rule) { initPath(layer, getWireType(type), rule); } void dbWireEncoder::initPath(dbTechLayer* layer, unsigned char wire_type) { _wire_type = wire_type; _point_cnt = 0; _via_cnt = 0; _layer = layer; _non_default_rule = 0; _rule_opcode = 0; _prev_extended_colinear_pnt = false; } void dbWireEncoder::initPath(dbTechLayer* layer, unsigned char wire_type, dbTechLayerRule* rule) { _wire_type = wire_type; _point_cnt = 0; _via_cnt = 0; _layer = layer; _non_default_rule = rule->getImpl()->getOID(); if (rule->isBlockRule()) _rule_opcode = WOP_RULE | WOP_BLOCK_RULE; else _rule_opcode = WOP_RULE; _prev_extended_colinear_pnt = false; _x = 0; _y = 0; } dbWireEncoder::dbWireEncoder() { _wire = NULL; } dbWireEncoder::~dbWireEncoder() { } void dbWireEncoder::begin(dbWire* wire) { clear(); _wire = (_dbWire*) wire; _block = wire->getBlock(); _tech = _block->getDb()->getTech(); } void dbWireEncoder::clear() { _wire = NULL; _block = NULL; _tech = NULL; _data.clear(); _opcodes.clear(); _layer = NULL; _idx = 0; _x = 0; _y = 0; _non_default_rule = 0; _rule_opcode = 0; _point_cnt = 0; _via_cnt = 0; _prev_extended_colinear_pnt = false; } void dbWireEncoder::append(dbWire* wire) { _wire = (_dbWire*) wire; _block = wire->getBlock(); _tech = _block->getDb()->getTech(); _data = _wire->_data; _opcodes = _wire->_opcodes; _layer = NULL; _idx = _data.size(); _x = 0; _y = 0; _non_default_rule = 0; _rule_opcode = 0; _point_cnt = 0; _via_cnt = 0; _prev_extended_colinear_pnt = false; } #define DB_WIRE_ENCODER_NON_ORTHOGANAL_SEGMENT 0 int dbWireEncoder::addPoint(int x, int y, uint property) { int jct_id = _idx; if (_non_default_rule == 0) { if (_point_cnt == 0) { addOp(WOP_X | WOP_DEFAULT_WIDTH, x); addOp(WOP_Y | WOP_DEFAULT_WIDTH, y); _x = x; _y = y; jct_id++; _point_cnt++; } else if ((_x == x) && (_y == y)) { addOp(WOP_COLINEAR | WOP_DEFAULT_WIDTH, 0); } else if (_y == y) { addOp(WOP_X | WOP_DEFAULT_WIDTH, x); _x = x; _point_cnt++; } else if (_x == x) { addOp(WOP_Y | WOP_DEFAULT_WIDTH, y); _y = y; _point_cnt++; } else { ZASSERT(DB_WIRE_ENCODER_NON_ORTHOGANAL_SEGMENT); } } else { if (_point_cnt == 0) { addOp(WOP_X, x); addOp(WOP_Y, y); _x = x; _y = y; _point_cnt++; jct_id++; } else if ((_x == x) && (_y == y)) { addOp(WOP_COLINEAR, 0); } else if (_y == y) { addOp(WOP_X, x); _x = x; _point_cnt++; } else if (_x == x) { addOp(WOP_Y, y); _y = y; _point_cnt++; } else { ZASSERT(DB_WIRE_ENCODER_NON_ORTHOGANAL_SEGMENT); } if (_point_cnt && ((_point_cnt & (WOP_NON_DEFAULT_WIDTH_POINT_CNT - 1)) == 0)) addOp(_rule_opcode, _non_default_rule); } if (_point_cnt != 1) addOp(WOP_PROPERTY, property); _prev_extended_colinear_pnt = false; return jct_id; } #define DB_WIRE_ENCODER_COLINEAR_EXT_RULE_1() \ ((_point_cnt > 1) || ((_point_cnt > 0) && (_via_cnt > 0))) #define DB_WIRE_ENCODER_COLINEAR_EXT_RULE_2() \ (_prev_extended_colinear_pnt == false) int dbWireEncoder::addPoint(int x, int y, int ext, uint property) { int jct_id = _idx; if (_non_default_rule == 0) { if (_point_cnt == 0) { addOp(WOP_X | WOP_DEFAULT_WIDTH, x); addOp(WOP_Y | WOP_EXTENSION | WOP_DEFAULT_WIDTH, y); addOp(WOP_OPERAND, ext); _x = x; _y = y; _point_cnt++; jct_id++; _prev_extended_colinear_pnt = false; } else if ((_x == x) && (_y == y)) { ZASSERT(DB_WIRE_ENCODER_COLINEAR_EXT_RULE_1()); ZASSERT(DB_WIRE_ENCODER_COLINEAR_EXT_RULE_2()); addOp(WOP_COLINEAR | WOP_EXTENSION | WOP_DEFAULT_WIDTH, ext); _prev_extended_colinear_pnt = true; } else if (_y == y) { addOp(WOP_X | WOP_EXTENSION | WOP_DEFAULT_WIDTH, x); addOp(WOP_OPERAND, ext); _x = x; _point_cnt++; _prev_extended_colinear_pnt = false; } else if (_x == x) { addOp(WOP_Y | WOP_EXTENSION | WOP_DEFAULT_WIDTH, y); addOp(WOP_OPERAND, ext); _y = y; _point_cnt++; _prev_extended_colinear_pnt = false; } else { ZASSERT(DB_WIRE_ENCODER_NON_ORTHOGANAL_SEGMENT); } } else { if (_point_cnt == 0) { addOp(WOP_X, x); addOp(WOP_Y | WOP_EXTENSION, y); addOp(WOP_OPERAND, ext); _x = x; _y = y; _point_cnt++; jct_id++; _prev_extended_colinear_pnt = false; } else if ((_x == x) && (_y == y)) { ZASSERT(DB_WIRE_ENCODER_COLINEAR_EXT_RULE_1()); ZASSERT(DB_WIRE_ENCODER_COLINEAR_EXT_RULE_2()); addOp(WOP_COLINEAR | WOP_EXTENSION, ext); _prev_extended_colinear_pnt = true; } else if (_y == y) { addOp(WOP_X | WOP_EXTENSION, x); addOp(WOP_OPERAND, ext); _x = x; _point_cnt++; _prev_extended_colinear_pnt = false; } else if (_x == x) { addOp(WOP_Y | WOP_EXTENSION, y); addOp(WOP_OPERAND, ext); _y = y; _point_cnt++; _prev_extended_colinear_pnt = false; } else { ZASSERT(DB_WIRE_ENCODER_NON_ORTHOGANAL_SEGMENT); } if (_point_cnt && ((_point_cnt & (WOP_NON_DEFAULT_WIDTH_POINT_CNT - 1)) == 0)) addOp(_rule_opcode, _non_default_rule); } if (_point_cnt != 1) addOp(WOP_PROPERTY, property); return jct_id; } int dbWireEncoder::addVia(dbVia* via) { int jct_id = _idx; ZASSERT(_point_cnt != 0); dbTechLayer* top = via->getTopLayer(); dbTechLayer* bot = via->getBottomLayer(); if (top == _layer) { _layer = bot; addOp(WOP_VIA, via->getImpl()->getOID()); } else if (bot == _layer) { _layer = top; addOp(WOP_VIA | WOP_VIA_EXIT_TOP, via->getImpl()->getOID()); } else { ZASSERT(DB_WIRE_ENCODER_INVALID_VIA_LAYER); addOp(WOP_VIA, 0); } _via_cnt++; return jct_id; } int dbWireEncoder::addTechVia(dbTechVia* via) { int jct_id = _idx; ZASSERT(_point_cnt != 0); dbTechLayer* top = via->getTopLayer(); dbTechLayer* bot = via->getBottomLayer(); if (top == _layer) { _layer = bot; addOp(WOP_TECH_VIA, via->getImpl()->getOID()); } else if (bot == _layer) { _layer = top; addOp(WOP_TECH_VIA | WOP_VIA_EXIT_TOP, via->getImpl()->getOID()); } else { ZASSERT(DB_WIRE_ENCODER_INVALID_VIA_LAYER); addOp(WOP_TECH_VIA, 0); } _via_cnt++; return jct_id; } void dbWireEncoder::addRect(int deltaX1, int deltaY1, int deltaX2, int deltaY2) { // order must match dbWireDecoder::next ZASSERT(_point_cnt != 0); addOp(WOP_RECT, deltaX1); addOp(WOP_OPERAND, deltaY1); addOp(WOP_OPERAND, deltaX2); addOp(WOP_OPERAND, deltaY2); } void dbWireEncoder::addITerm(dbITerm* iterm) { ZASSERT(_point_cnt != 0); addOp(WOP_ITERM, iterm->getImpl()->getOID()); } void dbWireEncoder::addBTerm(dbBTerm* bterm) { ZASSERT(_point_cnt != 0); addOp(WOP_BTERM, bterm->getImpl()->getOID()); } void dbWireEncoder::newPath(dbTechLayer* layer, dbWireType type) { initPath(layer, type); addOp(WOP_PATH | _wire_type, layer->getImpl()->getOID()); } void dbWireEncoder::newPath(dbTechLayer* layer, dbWireType type, dbTechLayerRule* rule) { initPath(layer, type, rule); addOp(WOP_PATH | _wire_type, layer->getImpl()->getOID()); addOp(_rule_opcode, _non_default_rule); } void dbWireEncoder::newPath(int jct_id) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, _wire_type); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(WOP_COLINEAR | WOP_DEFAULT_WIDTH, 0); } void dbWireEncoder::newPath(int jct_id, dbWireType type) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, type); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(WOP_COLINEAR | WOP_DEFAULT_WIDTH, 0); } void dbWireEncoder::newPathShort(int jct_id, dbTechLayer* layer, dbWireType type) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); initPath(layer, type); addOp(WOP_SHORT | _wire_type, layer->getImpl()->getOID()); addOp(WOP_OPERAND, jct_id); } void dbWireEncoder::newPathVirtualWire(int jct_id, dbTechLayer* layer, dbWireType type) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); initPath(layer, type); addOp(WOP_VWIRE | _wire_type, layer->getImpl()->getOID()); addOp(WOP_OPERAND, jct_id); } void dbWireEncoder::newPathExt(int jct_id, int ext) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, _wire_type); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(WOP_COLINEAR | WOP_EXTENSION | WOP_DEFAULT_WIDTH, ext); } void dbWireEncoder::newPathExt(int jct_id, int ext, dbWireType type) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, type); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(WOP_COLINEAR | WOP_EXTENSION | WOP_DEFAULT_WIDTH, ext); } void dbWireEncoder::newPath(int jct_id, dbTechLayerRule* rule) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, _wire_type, rule); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(_rule_opcode, _non_default_rule); addOp(WOP_COLINEAR, 0); } void dbWireEncoder::newPath(int jct_id, dbWireType type, dbTechLayerRule* rule) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, type, rule); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(_rule_opcode, _non_default_rule); addOp(WOP_COLINEAR, 0); } void dbWireEncoder::newPathShort(int jct_id, dbTechLayer* layer, dbWireType type, dbTechLayerRule* rule) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); initPath(layer, type, rule); addOp(WOP_SHORT | _wire_type, layer->getImpl()->getOID()); addOp(WOP_OPERAND, jct_id); addOp(_rule_opcode, _non_default_rule); } void dbWireEncoder::newPathVirtualWire(int jct_id, dbTechLayer* layer, dbWireType type, dbTechLayerRule* rule) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); initPath(layer, type, rule); addOp(WOP_VWIRE | _wire_type, layer->getImpl()->getOID()); addOp(WOP_OPERAND, jct_id); addOp(_rule_opcode, _non_default_rule); } void dbWireEncoder::newPathExt(int jct_id, int ext, dbTechLayerRule* rule) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, _wire_type, rule); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(_rule_opcode, _non_default_rule); addOp(WOP_COLINEAR | WOP_EXTENSION, ext); } void dbWireEncoder::newPathExt(int jct_id, int ext, dbWireType type, dbTechLayerRule* rule) { ZASSERT((jct_id >= 0) && (jct_id < _idx)); WirePoint pnt; getPrevPoint(_tech, _block, _opcodes, _data, jct_id, true, pnt); initPath(pnt._layer, type, rule); _x = pnt._x; _y = pnt._y; _point_cnt = 1; addOp(WOP_JUNCTION | _wire_type, jct_id); addOp(_rule_opcode, _non_default_rule); addOp(WOP_COLINEAR | WOP_EXTENSION, ext); } void dbWireEncoder::end() { if (_opcodes.size() == 0) return; uint n = _opcodes.size(); // Free the old memory _wire->_data.~dbVector(); new (&_wire->_data) dbVector(); _wire->_data.reserve(n); _wire->_data = _data; // Free the old memory _wire->_opcodes.~dbVector(); new (&_wire->_opcodes) dbVector(); _wire->_opcodes.reserve(n); _wire->_opcodes = _opcodes; // Should we calculate the bbox??? ((_dbBlock*) _block)->_flags._valid_bbox = 0; _point_cnt = 0; } ////////////////////////////////////////////////////////////////////////////////// // // dbWireDecoder // ////////////////////////////////////////////////////////////////////////////////// #define DB_WIRE_DECODE_INVALID_OPCODE 0 #define DB_WIRE_DECODE_INVALID_OPCODE_SEQUENCE 0 #define DB_WIRE_DECODE_INVALID_VIA_LAYER 0 dbWireDecoder::dbWireDecoder() { _wire = NULL; _block = NULL; _tech = NULL; } dbWireDecoder::~dbWireDecoder() { } void dbWireDecoder::begin(dbWire* wire) { _wire = (_dbWire*) wire; _block = wire->getBlock(); _tech = _block->getDb()->getTech(); _x = 0; _y = 0; _default_width = true; _layer = NULL; _idx = 0; _jct_id = -1; _opcode = END_DECODE; _wire_type = dbWireType::NONE; _point_cnt = 0; _property = 0; _deltaX1 = 0; _deltaY1 = 0; _deltaX2 = 0; _deltaY2 = 0; } inline unsigned char dbWireDecoder::nextOp(int& value) { ZASSERT(_idx < (int) _wire->length()); value = _wire->_data[_idx]; return _wire->_opcodes[_idx++]; } inline unsigned char dbWireDecoder::nextOp(uint& value) { ZASSERT(_idx < (int) _wire->length()); value = (uint) _wire->_data[_idx]; return _wire->_opcodes[_idx++]; } inline unsigned char dbWireDecoder::peekOp() { ZASSERT(_idx < (int) _wire->length()); return _wire->_opcodes[_idx]; } // // Flush the rule opcode if it exists here. The rule opcode that follows a point // is used to speed up shape-id searches. // inline void dbWireDecoder::flushRule() { if (_idx != (int) _wire->_opcodes.size()) if ((_wire->_opcodes[_idx] & WOP_OPCODE_MASK) == WOP_RULE) ++_idx; } dbWireDecoder::OpCode dbWireDecoder::peek() const { ZASSERT(_wire); int idx = _idx; nextOpCode: if (idx == (int) _wire->_opcodes.size()) return END_DECODE; unsigned char opcode = _wire->_opcodes[idx]; switch (opcode & WOP_OPCODE_MASK) { case WOP_PATH: return PATH; case WOP_SHORT: return SHORT; case WOP_JUNCTION: return JUNCTION; case WOP_RULE: return RULE; case WOP_X: case WOP_Y: case WOP_COLINEAR: if (opcode & WOP_EXTENSION) return POINT_EXT; return POINT; case WOP_VIA: return VIA; case WOP_TECH_VIA: return TECH_VIA; case WOP_ITERM: return ITERM; case WOP_BTERM: return BTERM; case WOP_RECT: return RECT; case WOP_VWIRE: return VWIRE; default: ++idx; goto nextOpCode; } } dbWireDecoder::OpCode dbWireDecoder::next() { ZASSERT(_wire); nextOpCode: if (_idx == (int) _wire->_opcodes.size()) return END_DECODE; _jct_id = _idx; unsigned char opcode = nextOp(_operand); switch (opcode & WOP_OPCODE_MASK) { case WOP_PATH: { _layer = dbTechLayer::getTechLayer(_tech, _operand); _point_cnt = 0; _default_width = true; switch (opcode & WOP_WIRE_TYPE_MASK) { case WOP_NONE: _wire_type = dbWireType::NONE; break; case WOP_COVER: _wire_type = dbWireType::COVER; break; case WOP_FIXED: _wire_type = dbWireType::FIXED; break; case WOP_ROUTED: _wire_type = dbWireType::ROUTED; break; case WOP_NOSHIELD: _wire_type = dbWireType::NOSHIELD; break; } return _opcode = PATH; } case WOP_SHORT: { _layer = dbTechLayer::getTechLayer(_tech, _operand); _point_cnt = 0; _default_width = true; switch (opcode & WOP_WIRE_TYPE_MASK) { case WOP_NONE: _wire_type = dbWireType::NONE; break; case WOP_COVER: _wire_type = dbWireType::COVER; break; case WOP_FIXED: _wire_type = dbWireType::FIXED; break; case WOP_ROUTED: _wire_type = dbWireType::ROUTED; break; case WOP_NOSHIELD: _wire_type = dbWireType::NOSHIELD; break; } // getjuction id nextOp(_operand2); return _opcode = SHORT; } case WOP_JUNCTION: { WirePoint pnt; getPrevPoint( _tech, _block, _wire->_opcodes, _wire->_data, _operand, true, pnt); _layer = pnt._layer; _x = pnt._x; _y = pnt._y; _point_cnt = 0; _default_width = true; switch (opcode & WOP_WIRE_TYPE_MASK) { case WOP_NONE: _wire_type = dbWireType::NONE; break; case WOP_COVER: _wire_type = dbWireType::COVER; break; case WOP_FIXED: _wire_type = dbWireType::FIXED; break; case WOP_ROUTED: _wire_type = dbWireType::ROUTED; break; case WOP_NOSHIELD: _wire_type = dbWireType::NOSHIELD; break; } return _opcode = JUNCTION; } case WOP_RULE: _default_width = false; _block_rule = (opcode & WOP_BLOCK_RULE); return _opcode = RULE; case WOP_X: { _x = _operand; if (_point_cnt == 0) { _jct_id = _idx; opcode = nextOp(_y); _point_cnt = 1; if (opcode & WOP_EXTENSION) { nextOp(_operand2); return _opcode = POINT_EXT; } return _opcode = POINT; } _point_cnt++; if (opcode & WOP_EXTENSION) { nextOp(_operand2); _opcode = POINT_EXT; } else _opcode = POINT; // if ( peekOp() == WOP_PROPERTY ) //{ // opcode = nextOp(_property); // assert(opcode == WOP_PROPERTY); //} // else _property = 0; flushRule(); return _opcode; } case WOP_Y: { ZASSERT(_point_cnt != 0); _point_cnt++; _y = _operand; if (opcode & WOP_EXTENSION) { nextOp(_operand2); _opcode = POINT_EXT; } else _opcode = POINT; // if ( peekOp() == WOP_PROPERTY ) //{ // opcode = nextOp(_property); // assert(opcode == WOP_PROPERTY); //} // else _property = 0; flushRule(); return _opcode; } case WOP_COLINEAR: { _point_cnt++; if (opcode & WOP_EXTENSION) { _operand2 = _operand; _opcode = POINT_EXT; } else _opcode = POINT; // if ( peekOp() == WOP_PROPERTY ) //{ // opcode = nextOp(_property); // assert(opcode == WOP_PROPERTY); //} // else _property = 0; flushRule(); return _opcode; } case WOP_VIA: { dbVia* via = dbVia::getVia(_block, _operand); if (opcode & WOP_VIA_EXIT_TOP) _layer = via->getTopLayer(); else _layer = via->getBottomLayer(); return _opcode = VIA; } case WOP_TECH_VIA: { dbTechVia* via = dbTechVia::getTechVia(_tech, _operand); if (opcode & WOP_VIA_EXIT_TOP) _layer = via->getTopLayer(); else _layer = via->getBottomLayer(); return _opcode = TECH_VIA; } case WOP_RECT: // order matches dbWireEncoder::addRect _deltaX1 = _operand; nextOp(_deltaY1); nextOp(_deltaX2); nextOp(_deltaY2); return _opcode = RECT; case WOP_ITERM: return _opcode = ITERM; case WOP_BTERM: return _opcode = BTERM; case WOP_OPERAND: ZASSERT(DB_WIRE_DECODE_INVALID_OPCODE_SEQUENCE); goto nextOpCode; case WOP_PROPERTY: goto nextOpCode; case WOP_VWIRE: { _layer = dbTechLayer::getTechLayer(_tech, _operand); _point_cnt = 0; _default_width = true; switch (opcode & WOP_WIRE_TYPE_MASK) { case WOP_NONE: _wire_type = dbWireType::NONE; break; case WOP_COVER: _wire_type = dbWireType::COVER; break; case WOP_FIXED: _wire_type = dbWireType::FIXED; break; case WOP_ROUTED: _wire_type = dbWireType::ROUTED; break; case WOP_NOSHIELD: _wire_type = dbWireType::NOSHIELD; break; } // getjuction id nextOp(_operand2); return _opcode = VWIRE; } case WOP_NOP: goto nextOpCode; default: ZASSERT(DB_WIRE_DECODE_INVALID_OPCODE); goto nextOpCode; } } dbTechLayer* dbWireDecoder::getLayer() const { return _layer; } dbTechLayerRule* dbWireDecoder::getRule() const { ZASSERT(_opcode == RULE); if (_block_rule) { return dbTechLayerRule::getTechLayerRule(_block, _operand); } else { return dbTechLayerRule::getTechLayerRule(_tech, _operand); } } void dbWireDecoder::getPoint(int& x, int& y) const { ZASSERT(_opcode == POINT); x = _x; y = _y; } void dbWireDecoder::getPoint(int& x, int& y, int& ext) const { ZASSERT(_opcode == POINT_EXT); x = _x; y = _y; ext = _operand2; } uint dbWireDecoder::getProperty() const { ZASSERT(((_opcode == POINT) || (_opcode == POINT_EXT)) && (_point_cnt > 1)); return _property; } dbVia* dbWireDecoder::getVia() const { ZASSERT(_opcode == VIA); dbVia* via = dbVia::getVia(_block, _operand); return via; } dbTechVia* dbWireDecoder::getTechVia() const { ZASSERT(_opcode == TECH_VIA); dbTechVia* via = dbTechVia::getTechVia(_tech, _operand); return via; } void dbWireDecoder::getRect(int& deltaX1, int& deltaY1, int& deltaX2, int& deltaY2) const { ZASSERT(_opcode == RECT); deltaX1 = _deltaX1; deltaY1 = _deltaY1; deltaX2 = _deltaX2; deltaY2 = _deltaY2; } dbITerm* dbWireDecoder::getITerm() const { ZASSERT(_opcode == ITERM); dbITerm* iterm = dbITerm::getITerm(_block, _operand); return iterm; } dbBTerm* dbWireDecoder::getBTerm() const { ZASSERT(_opcode == BTERM); dbBTerm* bterm = dbBTerm::getBTerm(_block, _operand); return bterm; } dbWireType dbWireDecoder::getWireType() const { ZASSERT((_opcode == PATH) || (_opcode == JUNCTION) || (_opcode == SHORT) || (_opcode == VWIRE)); return dbWireType((dbWireType::Value) _wire_type); } int dbWireDecoder::getJunctionId() const { return _jct_id; } int dbWireDecoder::getJunctionValue() const { ZASSERT((_opcode == JUNCTION) || (_opcode == SHORT) || (_opcode == VWIRE)); if (_opcode == SHORT || _opcode == VWIRE) return _operand2; return _operand; } void dumpDecoder4Net(dbNet* innet) { if (!innet) return; const char* prfx = "dumpDecoder:"; dbWire* wire0 = innet->getWire(); if (!wire0) { warning(0, "%s No wires for net %s\n", prfx, innet->getName().c_str()); return; } dbWireDecoder decoder; dbWireDecoder::OpCode opcode; int x, y, ext; decoder.begin(wire0); notice(0, "%s begin decoder for net %s\n", prfx, innet->getName().c_str()); dbTechLayer* layer; dbWireType wtype; dbTechLayerRule* lyr_rule; while (1) { opcode = decoder.next(); if (opcode == dbWireDecoder::END_DECODE) { notice(0, "%s End decoder for net %s\n", prfx, innet->getName().c_str()); break; } switch (opcode) { case dbWireDecoder::PATH: { layer = decoder.getLayer(); wtype = decoder.getWireType(); if (decoder.peek() == dbWireDecoder::RULE) { opcode = decoder.next(); lyr_rule = decoder.getRule(); notice(0, "%s New path: layer %s type %s non-default rule %s\n", prfx, layer->getName().c_str(), wtype.getString(), lyr_rule->getNonDefaultRule()->getName().c_str()); } else { notice(0, "%s New path: layer %s type %s\n", prfx, layer->getName().c_str(), wtype.getString()); } break; } case dbWireDecoder::JUNCTION: { uint jct = decoder.getJunctionValue(); lyr_rule = NULL; opcode = decoder.peek(); if (opcode == dbWireDecoder::RULE) { opcode = decoder.next(); lyr_rule = decoder.getRule(); opcode = decoder.peek(); } if (opcode == dbWireDecoder::POINT_EXT) { opcode = decoder.next(); decoder.getPoint(x, y, ext); if (lyr_rule) notice(0, "%s New path at junction %d, point(ext) %d %d %d, with rule " "%s\n", prfx, jct, x, y, ext, lyr_rule->getNonDefaultRule()->getName().c_str()); else notice(0, "%s New path at junction %d, point(ext) %d %d %d\n", prfx, jct, x, y, ext); } else if (opcode == dbWireDecoder::POINT) { opcode = decoder.next(); decoder.getPoint(x, y); if (lyr_rule) notice(0, "%s New path at junction %d, point %d %d, with rule %s\n", prfx, jct, x, y, lyr_rule->getNonDefaultRule()->getName().c_str()); else notice(0, "%s New path at junction %d, point %d %d\n", prfx, jct, x, y); } else { notice(0, "%s opcode after junction is not point or point_ext??\n", prfx); } break; } case dbWireDecoder::SHORT: { uint jval = decoder.getJunctionValue(); layer = decoder.getLayer(); wtype = decoder.getWireType(); lyr_rule = NULL; opcode = decoder.peek(); if (opcode == dbWireDecoder::RULE) { opcode = decoder.next(); lyr_rule = decoder.getRule(); } if (lyr_rule) notice(0, "%s Short at junction %d, with rule %s\n", prfx, jval, lyr_rule->getNonDefaultRule()->getName().c_str()); else notice(0, "%s Short at junction %d\n", prfx, jval); break; } case dbWireDecoder::VWIRE: { uint jval = decoder.getJunctionValue(); layer = decoder.getLayer(); wtype = decoder.getWireType(); lyr_rule = NULL; opcode = decoder.peek(); if (opcode == dbWireDecoder::RULE) { opcode = decoder.next(); lyr_rule = decoder.getRule(); } if (lyr_rule) notice(0, "%s Virtual wire at junction %d, with rule %s\n", prfx, jval, lyr_rule->getNonDefaultRule()->getName().c_str()); else notice(0, "%s Virtual wire at junction %d\n", prfx, jval); break; } case dbWireDecoder::POINT: { decoder.getPoint(x, y); notice(0, "%s Found point %d %d\n", prfx, x, y); break; } case dbWireDecoder::POINT_EXT: { decoder.getPoint(x, y, ext); notice(0, "%s Found point(ext) %d %d %d\n", prfx, x, y, ext); break; } case dbWireDecoder::TECH_VIA: { notice(0, "%s Found via %s\n", prfx, decoder.getTechVia()->getName().c_str()); break; } case dbWireDecoder::VIA: { error(0, "block via found in signal net!\n"); break; } case dbWireDecoder::RECT: { int deltaX1; int deltaY1; int deltaX2; int deltaY2; decoder.getRect(deltaX1, deltaY1, deltaX2, deltaY2); break; } case dbWireDecoder::ITERM: { notice(0, "%s Found Iterm\n", prfx); break; } case dbWireDecoder::BTERM: { notice(0, "%s Found Bterm\n", prfx); break; } case dbWireDecoder::RULE: { if (strcmp( lyr_rule->getNonDefaultRule()->getName().c_str(), (decoder.getRule())->getNonDefaultRule()->getName().c_str())) { error(0, "%s GOT RULE %s, EXPECTED RULE %s\n", prfx, lyr_rule->getNonDefaultRule()->getName().c_str(), decoder.getRule()->getNonDefaultRule()->getName().c_str()); } lyr_rule = decoder.getRule(); notice(0, "%s Found Rule %s in middle of path\n", prfx, lyr_rule->getNonDefaultRule()->getName().c_str()); break; } case dbWireDecoder::END_DECODE: notice( 0, "%s End decoder for net %s\n", prfx, innet->getName().c_str()); break; default: { error(0, "%s Hit default!\n", prfx); break; } } // switch opcode } // while } void dumpDecoder(dbBlock* inblk, const char* net_name_or_id) { const char* prfx = "dumpDecoder:"; if (!inblk || !net_name_or_id) { error(0, "%s Must specify DB Block and either net name or ID\n", prfx); return; } dbNet* innet = NULL; const char* ckdigit; for (ckdigit = net_name_or_id; *ckdigit; ckdigit++) if (!isdigit(*ckdigit)) break; innet = (*ckdigit == '\0') ? dbNet::getNet(inblk, atoi(net_name_or_id)) : inblk->findNet(net_name_or_id); if (!innet) { error(0, "%s Net %s not found\n", prfx, net_name_or_id); return; } dumpDecoder4Net(innet); } } // namespace odb