/* $Id: d_mos_base.model,v 25.92 2006/06/28 15:02:53 al Exp $ -*- C++ -*-
 * Copyright (C) 2001 Albert Davis
 * Author: Albert Davis <aldavis@ieee.org>
 *
 * 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.
 *------------------------------------------------------------------
 * MOS model - base for levels 1,2,3,6
 */ 
/* This file is automatically generated. DO NOT EDIT */

  const double mDEFAULT_is = 1e-14;
#include "ap.h"
#include "d_mos_base.h"
/*--------------------------------------------------------------------------*/
const double NA(NOT_INPUT);
const double INF(BIGBIG);
/*--------------------------------------------------------------------------*/
int MODEL_MOS_BASE::_count = 0;
/*--------------------------------------------------------------------------*/
SDP_MOS_BASE::SDP_MOS_BASE(const COMMON_COMPONENT* cc)
  :SDP_DIODE(cc)
{
  assert(cc);
  const COMMON_MOS* c = prechecked_cast<const COMMON_MOS*>(cc);
  assert(c);
  const MODEL_MOS_BASE* m = prechecked_cast<const MODEL_MOS_BASE*>(c->model());
  assert(m);
  // adjust: override
  // adjust: raw
  // adjust: calculated
    l_eff = (c->l_in != NA) 
		? c->l_in * m->lmlt + m->xl - 2. * (m->ld + m->del)
		: OPT::defl;
    w_eff = (c->w_in != NA) 
		? c->w_in * m->wmlt + m->xw - 2. * m->wd
		: OPT::defw;
    ad = (c->ad_in != NA) ? c->ad_in : OPT::defad;
    as = (c->as_in != NA) ? c->as_in : OPT::defas;
    cgate = NA;
    phi = NA;
    cgso = m->cgso * w_eff;
    cgdo = m->cgdo * w_eff;
    cgbo = m->cgbo * l_eff;
  // code_post

      {if (m->rsh != NA  &&  m->rd <= 0.  &&  m->rs <= 0.) {
	rd = m->rsh * c->nrd;
	rs = m->rsh * c->nrs;
      }else{
	rd = (m->rd != NA) ? m->rd : 0.;
	rs = (m->rs != NA) ? m->rs : 0.;
      }}
      {if (m->js == NA  ||  ad == 0.  ||  as == 0.) {
	{if (m->is == NA) {
	  untested();
	  idsat = issat = mDEFAULT_is;
	  //error(bWARNING, "ignoring js, using default is\n");
	}else{
	  idsat = issat = m->is;	/* this convoluted logic */
	}}				/* is for Spice compatibility */
      }else{
	idsat = m->js * ad;
	issat = m->js * as;
      }}
}
/*--------------------------------------------------------------------------*/
TDP_MOS_BASE::TDP_MOS_BASE(const DEV_MOS*)
{
}
/*--------------------------------------------------------------------------*/
MODEL_MOS_BASE::MODEL_MOS_BASE()
  :MODEL_DIODE(),
   level(1),
   wmax(INF),
   wmin(0),
   lmax(INF),
   lmin(0),
   is(NA),
   js(NA),
   rsh(NA),
   rd(NA),
   rs(NA),
   cbd(NA),
   cbs(NA),
   cgso(0.0),
   cgdo(0.0),
   cgbo(0.0),
   cmodel(0),
   xl(0.0),
   xw(0.0),
   lmlt(1.0),
   wmlt(1.0),
   del(0.0),
   ld(0.0),
   wd(0.0),
   polarity(pN),
   tnom_k(NA),
   egap(NA),
   needs_isub(false)
{
  ++_count;
  _tnom_c = OPT::tnom_c;
}
/*--------------------------------------------------------------------------*/
bool MODEL_MOS_BASE::parse_front(CS& cmd)
{
  return ONE_OF
    || set(cmd, "NMOS", &polarity, pN)
    || set(cmd, "PMOS", &polarity, pP)
    ;
}
/*--------------------------------------------------------------------------*/
bool MODEL_MOS_BASE::parse_params(CS& cmd)
{
  return ONE_OF
    || get(cmd, "TNOM", &_tnom_c)
    || get(cmd, "FC", &fc)
    || get(cmd, "PB", &pb)
    || get(cmd, "CJ", &cjo)
    || get(cmd, "MJ", &mj)
    || get(cmd, "CJSW", &cjsw)
    || get(cmd, "PBSW", &pbsw)
    || get(cmd, "MJSW", &mjsw)
    || get(cmd, "KF", &kf)
    || get(cmd, "AF", &af)
    || get(cmd, "LEVEL", &level)
    || get(cmd, "WMAX", &wmax)
    || get(cmd, "WMIN", &wmin)
    || get(cmd, "LMAX", &lmax)
    || get(cmd, "LMIN", &lmin)
    || get(cmd, "IS", &is)
    || get(cmd, "JS", &js)
    || get(cmd, "RSH", &rsh)
    || get(cmd, "RD", &rd)
    || get(cmd, "RS", &rs)
    || get(cmd, "CBD", &cbd)
    || get(cmd, "CBS", &cbs)
    || get(cmd, "CGSo", &cgso)
    || get(cmd, "CGDo", &cgdo)
    || get(cmd, "CGBo", &cgbo)
    || get(cmd, "CMODEL", &cmodel)
    || get(cmd, "XL", &xl)
    || get(cmd, "LDEL", &xl)
    || get(cmd, "XW", &xw)
    || get(cmd, "WDEL", &xw)
    || get(cmd, "LMLT", &lmlt)
    || get(cmd, "WMLT", &wmlt)
    || get(cmd, "DEL", &del)
    || get(cmd, "LD", &ld)
    || get(cmd, "LADT", &ld)
    || get(cmd, "WD", &wd)
    ;
}
/*--------------------------------------------------------------------------*/
void MODEL_MOS_BASE::elabo1()
{
  if (1 || !evaluated()) {
    const CARD_LIST* par_scope = scope();
    assert(par_scope);
    // final adjust: code_pre
    // final adjust: override
    // final adjust: raw
    this->level.e_val(1, par_scope);
    this->wmax.e_val(INF, par_scope);
    this->wmin.e_val(0, par_scope);
    this->lmax.e_val(INF, par_scope);
    this->lmin.e_val(0, par_scope);
    this->is.e_val(NA, par_scope);
    this->js.e_val(NA, par_scope);
    this->rsh.e_val(NA, par_scope);
    this->rd.e_val(NA, par_scope);
    this->rs.e_val(NA, par_scope);
    this->cbd.e_val(NA, par_scope);
    this->cbs.e_val(NA, par_scope);
    this->cgso.e_val(0.0, par_scope);
    this->cgdo.e_val(0.0, par_scope);
    this->cgbo.e_val(0.0, par_scope);
    this->cmodel.e_val(0, par_scope);
    this->xl.e_val(0.0, par_scope);
    this->xw.e_val(0.0, par_scope);
    this->lmlt.e_val(1.0, par_scope);
    this->wmlt.e_val(1.0, par_scope);
    this->del.e_val(0.0, par_scope);
    this->ld.e_val(0.0, par_scope);
    this->wd.e_val(0.0, par_scope);
    // final adjust: mid
    // final adjust: calculated
    tnom_k = _tnom_c + P_CELSIUS0;
    egap = 1.16 - (7.02e-4*tnom_k*tnom_k) / (tnom_k+1108.);
    // final adjust: post

      {if ((rs == NA)  &&  (rd != NA)) {
	error(bWARNING,
	      long_label() + ": rd input, but not rs. setting rs = 0.\n");
	rs = 0.;
      }else if ((rd == NA)  &&  (rs != NA)) {
	untested();
	error(bWARNING, 
	      long_label() + ": rs input, but not rd. setting rd = 0.\n");
	rd = 0.;
      }else{
	/* rd, rs are ok, either have both or neither */
      }}
      
      {if ((rsh != NA)  &&  (rd != NA)) {
	error(bWARNING, long_label() + ": rsh - rs - rd conflict: using "
	      + (((rd <= 0.)  &&  (rs <= 0.)) ? "rsh" : "rs,rd") + '\n');
      }else if ((rsh == NA)  &&  (rd == NA)) {
	rsh = 0.;
      }else{
	/* rsh, rd are ok, have one or other */
      }}
      
      {if (is == NA  &&  js == NA) {
	is = mDEFAULT_is;
      }else if (is != NA  &&  js != NA) {
	error(bWARNING, long_label() + ": is - js conflict\n");
      }else{
	/* is, js are ok, have one or other */
      }}
    // final adjust: done
  }else{
    untested();
  }
}
/*--------------------------------------------------------------------------*/
SDP_CARD* MODEL_MOS_BASE::new_sdp(const COMMON_COMPONENT* c)const
{
  assert(c);
  {if (dynamic_cast<const COMMON_MOS*>(c)) {
    return new SDP_MOS_BASE(c);
  }else{
    return MODEL_DIODE::new_sdp(c);
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_MOS_BASE::print_front(OMSTREAM& o)const
{
  {if (polarity == pN) {
    o << "  nmos";
  }else if (polarity == pP) {
    o << "  pmos";
  }else{
    unreachable();
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_MOS_BASE::print_params(OMSTREAM& o)const
{
  o << "  tnom=" << _tnom_c;
  o << "  fc=" << fc;
  o << "  pb=" << pb;
  o << "  cj=" << cjo;
  o << "  mj=" << mj;
  o << "  cjsw=" << cjsw;
  if (pbsw != pb)
    o << "  pbsw=" << pbsw;
  o << "  mjsw=" << mjsw;
  if (kf != NA)
    o << "  kf=" << kf;
  if (af != NA)
    o << "  af=" << af;
  if (false)
    o << "  level=" << level;
  if (wmax<INF)
    o << "  wmax=" << wmax;
  if (wmin>0)
    o << "  wmin=" << wmin;
  if (lmax<INF)
    o << "  lmax=" << lmax;
  if (lmin>0)
    o << "  lmin=" << lmin;
  if (is != NA)
    o << "  is=" << is;
  if (js != NA)
    o << "  js=" << js;
  if (rsh != NA)
    o << "  rsh=" << rsh;
  if (rd != NA)
    o << "  rd=" << rd;
  if (rs != NA)
    o << "  rs=" << rs;
  if (cbd != NA)
    o << "  cbd=" << cbd;
  if (cbs != NA)
    o << "  cbs=" << cbs;
  o << "  cgso=" << cgso;
  o << "  cgdo=" << cgdo;
  o << "  cgbo=" << cgbo;
  if (false)
    o << "  cmodel=" << cmodel;
  if (xl!=0.0)
    o << "  xl=" << xl;
  if (xw!=0.0)
    o << "  xw=" << xw;
  if (lmlt!=1.0)
    o << "  lmlt=" << lmlt;
  if (wmlt!=1.0)
    o << "  wmlt=" << wmlt;
  if (del!=0.0)
    o << "  del=" << del;
  o << "  ld=" << ld;
  if (wd!=0.0)
    o << "  wd=" << wd;
}
/*--------------------------------------------------------------------------*/
void MODEL_MOS_BASE::print_calculated(OMSTREAM& o)const
{
  o << "";
}
/*--------------------------------------------------------------------------*/
bool MODEL_MOS_BASE::is_valid(const COMMON_COMPONENT* cc)const
{
  const COMMON_MOS* c = dynamic_cast<const COMMON_MOS*>(cc);
  {if (!c) {
    return MODEL_DIODE::is_valid(cc);
  }else{
    const MODEL_MOS_BASE* m = this;
    return c->l_in >= m->lmin && c->l_in <= m->lmax
      && c->w_in >= m->wmin && c->w_in <= m->wmax;
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_MOS_BASE::tr_eval(COMPONENT*)const
{
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
