/*$Id: d_subckt.cc,v 26.19 2007/03/11 06:22:41 al Exp $ -*- C++ -*- * Copyright (C) 2001 Albert Davis * Author: Albert Davis * * This file is part of "Gnucap", the Gnu Circuit Analysis Package * * 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 2, 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. *------------------------------------------------------------------ * subcircuit stuff * base class for other elements using internal subckts * netlist syntax: * device: Xxxxx * model: .subckt * (device cards) * .ends * storage note ... * the .subckt always has a comment at the hook point, so a for loop works * the expansion (attact to the X) has all comments removed * - need to process the entire ring - for doesn't work */ //testing=script 2006.07.17 #include "l_dispatcher.h" #include "d_subckt.h" /*--------------------------------------------------------------------------*/ int DEV_SUBCKT::_count = -1; int COMMON_SUBCKT::_count = -1; int MODEL_SUBCKT::_count = -1; static COMMON_SUBCKT Default_SUBCKT(CC_STATIC); /*--------------------------------------------------------------------------*/ extern DISPATCHER device_dispatcher; static DEV_SUBCKT p1; static MODEL_SUBCKT p2; static DISPATCHER::INSTALL d1(&device_dispatcher, "X,dev_subckt", &p1), d2(&device_dispatcher, "subckt,macro", &p2); /*--------------------------------------------------------------------------*/ bool COMMON_SUBCKT::operator==(const COMMON_COMPONENT& x)const { const COMMON_SUBCKT* p = dynamic_cast(&x); bool rv = p && _params == p->_params && COMMON_COMPONENT::operator==(x); return rv; } /*--------------------------------------------------------------------------*/ MODEL_SUBCKT::MODEL_SUBCKT() :COMPONENT(), _net_nodes(0) { _n = _nodes; new_subckt(); ++_count; } /*--------------------------------------------------------------------------*/ MODEL_SUBCKT::MODEL_SUBCKT(const MODEL_SUBCKT& p) :COMPONENT(p), _net_nodes(p._net_nodes) { for (int ii = 0; ii < max_nodes(); ++ii) { _nodes[ii] = p._nodes[ii]; } _n = _nodes; assert(p.subckt()->is_empty()); // incomplete, but enough for now. new_subckt(); ++_count; } /*--------------------------------------------------------------------------*/ MODEL_SUBCKT::~MODEL_SUBCKT() { --_count; } /*--------------------------------------------------------------------------*/ void MODEL_SUBCKT::parse_spice(CS& cmd) { // parse the line cmd.reset(); cmd.skiparg(); /* skip known ".subckt" */ parse_label(cmd); _net_nodes = parse_nodes(cmd, max_nodes(), min_nodes(), 0/*no unnamed par*/, 0/*start*/, true/*all new*/); cmd.check(bDANGER, "subckt default parameters not supported yet"); } /*--------------------------------------------------------------------------*/ void MODEL_SUBCKT::print(OMSTREAM& o, LANGUAGE lang)const { switch (lang) { case lACS:untested(); case lSPICE: o << ".subckt "; print_label(o, lang); print_nodes(o, lang); o << '\n'; if (subckt()) { for (CARD_LIST::const_iterator ci = subckt()->begin(); ci != subckt()->end(); ++ci) { (**ci).print(o, lang); } }else{untested(); } o << ".ends " << short_label() << '\n'; break; case lVERILOG:itested(); o << "module "; print_label(o, lang); print_nodes(o, lang); o << ";\n"; if (subckt()) {itested(); for (CARD_LIST::const_iterator ci = subckt()->begin(); ci != subckt()->end(); ++ci) {itested(); (**ci).print(o, lang); } }else{untested(); } o << "endmodule // " << short_label() << '\n'; break; case lAUTO: unreachable(); break; } } /*--------------------------------------------------------------------------*/ DEV_SUBCKT::DEV_SUBCKT() :BASE_SUBCKT() { attach_common(&Default_SUBCKT); _n = _nodes; ++_count; } /*--------------------------------------------------------------------------*/ DEV_SUBCKT::DEV_SUBCKT(const DEV_SUBCKT& p) :BASE_SUBCKT(p) { //strcpy(modelname, p.modelname); in common for (int ii = 0; ii < max_nodes(); ++ii) { _nodes[ii] = p._nodes[ii]; } _n = _nodes; ++_count; } /*--------------------------------------------------------------------------*/ void DEV_SUBCKT::print(OMSTREAM& o, LANGUAGE lang)const { const COMMON_SUBCKT* c = prechecked_cast(common()); assert(c); switch (lang) { case lACS:untested(); print_type(o, lang); print_label(o, lang); print_nodes(o, lang); o << " " << c->modelname(); print_args(o, lang); o << '\n'; break; case lSPICE: print_label(o, lang); print_nodes(o, lang); print_type(o, lang); print_args(o, lang); o << '\n'; break; case lVERILOG:untested(); print_type(o, lang); print_args(o, lang); print_label(o, lang); print_nodes(o, lang); o << ";\n"; break; case lAUTO: unreachable(); break; } } /*--------------------------------------------------------------------------*/ static const CARD* find_subckt_model(CARD* scope, const std::string& modelname) { const CARD* model = 0; { model = scope->find_looking_out(modelname, bDEBUG); if (!model) {untested(); error(bDANGER, "can't find subckt: " + modelname + '\n'); return NULL; }else if(!dynamic_cast(model)) {untested(); error(bDANGER, modelname + " is not a subckt\n"); return NULL; }else{ } } return model; } /*--------------------------------------------------------------------------*/ void DEV_SUBCKT::elabo1() { BASE_SUBCKT::elabo1(); COMMON_SUBCKT* c = prechecked_cast(mutable_common()); assert(c); const CARD* model = find_subckt_model(this /*scope*/, c->modelname()); if (!model) {untested(); error(bERROR, "no subckt\n"); }else{ } new_subckt(model, this, scope(), &(c->_params)); subckt()->elabo2(); assert(!is_constant()); /* because I have more work to do */ } /*--------------------------------------------------------------------------*/ double DEV_SUBCKT::tr_probe_num(CS& cmd)const {itested(); if (cmd.pmatch("V")) {itested(); int nn = cmd.ctoi(); return (nn > 0 && nn <= net_nodes()) ? _n[nn-1].v0() : NOT_VALID; }else if (cmd.pmatch("P")) {untested(); double power = 0.; assert(subckt()); for (CARD_LIST::const_iterator ci = subckt()->begin(); ci != subckt()->end(); ++ci) {untested(); power += CARD::probe(*ci,"P"); } return power; }else if (cmd.pmatch("PD")) {untested(); double power = 0.; assert(subckt()); for (CARD_LIST::const_iterator ci = subckt()->begin(); ci != subckt()->end(); ++ci) {untested(); power += CARD::probe(*ci,"PD"); } return power; }else if (cmd.pmatch("PS")) {untested(); double power = 0.; assert(subckt()); for (CARD_LIST::const_iterator ci = subckt()->begin(); ci != subckt()->end(); ++ci) {untested(); power += CARD::probe(*ci,"PS"); } return power; }else{untested(); return COMPONENT::tr_probe_num(cmd); } /*NOTREACHED*/ } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/