// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2009-2018, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | H u r r i c a n e A n a l o g | // | | // | Author : Damien Dupuis | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./LayoutGenerator.cpp" | // +-----------------------------------------------------------------+ #include #include #include #include #include #include #include "hurricane/Warning.h" #include "hurricane/isobar/PyBox.h" #include "hurricane/viewer/Script.h" #include "hurricane/analog/Device.h" #include "hurricane/analog/TransistorArguments.h" #include "hurricane/analog/TransistorMultiArguments.h" #include "hurricane/analog/CapacitorArguments.h" #include "hurricane/analog/PyDevice.h" #include "hurricane/analog/PyTransistorArguments.h" #include "hurricane/analog/PyTransistorMultiArguments.h" #include "hurricane/analog/PyBJTArguments.h" #include "hurricane/analog/BJTArguments.h" #include "hurricane/analog/PyCapacitorArguments.h" #include "hurricane/analog/LayoutGenerator.h" namespace Analog { using namespace std; using namespace Hurricane; using namespace Isobar; // ------------------------------------------------------------------- // Class : "::LayoutGenerator::Logger". LayoutGenerator::Logger::Logger ( LayoutGenerator* generator ) : _generator(generator) { } LayoutGenerator::Logger::~Logger () { } void LayoutGenerator::Logger::popStatus ( const string& text ) { if (_generator->getVerboseLevel() >= LayoutGenerator::Verbose) cerr << text << endl; } void LayoutGenerator::Logger::popError ( const string& text ) { string error = "! " + text; cerr << error << endl; } void LayoutGenerator::Logger::popScriptError () { string scriptError = "! An error occured while creating layout. Please check the python console for more information."; cerr << scriptError << endl; } // ------------------------------------------------------------------- // Class : "::LayoutGenerator". int LayoutGenerator::_verboseLevel = LayoutGenerator::Debug; LayoutGenerator::LayoutGenerator () : _logger (NULL) , _device (NULL) , _box (NULL) , _activeBox(NULL) , _matrix () , _script (NULL) { _activeBox = new Hurricane::Box(); _script = Script::create(); setLogger ( new Logger(this) ); } LayoutGenerator::~LayoutGenerator () { if (_script) _script->destroy(); if (_logger) delete _logger; } bool LayoutGenerator::checkScript() { if (not _device) { popError( "Try to check for script but device does not exist." ); return false; } FILE* fs = fopen( _device->getLayoutScript().c_str(), "r" ); if (not fs) { perror( NULL ); popError( "Cannot load script : file does not exist or bad access rights." ); return false; } fclose( fs ); popStatus( _device->getLayoutScript()+" found." ); return true; } bool LayoutGenerator::checkFunctions() { if (not _script->getFunction("checkCoherency")) { cerr << Error( "LayoutGenerator::drawLayout(): Module <%s> miss checkCoherency()." , _script->getUserModuleName().c_str() ) << endl; finalize( ShowTimeTag ); return false; } if (not _script->getFunction("layout")) { cerr << Error( "LayoutGenerator::drawLayout(): Module <%s> miss layout()." , _script->getUserModuleName().c_str() ) << endl; finalize( ShowTimeTag ); return false; } return true; } bool LayoutGenerator::drawLayout () { if (_device == NULL) return false; //checkScript(); cdebug_log(500,0) << "LayoutGenerator::drawLayout() " << _device->getDeviceName() << endl; _device->destroyLayout(); initialize(); if (not _script->getUserModule()) { finalize( ShowTimeTag ); cerr << Error( "LayoutGenerator::drawLayout(): Couldn't load module <%s>" , _script->getUserModuleName().c_str() ) << endl; return false; } checkFunctions(); PyObject* pyArgsCheck = NULL; PyObject* pyArgsLayout = NULL; if (not toPyArguments(_device->getArguments(),pyArgsCheck,pyArgsLayout,NoFlags)) { finalize( ShowTimeTag ); return false; } if (not callCheckCoherency(pyArgsCheck,ShowError)) { return false; } if (not callLayout(pyArgsLayout)) { cerr << "Layout failed" << endl; cerr.flush(); return false; } // Eric passed by here //cerr << "Python driven Layout successfully drawn." << endl; finalize( ShowTimeTag|StatusOk ); _device->setAbutmentBox( getDeviceBox() ); //string message = _device->checkLayoutOnPhysicalGrid(); //if (not message.empty()) // popError( message.c_str() ); // Eric passed by here //popStatus( "Layout done." ); return true; } bool LayoutGenerator::initialize () { string moduleFullPath = _device->getLayoutScript(); size_t slash = moduleFullPath.rfind( '/' ); slash = (slash!=string::npos) ? slash+1 : 0; string moduleName = moduleFullPath.substr( slash ); string modulePath = moduleFullPath.substr( 0, slash-1 ); size_t dot = moduleName.rfind( '.' ); dot = (dot!=string::npos) ? dot : moduleName.size(); moduleName = moduleName.substr( 0, dot ); // Eric passed by here //cerr << "Path: " << modulePath << endl; //cerr << "Name: " << moduleName << endl; _script->setUserModuleName( moduleName ); return _script->initialize( Script::NoThrow ); } void LayoutGenerator::finalize ( unsigned int flags ) { if (flags & ShowTimeTag) { string code = ""; // Eric passed by here //if (flags & StatusOk) code = "import time; print ' -- Script SUCCESS2 --', time.strftime('%H:%M:%S',time.localtime())\n"; if (flags & StatusOk) code = ""; else code = "import time; print ' -- Script FAILED --' , time.strftime('%H:%M:%S',time.localtime())\n"; PyRun_SimpleString( code.c_str() ); } _script->finalize(); } bool LayoutGenerator::toPyArguments ( Arguments* args, PyObject*& pyArgsCheck, PyObject*& pyArgsLayout, unsigned int flags ) { PyObject* pyArgs = NULL; if (dynamic_cast(args)) { TransistorMultiArguments* tmArgs = static_cast(args); PyTransistorMultiArguments* pyTmArgs = PyObject_NEW( PyTransistorMultiArguments, &PyTypeTransistorMultiArguments ); pyTmArgs->_object = tmArgs; pyArgs = (PyObject*)pyTmArgs; } else if (dynamic_cast(args)) { TransistorArguments* tArgs = static_cast(args); PyTransistorArguments* pyTArgs = PyObject_NEW( PyTransistorArguments, &PyTypeTransistorArguments ); pyTArgs->_object = tArgs; pyArgs = (PyObject*)pyTArgs; } else if (dynamic_cast(args)) { CapacitorArguments* cArgs = static_cast(args); PyCapacitorArguments* pyCArgs = PyObject_NEW( PyCapacitorArguments, &PyTypeCapacitorArguments ); pyCArgs->_object = cArgs; pyArgs = (PyObject*)pyCArgs; } else { popError( "Bad arguments" ); return false; } PyObject* pyDevice = PyDevice_Link( _device ); pyArgsCheck = PyTuple_New( 1 ); PyTuple_SetItem( pyArgsCheck , 0, (PyObject*)pyArgs ); pyArgsLayout = PyTuple_New( 3 ); PyTuple_SetItem( pyArgsLayout, 0, pyDevice ); PyTuple_SetItem( pyArgsLayout, 1, (PyObject*)pyArgs ); PyTuple_SetItem( pyArgsLayout, 2, (flags & ComputeBbOnly) ? Py_True : Py_False ); return true; } void LayoutGenerator::pyTransistorArguments ( TransistorArguments* tArgs , unsigned m , PyObject*& pArgsCheck , PyObject*& pArgsLayout , unsigned int flags ) { pArgsCheck = PyTuple_New( 1 ); pArgsLayout = PyTuple_New( 3 ); PyObject* pyDevice = PyDevice_Link( _device ); PyTuple_SetItem( pArgsLayout, 0, pyDevice ); tArgs->setM( m ); PyTransistorArguments* pyTArgs = PyObject_NEW( PyTransistorArguments, &PyTypeTransistorArguments ); pyTArgs->_object = tArgs; PyTuple_SetItem( pArgsCheck , 0, (PyObject*)pyTArgs ); PyTuple_SetItem( pArgsLayout, 1, (PyObject*)pyTArgs ); PyTuple_SetItem( pArgsLayout, 2, (flags & ComputeBbOnly) ? Py_True : Py_False ); } void LayoutGenerator::pyTransistorMultiArguments ( TransistorMultiArguments* dpArgs , unsigned m , PyObject*& pArgsCheck , PyObject*& pArgsLayout , unsigned int flags ) { pArgsCheck = PyTuple_New( 1 ); pArgsLayout = PyTuple_New( 3 ); PyObject* pyDevice = PyDevice_Link( _device ); PyTuple_SetItem( pArgsLayout, 0, pyDevice ); dpArgs->setM( m ); PyTransistorMultiArguments* pyTArgs = PyObject_NEW( PyTransistorMultiArguments, &PyTypeTransistorMultiArguments ); pyTArgs->_object = dpArgs; PyTuple_SetItem( pArgsCheck , 0, (PyObject*)pyTArgs ); PyTuple_SetItem( pArgsLayout, 1, (PyObject*)pyTArgs ); PyTuple_SetItem( pArgsLayout, 2, (flags & ComputeBbOnly) ? Py_True : Py_False ); } void LayoutGenerator::pyCapacitorArguments ( CapacitorArguments* cArgs , PyObject*& pArgsCheck , PyObject*& pArgsLayout , unsigned int flags ) { pArgsCheck = PyTuple_New( 1 ); pArgsLayout = PyTuple_New( 3 ); PyObject* pyDevice = PyDevice_Link( _device ); PyTuple_SetItem( pArgsLayout, 0, pyDevice ); PyCapacitorArguments* pyCArgs = PyObject_NEW( PyCapacitorArguments, &PyTypeCapacitorArguments ); pyCArgs->_object = cArgs; PyTuple_SetItem( pArgsCheck , 0, (PyObject*)pyCArgs ); PyTuple_SetItem( pArgsLayout, 1, (PyObject*)pyCArgs ); PyTuple_SetItem( pArgsLayout, 2, (flags & ComputeBbOnly) ? Py_True : Py_False ); } bool LayoutGenerator::callCheckCoherency ( PyObject* pArgsCheck, unsigned int flags ) { PyObject* pTupleCheck = _script->callFunction( "checkCoherency", pArgsCheck ); if (not pTupleCheck) { string code = "print ' -- Script FAILED --', time.strftime('%H:%M:%S',time.localtime())\n"; PyRun_SimpleString( code.c_str() ); finalize( NoFlags ); popScriptError(); return false; } if ( not PyTuple_Check(pTupleCheck) or (PyTuple_Size(pTupleCheck) != 2) ) { popError( "checkCoherency function must return a tuple: (bool,errorMessage)" ); return false; } PyObject* pCheckOk = PyTuple_GetItem( pTupleCheck, 0 ); if (pCheckOk == Py_False) { if (flags & ShowError) popError( string(PyString_AsString(PyTuple_GetItem(pTupleCheck,1))) ); return false; } return true; } bool LayoutGenerator::callLayout ( PyObject* pArgsLayout ) { _matrix = _script->callFunction( "layout", pArgsLayout ); if ((not _matrix) or (IsPyCapacitorArguments(pArgsLayout))) { string code = "print ' -- Script FAILED --', time.strftime('%H:%M:%S',time.localtime())"; PyRun_SimpleString( code.c_str() ); finalize( NoFlags ); popScriptError(); cerr << "There was a problem running layout function" << endl; return false; } return true; } unsigned LayoutGenerator::getNumberTransistor () { PyObject* row = getRow(0); if (row and PyList_Check(row) == 1) return PyList_Size(row) - 1; // -1 because of the first column for global params return 0; // else return 0; } unsigned LayoutGenerator::getNumberStack () { if (_matrix and PyList_Check(_matrix) == 1) return PyList_Size(_matrix) - 1; // -1 because of the first row for global params return 0; } Box LayoutGenerator::getDeviceBox () { PyObject* pBox = getParamValue(getDic(getRow(0), 0), "box"); if (pBox == NULL) { finalize( NoFlags ); popError("Layout function did not returned a valid device box 2!"); return Box(); } if (pBox->ob_type != &PyTypeBox) { finalize( NoFlags ); popError("Layout function did not returned a valid device box!"); } return *((PyBox*)pBox)->_object; //get the hurricane box } Box LayoutGenerator::getActiveBox () { PyObject* pBox = getParamValue(getDic(getRow(0), 0), "globalActiveBox"); if (!pBox) { finalize( NoFlags ); popError("Layout function did not returned a valid active box 2!"); return Box(); } if (pBox->ob_type != &PyTypeBox) { finalize( NoFlags ); popError("Layout function did not returned a valid active box!"); } return *((PyBox*)pBox)->_object; //get the hurricane box } double LayoutGenerator::getParameterValue ( unsigned i, unsigned j, string paramName, bool& ok ) { PyObject* pValue = getParamValue(getDic(getRow(i),j), paramName); if (pValue == NULL){ ok = false; return 0.0; } ok = true; return (PyFloat_AsDouble(pValue)); } PyObject* LayoutGenerator::getRow ( unsigned i ) { if (_matrix and PyList_Check(_matrix) == 1 and ((int)i < PyList_Size(_matrix))){ return PyList_GetItem(_matrix, i); } return NULL; } PyObject* LayoutGenerator::getDic ( PyObject* row, unsigned j ) { if (row and PyList_Check(row) == 1 and ((int)j < PyList_Size(row))){ return PyList_GetItem(row, j); } return NULL; } PyObject* LayoutGenerator::getParamValue ( PyObject* dic, string paramName ) { if (dic and (PyDict_Check(dic) == 1) and (PyDict_Contains(dic,PyString_FromString(paramName.c_str())))) return PyDict_GetItemString(dic,paramName.c_str()); return NULL; } } // Analog namespace.