/*$Id: bmm_semi.cc,v 26.14 2007/02/07 09:06:48 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. *------------------------------------------------------------------ * behavioral modeling * Spice3 compatible "semiconductor resistor and capacitor" */ //testing=script 2006.07.13 #include "l_dispatcher.h" #include "u_parameter.h" //#include "bmm_semi.h" /*--------------------------------------------------------------------------*/ #include "e_model.h" #include "bm.h" /*--------------------------------------------------------------------------*/ class EVAL_BM_SEMI_BASE : public EVAL_BM_ACTION_BASE { protected: PARAMETER _length; PARAMETER _width; double _value; private: static double const _default_length; static double const _default_width; static double const _default_value; protected: explicit EVAL_BM_SEMI_BASE(const EVAL_BM_SEMI_BASE& p); explicit EVAL_BM_SEMI_BASE(int c=0); ~EVAL_BM_SEMI_BASE() {} protected: // override virtual bool operator==(const COMMON_COMPONENT&)const; COMMON_COMPONENT* clone()const = 0; //void parse(CS&); //COMPONENT_COMMON void print(OMSTREAM&, LANGUAGE)const; void elabo3(const COMPONENT*); //COMMON_COMPONENT* deflate(); //COMPONENT_COMMON/nothing void tr_eval(ELEMENT*)const; //void ac_eval(ELEMENT*)const; //EVAL_BM_ACTION_BASE //bool has_tr_eval()const; //EVAL_BM_BASE/true //bool has_ac_eval()const; //EVAL_BM_BASE/true const char* name()const {untested();return modelname().c_str();} bool ac_too()const {untested();return false;} //bool parse_numlist(CS&); //COMPONENT_COMMON/nothing bool parse_params(CS&); }; /*--------------------------------------------------------------------------*/ class EVAL_BM_SEMI_CAPACITOR : public EVAL_BM_SEMI_BASE { private: explicit EVAL_BM_SEMI_CAPACITOR(const EVAL_BM_SEMI_CAPACITOR& p) :EVAL_BM_SEMI_BASE(p) {untested();} public: explicit EVAL_BM_SEMI_CAPACITOR(int c=0) :EVAL_BM_SEMI_BASE(c) {} ~EVAL_BM_SEMI_CAPACITOR() {} private: // override virtual bool operator==(const COMMON_COMPONENT&)const; COMMON_COMPONENT* clone()const {untested(); return new EVAL_BM_SEMI_CAPACITOR(*this);} //void parse(CS&); //COMPONENT_COMMON //void print(OMSTREAM&)const; //EVAL_BM_SEMI_BASE void elabo3(const COMPONENT*); //COMMON_COMPONENT* deflate(); //COMPONENT_COMMON/nothing //void tr_eval(ELEMENT*)const; //EVAL_BM_SEMI_BASE //void ac_eval(ELEMENT*)const; //EVAL_BM_ACTION_BASE //bool has_tr_eval()const; //EVAL_BM_BASE/true //bool has_ac_eval()const; //EVAL_BM_BASE/true //const char* name()const; //EVAL_BM_SEMI_BASE //bool ac_too()const //EVAL_BM_SEMI_BASE/false //bool parse_numlist(CS&); //COMPONENT_COMMON/nothing //bool parse_params(CS&); //EVAL_BM_SEMI_BASE }; /*--------------------------------------------------------------------------*/ class EVAL_BM_SEMI_RESISTOR : public EVAL_BM_SEMI_BASE { private: explicit EVAL_BM_SEMI_RESISTOR(const EVAL_BM_SEMI_RESISTOR& p) :EVAL_BM_SEMI_BASE(p) {untested();} public: explicit EVAL_BM_SEMI_RESISTOR(int c=0) :EVAL_BM_SEMI_BASE(c) {} ~EVAL_BM_SEMI_RESISTOR() {} private: // override virtual bool operator==(const COMMON_COMPONENT&)const; COMMON_COMPONENT* clone()const {untested(); return new EVAL_BM_SEMI_RESISTOR(*this);} //void parse(CS&); //COMPONENT_COMMON //void print(OMSTREAM&)const; //EVAL_BM_SEMI_BASE void elabo3(const COMPONENT*); //COMMON_COMPONENT* deflate(); //COMPONENT_COMMON/nothing //void tr_eval(ELEMENT*)const; //EVAL_BM_SEMI_BASE //void ac_eval(ELEMENT*)const; //EVAL_BM_ACTION_BASE //bool has_tr_eval()const; //EVAL_BM_BASE/true //bool has_ac_eval()const; //EVAL_BM_BASE/true //const char* name()const; //EVAL_BM_SEMI_BASE //bool ac_too()const //EVAL_BM_SEMI_BASE/false //bool parse_numlist(CS&); //COMPONENT_COMMON/nothing //bool parse_params(CS&); //EVAL_BM_SEMI_BASE }; /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ class MODEL_SEMI_BASE : public MODEL_CARD { public: PARAMETER _narrow; PARAMETER _defw; PARAMETER _tc1; PARAMETER _tc2; private: static double const _default_narrow; static double const _default_defw; static double const _default_tc1; static double const _default_tc2; protected: explicit MODEL_SEMI_BASE(); explicit MODEL_SEMI_BASE(const MODEL_SEMI_BASE& p); protected: // override virtual void elabo1(); COMMON_COMPONENT* new_common()const {untested();return new EVAL_BM_SEMI_CAPACITOR;} //CARD* clone()const //MODEL_CARD/pure bool parse_front(CS&) = 0; bool parse_params(CS&); void print_front(OMSTREAM&,LANGUAGE)const = 0; void print_params(OMSTREAM&,LANGUAGE)const; //void print_calculated(OMSTREAM&,LANGUAGE)const //MODEL_CARD/nothing }; /*--------------------------------------------------------------------------*/ class MODEL_SEMI_CAPACITOR : public MODEL_SEMI_BASE { public: PARAMETER _cj; PARAMETER _cjsw; private: static double const _default_cj; static double const _default_cjsw; private: explicit MODEL_SEMI_CAPACITOR(const MODEL_SEMI_CAPACITOR& p); public: explicit MODEL_SEMI_CAPACITOR(); private: // override virtual void elabo1(); COMMON_COMPONENT* new_common()const {return new EVAL_BM_SEMI_CAPACITOR;} CARD* clone()const {return new MODEL_SEMI_CAPACITOR(*this);} bool parse_front(CS&); bool parse_params(CS&); void print_front(OMSTREAM&,LANGUAGE)const; void print_params(OMSTREAM&,LANGUAGE)const; //void print_calculated(OMSTREAM&,LANGUAGE)const //MODEL_CARD/nothing }; /*--------------------------------------------------------------------------*/ class MODEL_SEMI_RESISTOR : public MODEL_SEMI_BASE { public: PARAMETER _rsh; private: static double const _default_rsh; private: explicit MODEL_SEMI_RESISTOR(const MODEL_SEMI_RESISTOR& p); public: explicit MODEL_SEMI_RESISTOR(); private: // override virtual void elabo1(); COMMON_COMPONENT* new_common()const {return new EVAL_BM_SEMI_RESISTOR;} CARD* clone()const {return new MODEL_SEMI_RESISTOR(*this);} bool parse_front(CS&); bool parse_params(CS&); void print_front(OMSTREAM&,LANGUAGE)const; void print_params(OMSTREAM&,LANGUAGE)const; //void print_calculated(OMSTREAM&,LANGUAGE)const //MODEL_CARD/nothing }; /*--------------------------------------------------------------------------*/ double const EVAL_BM_SEMI_BASE::_default_length = NOT_INPUT; double const EVAL_BM_SEMI_BASE::_default_width = NOT_INPUT; double const EVAL_BM_SEMI_BASE::_default_value = NOT_INPUT; /*--------------------------------------------------------------------------*/ extern DISPATCHER model_dispatcher; static MODEL_SEMI_RESISTOR p1; static MODEL_SEMI_CAPACITOR p2; static DISPATCHER::INSTALL d1(&model_dispatcher, "R,RES", &p1), d2(&model_dispatcher, "C,CAP", &p2); /*--------------------------------------------------------------------------*/ EVAL_BM_SEMI_BASE::EVAL_BM_SEMI_BASE(int c) :EVAL_BM_ACTION_BASE(c), _length(_default_length), _width(_default_width), _value(_default_value) { } /*--------------------------------------------------------------------------*/ EVAL_BM_SEMI_BASE::EVAL_BM_SEMI_BASE(const EVAL_BM_SEMI_BASE& p) :EVAL_BM_ACTION_BASE(p), _length(p._length), _width(p._width), _value(p._value) { untested(); } /*--------------------------------------------------------------------------*/ bool EVAL_BM_SEMI_BASE::operator==(const COMMON_COMPONENT& x)const { untested(); const EVAL_BM_SEMI_BASE* p = dynamic_cast(&x); bool rv = p && _length == p->_length && _width == p->_width && EVAL_BM_ACTION_BASE::operator==(x); if (rv) { untested(); }else{ untested(); } return rv; } /*--------------------------------------------------------------------------*/ void EVAL_BM_SEMI_BASE::print(OMSTREAM& o, LANGUAGE lang)const { assert(lang == lSPICE || lang == lVERILOG); o << modelname(); print_pair(o, lang, "l", _length); print_pair_if_has_value(o, lang, "w", _width); EVAL_BM_ACTION_BASE::print(o, lang); } /*--------------------------------------------------------------------------*/ void EVAL_BM_SEMI_BASE::elabo3(const COMPONENT* c) { assert(c); const CARD_LIST* s = c->scope(); assert(s); EVAL_BM_ACTION_BASE::elabo3(c); _length.e_val(_default_length, s); _width.e_val(_default_width, s); } /*--------------------------------------------------------------------------*/ void EVAL_BM_SEMI_BASE::tr_eval(ELEMENT* d)const { tr_finish_tdv(d, _value); } /*--------------------------------------------------------------------------*/ bool EVAL_BM_SEMI_BASE::parse_params(CS& cmd) { return ONE_OF || get(cmd, "L", &_length) || get(cmd, "W", &_width) || EVAL_BM_ACTION_BASE::parse_params(cmd) ; } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ bool EVAL_BM_SEMI_CAPACITOR::operator==(const COMMON_COMPONENT& x)const { untested(); const EVAL_BM_SEMI_CAPACITOR* p = dynamic_cast(&x); bool rv = p && EVAL_BM_SEMI_BASE::operator==(x); if (rv) { untested(); }else{ untested(); } return rv; } /*--------------------------------------------------------------------------*/ void EVAL_BM_SEMI_CAPACITOR::elabo3(const COMPONENT* d) { EVAL_BM_SEMI_BASE::elabo3(d); const MODEL_SEMI_CAPACITOR* m = dynamic_cast(attach_model(d)); if (!m) { untested(); error(bERROR, d->long_label() + ": model " + modelname() + " is not a semi-capacitor (C)\n"); } double width = (_width == NOT_INPUT) ? m->_defw : _width; double eff_width = width - m->_narrow; double eff_length = _length - m->_narrow; if (eff_width <= 0.) { untested(); error(bWARNING, d->long_label() + ": " + modelname() + ": effective width is negative or zero\n"); } if (eff_length <= 0.) { untested(); error(bWARNING, d->long_label() + ": " + modelname() + ": effective length is negative or zero\n"); } _value = m->_cj * eff_length * eff_width + 2. * m->_cjsw * (eff_length + eff_width); double tempdiff = (_temp_c - m->_tnom_c); _value *= 1 + m->_tc1*tempdiff + m->_tc2*tempdiff*tempdiff; } /*--------------------------------------------------------------------------*/ bool EVAL_BM_SEMI_RESISTOR::operator==(const COMMON_COMPONENT& x)const { untested(); const EVAL_BM_SEMI_RESISTOR* p = dynamic_cast(&x); bool rv = p && EVAL_BM_SEMI_BASE::operator==(x); if (rv) { untested(); }else{ untested(); } return rv; } /*--------------------------------------------------------------------------*/ void EVAL_BM_SEMI_RESISTOR::elabo3(const COMPONENT* d) { EVAL_BM_SEMI_BASE::elabo3(d); const MODEL_SEMI_RESISTOR* m = dynamic_cast(attach_model(d)); if (!m) { untested(); error(bERROR, d->long_label() + ": " + "model " + modelname() + " is not a semi-resistor (R)\n"); } double width = (_width == NOT_INPUT) ? m->_defw : _width; double eff_width = width - m->_narrow; double eff_length = _length - m->_narrow; if (eff_width <= 0.) { untested(); error(bWARNING, d->long_label() + ": " + modelname() + ": effective width is negative or zero\n"); } if (eff_length <= 0.) { error(bWARNING, d->long_label() + ": " + modelname() + ": effective length is negative or zero\n"); } if (eff_width != 0.) { _value = m->_rsh * eff_length / eff_width; }else{ untested(); _value = BIGBIG; } double tempdiff = (_temp_c - m->_tnom_c); _value *= 1 + m->_tc1*tempdiff + m->_tc2*tempdiff*tempdiff; } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ double const MODEL_SEMI_BASE::_default_narrow = 0.; double const MODEL_SEMI_BASE::_default_defw = 1e-6; double const MODEL_SEMI_BASE::_default_tc1 = 0.; double const MODEL_SEMI_BASE::_default_tc2 = 0.; /*--------------------------------------------------------------------------*/ MODEL_SEMI_BASE::MODEL_SEMI_BASE() :MODEL_CARD(), _narrow(_default_narrow), _defw(_default_defw), _tc1(_default_tc1), _tc2(_default_tc2) { } /*--------------------------------------------------------------------------*/ MODEL_SEMI_BASE::MODEL_SEMI_BASE(const MODEL_SEMI_BASE& p) :MODEL_CARD(p), _narrow(p._narrow), _defw(p._defw), _tc1(p._tc1), _tc2(p._tc2) { } /*--------------------------------------------------------------------------*/ bool MODEL_SEMI_BASE::parse_params(CS& cmd) { return ONE_OF || get(cmd, "NARROW", &_narrow) || get(cmd, "DEFW", &_defw) || get(cmd, "TC1", &_tc1) || get(cmd, "TC2", &_tc2) || MODEL_CARD::parse_params(cmd); ; } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_BASE::print_params(OMSTREAM& o ,LANGUAGE lang)const { assert(lang == lSPICE || lang == lVERILOG); print_pair(o, lang, "narrow", _narrow); print_pair(o, lang, "defw", _defw); print_pair(o, lang, "tc1", _tc1); print_pair(o, lang, "tc2", _tc2); MODEL_CARD::print_params(o, lang); } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_BASE::elabo1() { if (1 || !evaluated()) { const CARD_LIST* s = scope(); assert(s); MODEL_CARD::elabo1(); _narrow.e_val(_default_narrow, s); _defw.e_val(_default_defw, s); _tc1.e_val(_default_tc1, s); _tc2.e_val(_default_tc2, s); }else{ unreachable(); } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ double const MODEL_SEMI_CAPACITOR::_default_cj = 0.; double const MODEL_SEMI_CAPACITOR::_default_cjsw = 0.; /*--------------------------------------------------------------------------*/ MODEL_SEMI_CAPACITOR::MODEL_SEMI_CAPACITOR() :MODEL_SEMI_BASE(), _cj(_default_cj), _cjsw(_default_cjsw) { } /*--------------------------------------------------------------------------*/ MODEL_SEMI_CAPACITOR::MODEL_SEMI_CAPACITOR(const MODEL_SEMI_CAPACITOR& p) :MODEL_SEMI_BASE(p), _cj(p._cj), _cjsw(p._cjsw) { } /*--------------------------------------------------------------------------*/ bool MODEL_SEMI_CAPACITOR::parse_front(CS& cmd) { bool dummy; return set(cmd, "Cap", &dummy, true); } /*--------------------------------------------------------------------------*/ bool MODEL_SEMI_CAPACITOR::parse_params(CS& cmd) { return ONE_OF || get(cmd, "CJ", &_cj) || get(cmd, "CJSW", &_cjsw) || MODEL_SEMI_BASE::parse_params(cmd) ; } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_CAPACITOR::print_front(OMSTREAM& o, LANGUAGE lang)const { assert(lang == lSPICE || lang == lVERILOG); o << "c"; } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_CAPACITOR::print_params(OMSTREAM& o, LANGUAGE lang)const { print_pair(o, lang, "cj", _cj); print_pair(o, lang, "cjsw", _cjsw); MODEL_SEMI_BASE::print_params(o, lang); } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_CAPACITOR::elabo1() { if (1 || !evaluated()) { const CARD_LIST* s = scope(); assert(s); MODEL_SEMI_BASE::elabo1(); _cj.e_val(_default_cj, s); _cjsw.e_val(_default_cjsw, s); }else{ unreachable(); } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ double const MODEL_SEMI_RESISTOR::_default_rsh = NOT_INPUT; /*--------------------------------------------------------------------------*/ MODEL_SEMI_RESISTOR::MODEL_SEMI_RESISTOR() :MODEL_SEMI_BASE(), _rsh(_default_rsh) { } /*--------------------------------------------------------------------------*/ MODEL_SEMI_RESISTOR::MODEL_SEMI_RESISTOR(const MODEL_SEMI_RESISTOR& p) :MODEL_SEMI_BASE(), _rsh(p._rsh) { } /*--------------------------------------------------------------------------*/ bool MODEL_SEMI_RESISTOR::parse_front(CS& cmd) { bool dummy; return set(cmd, "Res", &dummy, true); } /*--------------------------------------------------------------------------*/ bool MODEL_SEMI_RESISTOR::parse_params(CS& cmd) { return ONE_OF || get(cmd, "RSH", &_rsh) || MODEL_SEMI_BASE::parse_params(cmd) ; } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_RESISTOR::print_front(OMSTREAM& o, LANGUAGE lang)const { assert(lang == lSPICE || lang == lVERILOG); o << "r"; } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_RESISTOR::print_params(OMSTREAM& o, LANGUAGE lang)const { print_pair(o, lang, "rsh", _rsh); MODEL_SEMI_BASE::print_params(o, lang); } /*--------------------------------------------------------------------------*/ void MODEL_SEMI_RESISTOR::elabo1() { if (1 || !evaluated()) { const CARD_LIST* par_scope = scope(); assert(par_scope); MODEL_SEMI_BASE::elabo1(); _rsh.e_val(_default_rsh, par_scope); }else{ unreachable(); } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/