// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2018, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | K i t e - D e t a i l e d R o u t e r | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./DataSymmetric.cpp" | // +-----------------------------------------------------------------+ #include "anabatic/AutoSegment.h" #include "katana/DataSymmetric.h" #include "katana/Session.h" namespace { using namespace std; class Message { public: inline Message ( size_t, string header="" ); inline size_t size () const; inline ostringstream& newline (); inline ostringstream& line (); inline void setHeader ( string ); void print ( ostream& ); private: size_t _indent; string _header; vector _lines; ostringstream _current; }; inline Message::Message ( size_t indent, string header ) : _indent (indent) , _header (header) , _lines () , _current() { } inline size_t Message::size () const { return _lines.size(); } inline void Message::setHeader ( string header ) { _header = header; } inline ostringstream& Message::line () { return _current; } inline ostringstream& Message::newline () { if (_current.str().size()) _lines.push_back(_current.str()); _current.str(""); return _current; } void Message::print ( ostream& o ) { if (not _header.empty()) _indent = _header.size()+1; string head ( _indent, ' ' ); for ( size_t i=0 ; i<_lines.size() ; ++i ) { if ((i == 0) and not _header.empty()) o << _header << " "; else o << head; o << _lines[i] << endl; } } } // Anonymous namespace. namespace Katana { using namespace std; using Anabatic::AutoSegment; DataSymmetric* DataSymmetric::create ( Net* net ) { NetRoutingState* state = NetRoutingExtension::get( net ); if (not state or not state->isSymmetric()) return NULL; if (state->getSymNet() and not state->isSymMaster()) return NULL; return new DataSymmetric ( net ); } DataSymmetric::DataSymmetric ( Net* net ) : _valid (true) , _net (net) , _symNet (NULL) , _state (NetRoutingExtension::get(_net)) , _paireds () , _symIndex(0) { _symNet = _state->getSymNet(); } void DataSymmetric::addSymmetrical ( AutoSegment* symmetrical ) { if (_paireds.size() > _symIndex) _paireds[_symIndex++][1] = symmetrical; else _paireds.push_back( {{ NULL, symmetrical }} ); } AutoSegment* DataSymmetric::getSymmetrical ( AutoSegment* segment ) const { for ( const array& paired : _paireds ) { if (segment == paired[0]) return paired[1]; if (segment == paired[1]) return paired[0]; } return NULL; } bool DataSymmetric::checkPairing () { const uint64_t mask = ~(AutoSegment::SegIsReduced); Message errors ( 0, "[ERROR]" ); // Temporary hardwired: M2 (depth 1) for H pitch, M3 (depth 2) for V pitch. DbU::Unit hPitch = Session::getPitch( 1 ); DbU::Unit vPitch = Session::getPitch( 2 ); size_t refs = 0; size_t syms = 0; for ( const array& paired : _paireds ) { refs += (paired[0]) ? 1 : 0; syms += (paired[1]) ? 1 : 0; } if (refs != syms) { errors.newline() << "Segments symmetric sets size mismatch, reference:" << refs << " symmetricals:" << syms << "."; _valid = false; } else { size_t index = 0; for ( const array& paired : _paireds ) { if (paired[0]->isHorizontal() xor paired[1]->isHorizontal()) { errors.newline() << "Direction mismatch @ [" << index << "]"; errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; _valid = false; } if (paired[0]->getLayer() != paired[1]->getLayer()) { errors.newline() << "Layer mismatch @ [" << index << "]"; errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; _valid = false; } if (_state->isSymVertical()) { if (paired[0]->isVertical()) { if ( (paired[0]->getFlags() ^ paired[1]->getFlags()) & mask ) { errors.newline() << "Flags mismatch at index " << index << " " << paired[0]->getFlags() << " vs. " << paired[1]->getFlags(); errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; _valid = false; } if (std::abs( 2*getSymAxis() - paired[0]->getAxis() - paired[1]->getAxis() ) > 5*vPitch ) { errors.newline() << "Mirror axis mismatch @ [" << index << "] " << DbU::getValueString(paired[1]->getAxis()) << " (should be: " << DbU::getValueString(2*getSymAxis() - paired[0]->getAxis()) << ")"; errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; errors.newline() << "| Tolerance (5*vPitch): " << DbU::getValueString(5*vPitch); _valid = false; } } else { if ( (paired[0]->getFlags() ^ AutoSegment::swapSourceTargetFlags(paired[1])) & mask ) { errors.newline() << "Flags mismatch at index " << index << " " << paired[0]->getFlags() << " vs. " << paired[1]->getFlags() << " swp " << AutoSegment::swapSourceTargetFlags(paired[1]); _valid = false; } if ( std::abs( paired[0]->getAxis() - paired[1]->getAxis() ) > 5*hPitch ) { errors.newline() << "Axis mismatch index " << index << " " << DbU::getValueString(paired[1]->getAxis()) << " (should be:" << DbU::getValueString(paired[0]->getAxis()) << ")"; errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; errors.newline() << "| Tolerance (5*hPitch): " << DbU::getValueString(5*hPitch); _valid = false; } } } else { if (paired[0]->isHorizontal()) { if ( std::abs( 2*getSymAxis() - paired[0]->getAxis() - paired[1]->getAxis() ) > 5*hPitch ) { errors.newline() << "Mirror axis mismatch index " << index << " " << DbU::getValueString(paired[1]->getAxis()) << " (should be:" << DbU::getValueString(2*getSymAxis() - paired[0]->getAxis()) << ")"; errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; errors.newline() << "| Tolerance (5*hPitch): " << DbU::getValueString(5*hPitch); _valid = false; } } else { if ( std::abs( paired[0]->getAxis() != paired[1]->getAxis() ) > 5*vPitch ) { errors.newline() << "Axis mismatch index " << index << " " << DbU::getValueString(paired[1]->getAxis()) << " (should be:" << DbU::getValueString(paired[0]->getAxis()) << ")"; errors.newline() << "| " << paired[0]; errors.newline() << "| " << paired[1]; errors.newline() << "| Tolerance (5*vPitch): " << DbU::getValueString(5*vPitch); _valid = false; } } } ++index; } } errors.newline(); if (errors.size()) { //cmess2 << " pairing failed." << endl; errors.print( cmess2 ); } else { //cmess2 << " paired." << endl; } return _valid; } void DataSymmetric::print ( ostream& o ) const { Message lines ( 0 ); lines.newline() << "Paired components of Net \"" << _net->getName() << "\""; if (_symNet) lines.line() << " (symmetrical:\"" << _symNet->getName() << "\")"; size_t index = 0; for ( const array& paired : _paireds ) { lines.newline() << "| " << setw(2) << index << " " << paired[0]; lines.newline() << "+ " << setw(2) << index << " " << paired[1]; ++index; } lines.newline(); lines.print( o ); } string DataSymmetric::_getString () const { return "getName()) + ">"; } Record* DataSymmetric::_getRecord () const { Record* record = new Record ( getString(this) ); record->add( getSlot( "_valid" , _valid ) ); record->add( getSlot( "_net" , _net ) ); record->add( getSlot( "_symNet" , _symNet ) ); record->add( getSlot( "_state" , _state ) ); record->add( getSlot( "_paireds" , &_paireds ) ); record->add( getSlot( "_symIndex" , &_symIndex ) ); return record; } } // Katana namespace.