Qucs-core  0.0.19
check_spice.cpp
Go to the documentation of this file.
00001 /*
00002  * check_spice.cpp - checker for a Spice netlist
00003  *
00004  * Copyright (C) 2004-2011 Stefan Jahn <stefan@lkcc.org>
00005  *
00006  * This is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2, or (at your option)
00009  * any later version.
00010  *
00011  * This software is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this package; see the file COPYING.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  * $Id$
00022  *
00023  */
00024 
00025 #if HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <cmath>
00033 #include <assert.h>
00034 #include <float.h>
00035 #include <ctype.h>
00036 
00037 #if defined(_WIN32) & not defined(__MINGW32__)
00038 #define strcasecmp stricmp
00039 #endif
00040 
00041 #include "constants.h"
00042 #include "check_spice.h"
00043 #include "qucs_producer.h"
00044 #include "hash.h"
00045 
00046 /* Global definitions for parser and checker. */
00047 struct definition_t * definition_root = NULL;
00048 struct definition_t * subcircuit_root = NULL;
00049 struct definition_t * device_root = NULL;
00050 int spice_errors = 0;
00051 char * spice_title = NULL;
00052 
00053 // List of available Spice component properties.
00054 static struct property_t spice_noprops[] = { PROP_NO_PROP };
00055 
00056 static struct property_t req_spice_R[] = {
00057   { "R", PROP_REAL, { 50, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00058 static struct property_t opt_spice_R[] = {
00059   { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
00060   PROP_NO_PROP };
00061 
00062 static struct property_t req_spice_L[] = {
00063   { "L", PROP_REAL, { 1e-9, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00064 
00065 static struct property_t req_spice_C[] = {
00066   { "C", PROP_REAL, { 1e-12, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00067 
00068 static struct property_t req_spice_V[] = {
00069   { "U", PROP_REAL, { 1, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00070 
00071 static struct property_t req_spice_I[] = {
00072   { "I", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00073 
00074 static struct property_t req_spice_G[] = {
00075   { "G", PROP_REAL, { 1, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00076 
00077 static struct property_t req_spice_E[] = {
00078   { "G", PROP_REAL, { 1, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00079 
00080 static struct property_t req_spice_F[] = {
00081   { "G", PROP_REAL, { 1, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00082 
00083 static struct property_t req_spice_H[] = {
00084   { "G", PROP_REAL, { 1, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00085 
00086 static struct property_t req_spice_T[] = {
00087   { "Z0", PROP_REAL, { 50, PROP_NO_STR }, PROP_POS_RANGE }, PROP_NO_PROP };
00088 
00089 static struct property_t req_spice_NODESET[] = {
00090   { "U", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00091 
00092 static struct property_t req_spice_IC[] = {
00093   { "U", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, PROP_NO_PROP };
00094 
00095 // List of available Spice components.
00096 struct define_t spice_definition_available[] =
00097 {
00098   /* resistor */
00099   { "R", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00100     req_spice_R, opt_spice_R },
00101   /* inductor */
00102   { "L", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00103     req_spice_L, spice_noprops },
00104   /* capacitor */
00105   { "C", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00106     req_spice_C, spice_noprops },
00107   /* voltage sources */
00108   { "V", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00109     req_spice_V, spice_noprops },
00110   /* current sources */
00111   { "I", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00112     req_spice_I, spice_noprops },
00113   /* voltage-controlled current source */
00114   { "G", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00115     req_spice_G, spice_noprops },
00116   /* voltage-controlled voltage source */
00117   { "E", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00118     req_spice_E, spice_noprops },
00119   /* current-controlled current source */
00120   { "F", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00121     req_spice_F, spice_noprops },
00122   /* current-controlled voltage source */
00123   { "H", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00124     req_spice_H, spice_noprops },
00125   /* transformer (mutual inductors) */
00126   { "K", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00127     spice_noprops, spice_noprops },
00128   /* BJT device */
00129   { "Q", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR,
00130     spice_noprops, spice_noprops },
00131   /* MOS device */
00132   { "M", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR,
00133     spice_noprops, spice_noprops },
00134   /* JFET device */
00135   { "J", 3, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR,
00136     spice_noprops, spice_noprops },
00137   /* diodes */
00138   { "D", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR,
00139     spice_noprops, spice_noprops },
00140   /* relais */
00141   { "S", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00142     spice_noprops, spice_noprops },
00143   /* lossless transmission line */
00144   { "T", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00145     req_spice_T, spice_noprops },
00146   /* transient analysis */
00147   { "TRAN", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR,
00148     spice_noprops, spice_noprops },
00149   /* AC analysis */
00150   { "AC", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR,
00151     spice_noprops, spice_noprops },
00152   /* DC analysis */
00153   { "DC", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR,
00154     spice_noprops, spice_noprops },
00155   /* operating point analysis */
00156   { "OP", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR,
00157     spice_noprops, spice_noprops },
00158   /* subcircuit instance */
00159   { "X", PROP_NODES, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00160     spice_noprops, spice_noprops },
00161   /* subcircuit definition */
00162   { "SUBCKT", PROP_NODES, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR,
00163     spice_noprops, spice_noprops },
00164   /* nodeset functionality */
00165   { "NODESET", 1, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00166     req_spice_NODESET, spice_noprops },
00167   /* nodeset functionality */
00168   { "IC", 1, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR,
00169     req_spice_IC, spice_noprops },
00170 
00171   /* end of list */
00172   { NULL, 0, 0, 0, 0, spice_noprops, spice_noprops },
00173 };
00174 
00175 // Include also the (generated) Qucs definitions.
00176 #include "qucsdefs.h"
00177 
00178 // Short definition for iterating a list of values.
00179 #define foreach_value(values,val) \
00180   for ((val) = (values); (val) != NULL; (val) = (val)->next) \
00181     if (!((val)->hint & HINT_DONE))
00182 
00183 /* The function reverses the order of the given value list and returns
00184    the reversed list. */
00185 struct value_t * netlist_reverse_values (struct value_t * values) {
00186   struct value_t * root, * next;
00187   for (root = NULL; values != NULL; values = next) {
00188     next = values->next;
00189     values->next = root;
00190     root = values;
00191   }
00192   return root;
00193 }
00194 
00195 /* The function reverses the order of the given pair list and returns
00196    the reversed list. */
00197 struct pair_t * netlist_reverse_pairs (struct pair_t * pairs) {
00198   struct pair_t * root, * next;
00199   for (root = NULL; pairs != NULL; pairs = next) {
00200     next = pairs->next;
00201     pairs->next = root;
00202     root = pairs;
00203   }
00204   return root;
00205 }
00206 
00207 /* The function reverses the order of the given node list and returns
00208    the reversed list. */
00209 struct node_t * netlist_reverse_nodes (struct node_t * nodes) {
00210   struct node_t * root, * next;
00211   for (root = NULL; nodes != NULL; nodes = next) {
00212     next = nodes->next;
00213     nodes->next = root;
00214     root = nodes;
00215   }
00216   return root;
00217 }
00218 
00219 // The function appends lists of pairs and returns the resulting list.
00220 struct pair_t *
00221 netlist_append_pairs (struct pair_t * p1, struct pair_t * p2) {
00222   if (p1 == NULL) return p2;
00223   struct pair_t * pair;
00224   for (pair = p1; pair->next != NULL; pair = pair->next) ;
00225   pair->next = p2;
00226   return p1;
00227 }
00228 
00229 // The function appends lists of values and returns the resulting list.
00230 struct value_t *
00231 netlist_append_values (struct value_t * v1, struct value_t * v2) {
00232   if (v1 == NULL) return v2;
00233   struct value_t * val;
00234   for (val = v1; val->next != NULL; val = val->next) ;
00235   val->next = v2;
00236   return v1;
00237 }
00238 
00239 // The function appends lists of nodes and returns the resulting list.
00240 struct node_t *
00241 netlist_append_nodes (struct node_t * n1, struct node_t * n2) {
00242   if (n1 == NULL) return n2;
00243   struct node_t * node;
00244   for (node = n1; node->next != NULL; node = node->next) ;
00245   node->next = n2;
00246   return n1;
00247 }
00248 
00249 /* This function goes through the list of available definitions and
00250    checks whether the given component type can be found. */
00251 static struct define_t * spice_find_definition (const char * n) {
00252   struct define_t * def;
00253   for (def = spice_definition_available; def->type != NULL; def++)
00254     if (!strcasecmp (n, def->type)) return def;
00255   return NULL;
00256 }
00257 
00258 /* The function creates a single translated spice node. */
00259 static struct node_t * spice_translate_node (char * node) {
00260   struct node_t * n = create_node ();
00261   if (!strcmp (node, "0")) { // translate ground node
00262     n->node = strdup (qucs_gnd);
00263   }
00264   else {                     // translated other node than ground
00265     n->node = (char *) malloc (5 + strlen (node));
00266     strcpy (n->node, "_net");
00267     strcat (n->node, node);
00268     // strip off invalid characters
00269     for (unsigned int i = 0; i < strlen (n->node); i++) {
00270       if (!isalpha (n->node[i]) && !isdigit (n->node[i])) {
00271         switch (n->node[i]) {
00272         case '+': n->node[i] = 'P'; break;
00273         case '-': n->node[i] = 'N'; break;
00274         default : n->node[i] = '_'; break;
00275         }
00276       }
00277     }
00278   }
00279   return n;
00280 }
00281 
00282 /* The function marks the given value to be processed and free()'s
00283    unnecessary memory. */
00284 static void spice_value_done (struct value_t * val) {
00285   if (val->ident) { free (val->ident); val->ident = NULL; }
00286   if (val->unit)  { free (val->unit);  val->unit = NULL;  }
00287   if (val->scale) { free (val->scale); val->scale = NULL; }
00288   val->hint |= HINT_DONE;
00289 }
00290 
00291 /* The function creates the nodes list for the given component. */
00292 static struct node_t * spice_get_nodes (struct definition_t * def) {
00293 
00294   // has this component actually any nodes to define?
00295   int nodes = def->define->nodes;
00296   if (nodes == 0) return NULL;
00297 
00298   // go through value list and try identifying nodes
00299   struct value_t * val;
00300   struct node_t * root = NULL;
00301   int i = 0;
00302   foreach_value (def->values, val) {
00303     if (val->hint & HINT_NODE) {
00304       struct node_t * n = spice_translate_node (val->ident);
00305       n->next = root;
00306       root = n;
00307       spice_value_done (val);
00308       // continue until all nodes are done
00309       if (++i >= nodes && nodes != PROP_NODES) break;
00310     }
00311     // nodes are defined successively
00312     else break;
00313   }
00314   // return reversed list of nodes
00315   return netlist_reverse_nodes (root);
00316 }
00317 
00318 /* Evaluates the unit scale in a property value.  It adjusts the
00319    actual value and omits the scale.  The function returns NULL if
00320    there is no valid scale found and otherwise the corrected scale.
00321    The given endptr is set to the character after the last valid scale
00322    character. */
00323 static const char *
00324 spice_evaluate_scale (char * value, char ** endptr, double * factor) {
00325   const char * scale = NULL;
00326   *factor = 1.0;
00327   switch (*value) {
00328   case 'T': case 't':
00329     value++; scale = "T"; break;
00330   case 'G': case 'g':
00331     value++; scale = "G"; break;
00332   case 'M': case 'm':
00333     value++; scale = (char *) ((*value == 'M') ? "M" : "m");
00334     if ((value[0] == 'i' || value[0] == 'I') &&
00335         (value[1] == 'l' || value[1] == 'L')) {
00336       value += 2; *factor = 2.54e-5; scale = NULL;
00337     }
00338     if ((value[0] == 'e' || value[0] == 'E') &&
00339         (value[1] == 'g' || value[1] == 'G')) {
00340       value += 2; scale = "M";
00341     }
00342     break;
00343   case 'k': case 'K':
00344     value++; scale = "k"; break;
00345   case 'u': case 'U':
00346     value++; scale = "u"; break;
00347   case 'n': case 'N':
00348     value++; scale = "n"; break;
00349   case 'p': case 'P':
00350     value++; scale = "p"; break;
00351   case 'f': case 'F':
00352     value++; scale = "f"; break;
00353   }
00354   *endptr = value;
00355   return scale;
00356 }
00357 
00358 /* This little function takes the given string value, converts it into
00359    an appropriate real value and save optional scale and unit. */
00360 static struct value_t * spice_create_value (const char * ident) {
00361   struct value_t * val;
00362   char * end;
00363   const char  * str;
00364   double value = 1.0;
00365   val = create_value ();
00366   val->value = strtod (ident, &end);
00367   if (*end) {
00368     str = spice_evaluate_scale (end, &end, &value);
00369     val->value *= value;
00370     val->scale = str ? strdup (str) : NULL;
00371     if (*end) val->unit = strdup (end);
00372   }
00373   return val;
00374 }
00375 
00376 /* The function identifies key/value pairs in the value list of the
00377    given definition and saves these into an appropriate list. */
00378 static struct pair_t * spice_get_pairs (struct definition_t * def) {
00379   struct value_t * val;
00380   struct pair_t * p, * root = NULL;
00381   struct property_t * prop;
00382   int i = 0;
00383 
00384   // if there is a value given and no description (key), it is required
00385   foreach_value (def->values, val) {
00386     prop = &def->define->required[i];
00387     // a float given ?
00388     if (val->hint & HINT_NUMBER && prop->key) {
00389       p = create_pair ();
00390       p->key = strdup (prop->key);
00391       p->value = spice_create_value (val->ident);
00392       p->next = root;
00393       root = p;
00394       spice_value_done (val);
00395       i++;
00396     }
00397     // skip identifier if next is a float again (F and H sources)
00398     else if ((def->type[0] == 'F' || def->type[0] == 'H') &&
00399              strcasecmp (val->ident, "POLY") &&
00400              val->hint & HINT_NAME &&
00401              val->next && val->next->hint & HINT_NUMBER)
00402       continue;
00403     // break it here
00404     else
00405       break;
00406   }
00407   // other key/value pairs on that line
00408   foreach_value (def->values, val) {
00409     if (val->hint & HINT_PAIR) {
00410       p = create_pair ();
00411       p->key = strdup (val->ident);
00412       p->value = spice_create_value (val->unit);
00413       p->next = root;
00414       root = p;
00415       spice_value_done (val);
00416     }
00417   }
00418   return netlist_reverse_pairs (root);
00419 }
00420 
00421 /* The function goes through the list of definitions and tries to find
00422    the given device model.  It returns NULL if there is no such
00423    model. */
00424 static struct definition_t *
00425 spice_find_device (struct definition_t * root, char * type) {
00426   for (struct definition_t * def = root; def != NULL; def = def->next) {
00427     if (def->action && !strcasecmp (def->type, "MODEL") &&
00428         !strcasecmp (def->instance, type)) {
00429       return def;
00430     }
00431   }
00432   return NULL;
00433 }
00434 
00435 /* Looks for the first possible .MODEL or any other device reference
00436    instance name in the given list.  Returns NULL if there is no such
00437    thing. */
00438 static struct value_t *
00439 spice_find_device_instance (struct definition_t * def) {
00440   struct value_t * val;
00441   foreach_value (def->values, val) {
00442     if (val->hint & HINT_NAME) return val;
00443   }
00444   return NULL;
00445 }
00446 
00447 // Little helper structure for device translations.
00448 struct spice_device_t {
00449   const char * type;            // Spice type
00450   const char * trans_type;      // Qucs type
00451   const char * trans_type_prop; // value of 'Type' in Qucs
00452 }
00453 spice_devices[] = {
00454   { "NPN",     "BJT",    "npn"  },
00455   { "PNP",     "BJT",    "pnp"  },
00456   { "NJF",     "JFET",   "nfet" },
00457   { "PJF",     "JFET",   "pfet" },
00458   { "NMOS",    "MOSFET", "nfet" },
00459   { "PMOS",    "MOSFET", "pfet" },
00460   { "D",       "Diode",  NULL   },
00461   { "SW",      "Relais", NULL   },
00462   { "VSWITCH", "Relais", NULL   },
00463   { "RES",     "R",      NULL   },
00464   { "R",       "R",      NULL   },
00465   { "C",       "C",      NULL   },
00466   { NULL, NULL, NULL }
00467 };
00468 
00469 /* The function goes through the given value list and creates an
00470    appropriate list of key/value pairs stored inside .MODEL
00471    specifications. */
00472 static struct pair_t * spice_generate_Model_pairs (struct value_t * values) {
00473   struct pair_t * root = NULL;
00474   struct value_t * val;
00475   foreach_value (values, val) {
00476     if (val->hint & HINT_PAIR) {
00477       struct pair_t * p = create_pair ();
00478       p->key = strdup (val->ident);
00479       p->value = spice_create_value (val->unit);
00480       p->next = root;
00481       root = p;
00482       if (val->hint & HINT_MSTOP) break;
00483     }
00484     else break;
00485   }
00486   return netlist_reverse_pairs (root);
00487 }
00488 
00489 /* The function goes through the property list of the given definition
00490    and checks whether there is the given property stored.  It returns
00491    NULL if not. */
00492 static struct pair_t *
00493 spice_find_property (struct definition_t * def, const char * prop) {
00494   struct pair_t * pair;
00495   for (pair = def->pairs; pair != NULL; pair = pair->next) {
00496     if (!strcmp (pair->key, prop))
00497       return pair;
00498   }
00499   return NULL;
00500 }
00501 
00502 /* This function is the case-insensitive version of the above. */
00503 static struct pair_t *
00504 spice_find_property_nocase (struct definition_t * def, const char * prop) {
00505   struct pair_t * pair;
00506   for (pair = def->pairs; pair != NULL; pair = pair->next) {
00507     if (!strcasecmp (pair->key, prop))
00508       return pair;
00509   }
00510   return NULL;
00511 }
00512 
00513 /* The function starts at a given property pair and is otherwise
00514    similar to the above function. */
00515 static struct pair_t *
00516 spice_find_property_nocase (struct pair_t * pair, const char * prop) {
00517   for (; pair != NULL; pair = pair->next) {
00518     if (!strcasecmp (pair->key, prop))
00519       return pair;
00520   }
00521   return NULL;
00522 }
00523 
00524 /* This function looks whether the given property name is stored
00525    within the given list of values and returns it.  If there is no
00526    such name, then it returns NULL. */
00527 static struct value_t *
00528 spice_find_property (struct value_t * values, const char * prop) {
00529   struct value_t * val;
00530   foreach_value (values, val) {
00531     if (!strcasecmp (prop, val->ident)) return val;
00532   }
00533   return NULL;
00534 }
00535 
00536 /* The function replaces or appends the given key/value pair to the
00537    list of properties of the given definition. */
00538 static void
00539 spice_set_property_string (struct definition_t * def, const char * key,
00540                            const char * val) {
00541   struct pair_t * prop = spice_find_property (def, key);
00542   if (prop != NULL) {
00543     free (prop->value->ident);
00544     prop->value->ident = strdup (val);
00545   }
00546   else {
00547     prop = create_pair ();
00548     prop->key = strdup (key);
00549     prop->value = create_value ();
00550     prop->value->ident = strdup (val);
00551     def->pairs = netlist_append_pairs (prop, def->pairs);
00552   }
00553 }
00554 
00555 /* This function evaluates the already translated value (translated
00556    scale value) and returns the actual value leaving it untouched. */
00557 static double spice_evaluate_value (struct value_t * value) {
00558   double val = value->value, factor = 1.0;
00559   if (value->scale != NULL) {
00560     switch (*(value->scale)) {
00561     case 'T': factor = 1e12;  break;
00562     case 'G': factor = 1e9;   break;
00563     case 'M': factor = 1e6;   break;
00564     case 'k': factor = 1e3;   break;
00565     case 'm': factor = 1e-3;  break;
00566     case 'u': factor = 1e-6;  break;
00567     case 'n': factor = 1e-9;  break;
00568     case 'p': factor = 1e-12; break;
00569     case 'f': factor = 1e-15; break;
00570     }
00571   }
00572   return val * factor;
00573 }
00574 
00575 /* The following function free()'s the given value. */
00576 static void netlist_free_value (struct value_t * value) {
00577   free (value->ident);
00578   if (value->unit)  free (value->unit);
00579   free (value->scale);
00580   free (value);
00581 }
00582 
00583 /* Deletes the given value list. */
00584 static void netlist_free_values (struct value_t * value) {
00585   struct value_t * next;
00586   for (; value != NULL; value = next) {
00587     next = value->next;
00588     netlist_free_value (value);
00589   }
00590 }
00591 
00592 /* Deletes the given key/value pair. */
00593 void netlist_free_pair (struct pair_t * pair) {
00594   if (pair->value) netlist_free_values (pair->value);
00595   free (pair->key);
00596   free (pair);
00597 }
00598 
00599 /* Unchains a property pair and deletes it. */
00600 struct pair_t *
00601 spice_del_property (struct pair_t * root, struct pair_t * pair) {
00602   struct pair_t * prev;
00603   if (pair == root) {
00604     root = pair->next;
00605     netlist_free_pair (pair);
00606   }
00607   else {
00608     // find previous to the candidate to be deleted
00609     for (prev = root; prev != NULL && prev->next != pair; prev = prev->next) ;
00610     if (prev != NULL) {
00611       prev->next = pair->next;
00612       netlist_free_pair (pair);
00613     }
00614   }
00615   return root;
00616 }
00617 
00618 /* This function adjusts the given device instance definition using
00619    the the given device definition. */
00620 static void spice_adjust_device (struct definition_t * def,
00621                                  struct definition_t * trandef) {
00622 
00623   // first find the starting point of the definition
00624   struct value_t * val, * start = NULL;
00625   foreach_value (trandef->values, val) {
00626     if (val->hint & HINT_MSTART) { start = val; break; }
00627   }
00628   if (start == NULL) {
00629     foreach_value (trandef->values, val) {
00630       if (val->hint & HINT_NAME) { start = val; break; }
00631     }
00632   }
00633 
00634   // second: look for an appropriate available translation
00635   struct spice_device_t * tran;
00636   for (tran = spice_devices; tran->type; tran++) {
00637     if (!strcasecmp (tran->type, start->ident)) {
00638       struct pair_t * p;
00639       // append properties
00640       p = spice_generate_Model_pairs (start->next);
00641       def->pairs = netlist_append_pairs (def->pairs, p);
00642       // adjust type of device
00643       free (def->type);
00644 
00645       bool hic = false;
00646       // check for HICUM transistors
00647       if (!strcmp (tran->trans_type, "BJT")) {
00648         struct pair_t * p1, * p2;
00649         if ((p1 = spice_find_property (def, "LEVEL")) != NULL) {
00650           double level = spice_evaluate_value (p1->value);
00651           def->pairs = spice_del_property (def->pairs, p1);
00652           if ((p2 = spice_find_property (def, "VERSION")) != NULL) {
00653             double version = spice_evaluate_value (p2->value);
00654             def->pairs = spice_del_property (def->pairs, p2);
00655             if (level == 0) {
00656               if (version >= 1.11) {
00657                 if (version >= 1.2e9)
00658                   def->type = strdup ("hicumL0V1p2g");
00659                 else if (version >= 1.3)
00660                   def->type = strdup ("hicumL0V1p3");
00661                 else if (version >= 1.2)
00662                   def->type = strdup ("hicumL0V1p2");
00663                 else
00664                   def->type = strdup ("hic0_full");
00665                 if (tran->trans_type_prop != NULL) {
00666                   spice_set_property_string (def, "Type",
00667                                              tran->trans_type_prop);
00668                 }
00669                 hic = true;
00670               }
00671             }
00672             else if (level == 2 && version == 2.1) {
00673               def->type = strdup ("hicumL2V2p1");
00674               hic = true;
00675             }
00676             else if (level == 2 && version >= 2.21 && version <= 2.22) {
00677               def->type = strdup ("hic2_full");
00678               hic = true;
00679             }
00680             else if (level == 2 && version == 2.23) {
00681               def->type = strdup ("hicumL2V2p23");
00682               hic = true;
00683             }
00684             else if (level == 2 && version >= 2.24) {
00685               def->type = strdup ("hicumL2V2p24");
00686               hic = true;
00687             }
00688           }
00689         }
00690       }
00691       if (!hic) {
00692         def->type = strdup (tran->trans_type);
00693         // append "Type" property
00694         if (tran->trans_type_prop != NULL) {
00695           spice_set_property_string (def, "Type", tran->trans_type_prop);
00696         }
00697       }
00698       break;
00699     }
00700   }
00701 }
00702 
00703 /* The function translates .MODEL specifications in device (MOSFET,
00704    BJT, etc.)  instances. */
00705 static void spice_translate_device (struct definition_t * root,
00706                                     struct definition_t * def) {
00707   struct value_t * inst = spice_find_device_instance (def);
00708 
00709   // return if no Model given
00710   if (inst == NULL) return;
00711 
00712   /* first look for the Model in the local definition root, then in
00713      the global definition root */
00714   struct definition_t * tran;
00715   if ((tran = spice_find_device (root, inst->ident)) == NULL)
00716     tran = spice_find_device (definition_root, inst->ident);
00717   // really translate the instance here
00718   if (tran != NULL) {
00719     spice_value_done (inst);
00720     spice_adjust_device (def, tran);
00721   }
00722   else if (!strcasecmp (def->type, "C")) {
00723     // can probably be skipped
00724   }
00725   else {
00726     fprintf (stderr, "spice error, no such .MODEL `%s' found as specified in "
00727              "device instance `%s'\n", inst->ident, def->instance);
00728     spice_errors++;
00729   }
00730 }
00731 
00732 /* Goes through the list of available definition and returns the
00733    appropriate component definition. */
00734 static struct define_t *
00735 spice_get_qucs_definition (struct definition_t * def) {
00736   struct define_t * entry;
00737   for (entry = qucs_definition_available; entry->type != NULL; entry++)
00738     if (!strcmp (entry->type, def->type)) return entry;
00739   return NULL;
00740 }
00741 
00742 // Helper structure for direct type translations.
00743 struct spice_device_table_t {
00744   const char * type;  // Spice type
00745   const char * trans; // Qucs type
00746 }
00747 spice_device_table[] = {
00748   { "Q", "BJT"    },
00749   { "J", "JFET",  },
00750   { "M", "MOSFET" },
00751   { "D", "Diode"  },
00752   { "V", "Vdc"    },
00753   { "I", "Idc"    },
00754   { "G", "VCCS"   },
00755   { "E", "VCVS"   },
00756   { "F", "CCCS"   },
00757   { "H", "CCVS"   },
00758   { "K", "Tr"     },
00759   { "S", "Relais" },
00760   { "T", "TLIN4P" },
00761   { NULL, NULL }
00762 };
00763 
00764 /* This little function translates the Spice type definitions into Qucs
00765    types. */
00766 static int spice_translate_type (struct definition_t * def) {
00767   struct spice_device_table_t * tran;
00768   int found = 0;
00769   for (tran = spice_device_table; tran->type && def->type; tran++) {
00770     found = 1;
00771     if (!strcasecmp (tran->type, def->type)) {
00772       if (!spice_find_property (def->values, "POLY")) {
00773         free (def->type);
00774         def->type = strdup (tran->trans);
00775         found++;
00776         break;
00777       }
00778     }
00779   }
00780   return found;
00781 }
00782 
00783 // Helper structure for node translations.
00784 struct node_translation_t {
00785   const char * type;    // the type of definition
00786   int pass;             // pass number when the translation should be performed
00787   int Mapping[6];       // node ordering
00788   int Default[6];       // default nodes
00789 }
00790 node_translations[] = {
00791   { "BJT", 0,
00792     { 2, 1, 3, 4, -1 },
00793     { 1, 2, 3, 0, -1 }
00794   },
00795   { "MOSFET", 0,
00796     { 2, 1, 3, 4, -1 },
00797     { 1, 2, 3, 3, -1 }
00798   },
00799   { "JFET", 0,
00800     { 2, 1, 3, -1 },
00801     { 1, 2, 3, -1 }
00802   },
00803   { "Diode", 0,
00804     { 2, 1, -1 },
00805     { 1, 2, -1 }
00806   },
00807   { "Iac", 0,
00808     { 2, 1, -1 },
00809     { 1, 2, -1 }
00810   },
00811   { "Idc", 0,
00812     { 2, 1, -1 },
00813     { 1, 2, -1 }
00814   },
00815   { "VCCS", 0,
00816     { 3, 1, 2, 4, -1 },
00817     { 1, 2, 3, 4, -1 }
00818   },
00819   { "VCVS", 0,
00820     { 3, 1, 2, 4, -1 },
00821     { 1, 2, 3, 4, -1 }
00822   },
00823   { "CCCS", 1,
00824     { 3, 1, 2, 4, -1 },
00825     { 1, 2, 3, 4, -1 }
00826   },
00827   { "CCVS", 1,
00828     { 3, 1, 2, 4, -1 },
00829     { 1, 2, 3, 4, -1 }
00830   },
00831   { "Tr", 1,
00832     { 3, 1, 2, 4, -1 },
00833     { 1, 2, 3, 4, -1 }
00834   },
00835   { "NodeSet", 1,
00836     { 1, -1 },
00837     { 1, -1 }
00838   },
00839   { "Relais", 0,
00840     { 3, 1, 2, 4, -1 },
00841     { 1, 2, 3, 4, -1 }
00842   },
00843   { "TLIN4P", 0,
00844     { 1, 3, 4, 2, -1 },
00845     { 1, 2, 3, 4, -1 }
00846   },
00847   { NULL, 0, { -1 }, { -1 } }
00848 };
00849 
00850 // Counts the number of nodes stored in the given definition.
00851 static int spice_count_nodes (struct definition_t * def) {
00852   int res = 0;
00853   for (struct node_t * node = def->nodes; node != NULL; node = node->next)
00854     res++;
00855   return res;
00856 }
00857 
00858 // Deletes node list of a definition.
00859 static void netlist_free_nodes (struct node_t * node) {
00860   struct node_t * n;
00861   for (; node != NULL; node = n) {
00862     n = node->next;
00863     free (node->node);
00864     free (node);
00865   }
00866 }
00867 
00868 /* Deletes pair list of a definition. */
00869 static void netlist_free_pairs (struct pair_t * pair) {
00870   struct pair_t * n;
00871   for (; pair != NULL; pair = n) {
00872     n = pair->next;
00873     netlist_free_pair (pair);
00874   }
00875 }
00876 
00877 // The function returns the node specified at the given position.
00878 static struct node_t * spice_get_node (struct definition_t * def, int pos) {
00879   struct node_t * node;
00880   int i;
00881   for (i = 1, node = def->nodes; node != NULL; node = node->next, i++)
00882     if (i == pos) return node;
00883   return NULL;
00884 }
00885 
00886 /* This function transforms the collected node information in the
00887    Spice list into the appropriate Qucs definition. */
00888 static void spice_translate_nodes (struct definition_t * def, int pass) {
00889   struct node_translation_t * nodes;
00890   struct node_t * node;
00891   // find node translator
00892   for (nodes = node_translations; nodes->type != NULL; nodes++)
00893     if (!strcmp (nodes->type, def->type)) break;
00894   if (nodes->type == NULL || pass != nodes->pass) return;
00895 
00896   struct define_t * entry = spice_get_qucs_definition (def);
00897   // adjust the number of nodes and append default nodes
00898   if (entry->nodes > spice_count_nodes (def)) {
00899     for (int n = spice_count_nodes (def); n < entry->nodes; n++) {
00900       node = create_node ();
00901       if (nodes->Default[n] == 0) { // default is the ground node
00902         node->node = strdup (qucs_gnd);
00903       }
00904       else {                        // default is some other node
00905         struct node_t * t = spice_get_node (def, nodes->Default[n]);
00906         if (t != NULL)
00907           node->node = strdup (t->node);
00908         else {
00909           // no node given, occurs in device descriptions
00910           char txt[16];
00911           sprintf (txt, "%s%d", "_node", n);
00912           node->node = strdup (txt);
00913         }
00914       }
00915       def->nodes = netlist_append_nodes (def->nodes, node);
00916     }
00917   }
00918   // remap the node definitions if necessary
00919   struct node_t * root = NULL;
00920   for (int n = entry->nodes - 1; n >= 0; n--) {
00921     struct node_t * t = spice_get_node (def, nodes->Mapping[n]);
00922     node = create_node ();
00923     node->node = strdup (t->node);
00924     node->next = root;
00925     root = node;
00926   }
00927   netlist_free_nodes (def->nodes);
00928   def->nodes = root;
00929 }
00930 
00931 // Helper structure for unit translations.
00932 struct unit_translation_t {
00933   const char * key;
00934   const char * trans;
00935 }
00936 unit_translations[] = {
00937   { "OHM",  "Ohm" },
00938   { "OHMS", "Ohm" },
00939   { "MHO",  "S" },
00940   { "S",    "s" },
00941   { "H",    "H" },
00942   { "F",    "F" },
00943   { "HZ",   "Hz" },
00944   { "V",    "V" },
00945   { "VOLT", "V" },
00946   { "A",    "A" },
00947   { "M",    "m" },
00948   { NULL, NULL }
00949 };
00950 
00951 /* This function tries to figure out units given in the Spice list and
00952    translates these patterns into valid Qucs units. */
00953 static void spice_translate_units (struct definition_t * def) {
00954   for (struct pair_t * pair = def->pairs; pair != NULL; pair = pair->next) {
00955     struct value_t * value = pair->value;
00956     if (value->unit) {
00957       struct unit_translation_t * unit;
00958       int found = 0;
00959       for (unit = unit_translations; unit->key != NULL; unit++) {
00960         if (!strcasecmp (unit->key, value->unit)) {
00961           free (value->unit);
00962           value->unit = strdup (unit->trans);
00963           found++;
00964           break;
00965         }
00966       }
00967       if (!found) { // no such unit found
00968         free (value->unit);
00969         value->unit = NULL;
00970       }
00971     }
00972   }
00973 }
00974 
00975 /* This function appends all the required Qucs properties not given in
00976    the Spice netlist. */
00977 static void spice_adjust_default_properties (struct definition_t * def) {
00978   struct define_t * entry = spice_get_qucs_definition (def);
00979   if (entry == NULL) return;
00980 
00981   // handle required properties only
00982   for (int i = 0; PROP_IS_PROP (entry->required[i]); i++) {
00983     struct property_t * prop = &entry->required[i];
00984     if (spice_find_property (def, prop->key) == NULL) {
00985       struct pair_t * pair = create_pair ();
00986       pair->key = strdup (prop->key);
00987       pair->value = create_value ();
00988       if (PROP_IS_VAL (*prop)) {
00989         pair->value->value = prop->defaultval.d;
00990       }
00991       else {
00992         pair->value->ident = strdup (prop->defaultval.s);
00993       }
00994       def->pairs = netlist_append_pairs (def->pairs, pair);
00995     }
00996   }
00997 }
00998 
00999 /* This function appends the optional Qucs properties not given in the
01000    Spice netlist. */
01001 static void spice_adjust_optional_properties (struct definition_t * def) {
01002   struct define_t * entry = spice_get_qucs_definition (def);
01003   if (entry == NULL) return;
01004 
01005   // handle optional properties if requested
01006   for (int i = 0; PROP_IS_PROP (entry->optional[i]); i++) {
01007     struct property_t * prop = &entry->optional[i];
01008     if (spice_find_property (def, prop->key) == NULL) {
01009       struct pair_t * pair = create_pair ();
01010       pair->key = strdup (prop->key);
01011       pair->value = create_value ();
01012       if (PROP_IS_VAL (*prop)) {
01013         pair->value->value = prop->defaultval.d;
01014       }
01015       else {
01016         pair->value->ident = strdup (prop->defaultval.s);
01017       }
01018       def->pairs = netlist_append_pairs (def->pairs, pair);
01019     }
01020   }
01021 }
01022 
01023 // Helper structure for property translations and aliases in devices.
01024 struct property_translation_t {
01025   const char * type;
01026   const char * key;
01027   const char * trans;
01028 }
01029 property_translations[] = {
01030   /* BJT device */
01031   { NULL, "CCS", "Cjs" },
01032   { NULL, "VA",  "Vaf" },
01033   { NULL, "VB",  "Var" },
01034   { NULL, "IK",  "Ikf" },
01035   { NULL, "PE",  "Vje" },
01036   { NULL, "ME",  "Mje" },
01037   { NULL, "PC",  "Vjc" },
01038   { NULL, "MC",  "Mjc" },
01039   { NULL, "PS",  "Vjs" },
01040   { NULL, "MS",  "Mjs" },
01041   /* MOSFET device */
01042   { NULL, "VTO", "Vt0" },
01043   { NULL, "U0",  "Uo"  },
01044   /* DIODE device */
01045   { NULL, "CJO", "Cj0" },
01046   /* OTHER devices */
01047   { "C",  "IC",  "V"   },
01048   { "L",  "IC",  "I"   },
01049   { NULL, "Z0",  "Z"   },
01050   { "R",  "TC",  "Tc1" },
01051   /* END of list */
01052   { NULL, NULL,  NULL  }
01053 };
01054 
01055 /* The function translates property and aliases of devices in the list
01056    of key/value pairs of the given definition. */
01057 void spice_adjust_alias_properties (struct definition_t * def,
01058                                     struct pair_t * pair) {
01059   struct property_translation_t * prop = property_translations;
01060   for (; prop->key != NULL; prop++) {
01061     if (!prop->type || !strcmp (prop->type, def->type)) {
01062       if (!strcasecmp (prop->key, pair->key)) {
01063         free (pair->key);
01064         pair->key = strdup (prop->trans);
01065       }
01066     }
01067   }
01068 }
01069 
01070 /* The function goes through the pair (property) list of the given
01071    definition and adjusts the spelling of the property keys according
01072    to the Qucs definitions. */
01073 void spice_adjust_properties (struct definition_t * def) {
01074   struct define_t * entry = spice_get_qucs_definition (def);
01075   if (entry) {
01076     struct pair_t * pair;
01077     for (pair = def->pairs; pair != NULL; pair = pair->next) {
01078       int i, found = 0;
01079       // handle required properties
01080       for (i = 0; PROP_IS_PROP (entry->required[i]); i++) {
01081         if (!strcasecmp (entry->required[i].key, pair->key)) {
01082           free (pair->key);
01083           pair->key = strdup (entry->required[i].key);
01084           found++;
01085           break;
01086         }
01087       }
01088       // handle optional properties
01089       for (i = 0; PROP_IS_PROP (entry->optional[i]); i++) {
01090         if (!strcasecmp (entry->optional[i].key, pair->key)) {
01091           free (pair->key);
01092           pair->key = strdup (entry->optional[i].key);
01093           found++;
01094           break;
01095         }
01096       }
01097       // some other direct translations
01098       if (!found) spice_adjust_alias_properties (def, pair);
01099     }
01100   }
01101 }
01102 
01103 /* This function appends the given key/value pair to the given
01104    definition.  If the replace flag is non-zero the pair gets
01105    replaced.  If the replace flag is zero and the pair already exists
01106    nothing is done here. */
01107 static void spice_append_pair (struct definition_t * def, const char * prop,
01108                                const char * value, int replace) {
01109   struct pair_t * p = spice_find_property (def, prop);
01110   if (p != NULL) {
01111     if (replace) {
01112       netlist_free_value (p->value);
01113       p->value = spice_create_value (value);
01114       return;
01115     }
01116     else return;
01117   }
01118   p = create_pair ();
01119   p->key = strdup (prop);
01120   p->value = spice_create_value (value);
01121   def->pairs = netlist_append_pairs (def->pairs, p);
01122 }
01123 
01124 /* The function appends the given node name to the list of nodes of
01125    the given definition. */
01126 static void spice_append_node (struct definition_t * def, char * node) {
01127   struct node_t * n = create_node ();
01128   n->node = strdup (node);
01129   def->nodes = netlist_append_nodes (def->nodes, n);
01130 }
01131 
01132 // Converts the given string into upper case.
01133 static char * spice_toupper (char * str) {
01134   for (unsigned int i = 0; i < strlen (str); i++) {
01135     if (str[i] >= 'a' && str[i] <= 'z') str[i] = toupper (str[i]);
01136   }
01137   return str;
01138 }
01139 
01140 /* The function adjusts the instance name of the given component
01141    definition. */
01142 static void spice_adjust_instance (struct definition_t * def) {
01143   spice_toupper (def->instance);
01144 }
01145 
01146 /* This function is used by the overall netlist translator in order to
01147    fixup the properties, nodes, instance name and property units of
01148    the given definition. */
01149 static void spice_fixup_definition (struct definition_t * def) {
01150   spice_adjust_instance (def);
01151   spice_adjust_properties (def);
01152   spice_translate_nodes (def, 0);
01153   spice_translate_units (def);
01154   spice_adjust_default_properties (def);
01155 }
01156 
01157 /* The function adds the given definition to the list of valid
01158    definitions.  The definition is placed at the beginning of the
01159    list. */
01160 static struct definition_t *
01161 spice_add_definition (struct definition_t * root, struct definition_t * def) {
01162   spice_fixup_definition (def);
01163   def->next = root;
01164   return def;
01165 }
01166 
01167 /* Forward declaration for recursive calls. */
01168 static void netlist_destroy_intern (struct definition_t *);
01169 
01170 /* Deletes a definition and all its content. */
01171 static void
01172 netlist_free_definition (struct definition_t * def) {
01173   netlist_free_nodes (def->nodes);
01174   netlist_free_pairs (def->pairs);
01175   netlist_free_values (def->values);
01176   free (def->subcircuit);
01177   free (def->text);
01178   if (def->sub) netlist_destroy_intern (def->sub);
01179   free (def->type);
01180   free (def->instance);
01181   free (def);
01182 }
01183 
01184 /* The function deletes the given definition list. */
01185 static void netlist_destroy_intern (struct definition_t * root) {
01186   struct definition_t * def, * next;
01187   for (def = root; def != NULL; def = next) {
01188     next = def->next;
01189     netlist_free_definition (def);
01190   }
01191 }
01192 
01193 /* Deletes all available definition lists. */
01194 void spice_destroy (void) {
01195   netlist_destroy_intern (definition_root);
01196   netlist_destroy_intern (device_root);
01197   for (struct definition_t * def = subcircuit_root; def; def = def->next) {
01198     netlist_destroy_intern (def->sub);
01199   }
01200   netlist_destroy_intern (subcircuit_root);
01201   definition_root = subcircuit_root = device_root = NULL;
01202   netlist_free_nodes (spice_nodes);
01203   spice_nodes = NULL;
01204   free (spice_title);
01205   spice_title = NULL;
01206 }
01207 
01208 /* Unchains a definition and deletes it. */
01209 struct definition_t *
01210 spice_del_definition (struct definition_t * root, struct definition_t * def) {
01211   struct definition_t * prev;
01212   if (def == root) {
01213     root = def->next;
01214     netlist_free_definition (def);
01215   }
01216   else {
01217     // find previous to the candidate to be deleted
01218     for (prev = root; prev != NULL && prev->next != def; prev = prev->next) ;
01219     if (prev != NULL) {
01220       prev->next = def->next;
01221       netlist_free_definition (def);
01222     }
01223   }
01224   return root;
01225 }
01226 
01227 /* This function creates an internal node name used during the
01228    conversion process.  The returned string is static and must be
01229    copied by the caller.  Successive calls result in different node
01230    names. */
01231 static char * spice_create_intern_node (void) {
01232   static int intern = 0;
01233   static char txt[32];
01234   sprintf (txt, "_cnet%d", intern++);
01235   return txt;
01236 }
01237 
01238 /* This function places an internal node in between the given
01239    components.  The first node of the 'dn' component becomes the first
01240    node of the 'up' component. */
01241 static void spice_adjust_vsource_nodes (struct definition_t * up,
01242                                         struct definition_t * dn) {
01243   struct node_t * node = spice_get_node (dn, 1);
01244   spice_append_node (up, node->node);
01245   char * inode = spice_create_intern_node ();
01246   spice_append_node (up, inode);
01247   free (node->node);
01248   node->node = strdup (inode);
01249 }
01250 
01251 /* The function copies both of the nodes from the 'right' component
01252    into the 'left' component. */
01253 static void spice_adjust_isource_nodes (struct definition_t * left,
01254                                         struct definition_t * right) {
01255   struct node_t * node;
01256   node = spice_get_node (right, 1);
01257   spice_append_node (left, node->node);
01258   node = spice_get_node (right, 2);
01259   spice_append_node (left, node->node);
01260 }
01261 
01262 /* The function creates a new definition based upon the given
01263    definition.  The type of the new component must be given as
01264    well. */
01265 static struct definition_t *
01266 spice_create_definition (struct definition_t * base, const char * type) {
01267   struct definition_t * res = create_definition ();
01268   res->type = strdup (type);
01269   res->action = PROP_COMPONENT;
01270   res->instance = strdup (base->instance);
01271   res->define = base->define;
01272   return res;
01273 }
01274 
01275 /* The function returns the actual property value stored in the given
01276    definition of the given property.  If there is no such property it
01277    returns 0. */
01278 static double
01279 spice_get_property_value (struct definition_t * def, const char * key) {
01280   struct pair_t * prop = spice_find_property (def, key);
01281   return prop ? spice_evaluate_value (prop->value) : 0;
01282 }
01283 
01284 /* This function replaces or appends the given key/value pair in the
01285    given definition. */
01286 static void
01287 spice_set_property_value (struct definition_t * def, const char * key,
01288                           double val) {
01289   struct pair_t * prop = spice_find_property (def, key);
01290   if (prop != NULL) {
01291     // just replace the key/value pair
01292     if (prop->value->scale) {
01293       free (prop->value->scale);
01294       prop->value->scale = NULL;
01295     }
01296     if (prop->value->unit) {
01297       free (prop->value->unit);
01298       prop->value->unit = NULL;
01299     }
01300     prop->value->value = val;
01301   }
01302   else {
01303     // create key/value pair and append it
01304     prop = create_pair ();
01305     prop->key = strdup (key);
01306     prop->value = create_value ();
01307     prop->value->value = val;
01308     def->pairs = netlist_append_pairs (def->pairs, prop);
01309   }
01310 }
01311 
01312 // Helper structure for property extraction routine.
01313 struct property_field_t {
01314   const char * field[16];
01315 };
01316 
01317 /* The function extracts a list of properties from the given value
01318    list and assign the property names stored in the field extractor
01319    structure.  The extracted properties are saved into the given
01320    definition. */
01321 static void spice_extract_properties (struct definition_t * def,
01322                                       struct value_t * values,
01323                                       struct property_field_t * field) {
01324   int i = 0;
01325   struct value_t * val;
01326   // go through each not yet processed value
01327   foreach_value (values, val) {
01328     if (field->field[i] == NULL) break; // stop at the end
01329     if (val->hint & HINT_NAME) {
01330       spice_set_property_string (def, field->field[i], val->ident);
01331     }
01332     else if (val->hint & (HINT_NODE | HINT_NUMBER)) {
01333       spice_append_pair (def, field->field[i], val->ident, 0);
01334     }
01335     else break;
01336     spice_value_done (val);
01337     if (val->hint & HINT_MSTOP) break; // stop here if necessary
01338     i++;
01339   }
01340 }
01341 
01342 /* This function tries to reproduce a Spice netlist line.  It is used
01343    if no proper translation could be found for the line and is printed
01344    as commentary line then. */
01345 static char * spice_untranslated_text (struct definition_t * def) {
01346   struct value_t * val;
01347   char str[256];
01348   sprintf (str, "%s%s:%s ", def->action ? "." : "", def->type, def->instance);
01349   char * txt = (char *) malloc (strlen (str) + 1);
01350   strcpy (txt, str);
01351   for (val = def->values; val != NULL; val = val->next) {
01352     if (val->hint == HINT_NODE) {
01353       sprintf (str, "%s ", val->ident);
01354     }
01355     else if (val->hint & (HINT_NODE | HINT_NUMBER)) {
01356       sprintf (str, "%s%s ", val->ident, val->hint & HINT_MSTOP ? ")" : "");
01357     }
01358     else if (val->hint & HINT_PAIR) {
01359       sprintf (str, "%s%s=%s%s ", val->hint & HINT_MSTART ? "(" : "",
01360                val->ident, val->unit, val->hint & HINT_MSTOP ? ")" : "");
01361     }
01362     else if (val->hint & HINT_NAME) {
01363       sprintf (str, "%s%s%s%s",
01364                (val->hint & HINT_MSTART) ? " " : "",
01365                val->ident,
01366                ((val->hint & HINT_MSTART) && val->next &&
01367                 (val->next->hint & HINT_MSTOP)) ||
01368                (val->hint & HINT_MSTOP) ? "" : " ",
01369                (val->hint & HINT_MSTART && val->next) ? "(" :
01370                (val->hint & HINT_MSTOP) ? ")" : " ");
01371     }
01372     txt = (char *) realloc (txt, strlen (txt) + strlen (str) + 1);
01373     strcat (txt, str);
01374   }
01375   return spice_toupper (txt);
01376 }
01377 
01378 #define VAL_IS_NUMBER(val) \
01379   ((val) != NULL && \
01380   (val)->hint & (HINT_NUMBER | HINT_NODE) && \
01381   !((val)->hint & HINT_DONE))
01382 
01383 #define VAL_IS_DONE(val) \
01384   ((val) == NULL || (val)->hint & HINT_DONE)
01385 
01386 /* The function counts values in a property list up to a stop
01387    value. */
01388 static int spice_count_real_values (struct value_t * values) {
01389   int ret = 0;
01390   struct value_t * val;
01391   // go through each not yet processed value
01392   foreach_value (values, val) {
01393     if (val->hint & (HINT_NODE | HINT_NUMBER))
01394       ret++;
01395     if (val->hint & HINT_MSTOP) break; // stop here if necessary
01396   }
01397   return ret;
01398 }
01399 
01400 /* This function is the independent source translator.  If necessary
01401    new kinds of sources are created.  This must be done since Qucs has
01402    separate sources for each type of excitation and Spice summarizes
01403    these voltage/current excitations in a single source. */
01404 static struct definition_t *
01405 spice_translate_source (struct definition_t * root,
01406                         struct definition_t * def, char type) {
01407   struct definition_t * ac = NULL, * dc = def, * pulse = NULL, * expo = NULL;
01408   struct value_t * prop;
01409   char * ui = (char *) ((type == 'U') ? "U" : "I");
01410 
01411   // adjust the DC part of the source
01412   if ((prop = spice_find_property (dc->values, "DC")) != NULL) {
01413     spice_value_done (prop);
01414     prop = prop->next;
01415     if (VAL_IS_NUMBER (prop)) {
01416       spice_append_pair (def, ui, prop->ident, 1);
01417       spice_value_done (prop);
01418     }
01419   }
01420   free (dc->type);
01421   dc->type = strdup (type == 'U' ? "Vdc" : "Idc");
01422 
01423   // adjust the sinusoidal part of the source
01424   if ((prop = spice_find_property (dc->values, "SIN")) != NULL) {
01425     ac = spice_create_definition (dc, type == 'U' ? "Vac" : "Iac");
01426     spice_value_done (prop);
01427     prop = prop->next;
01428     if (VAL_IS_NUMBER (prop)) {
01429       // adjust DC offset
01430       nr_double_t off;
01431       off = spice_get_property_value (dc, ui);
01432       spice_append_pair (dc, ui, prop->ident, 1);
01433       off += spice_get_property_value (dc, ui);
01434       spice_set_property_value (dc, ui, off);
01435       spice_value_done (prop);
01436       // extract frequency, phase and theta
01437       prop = prop->next;
01438       struct property_field_t field =
01439       { { ui, "f", "Phase", "Theta", NULL } };
01440       spice_extract_properties (ac, prop, &field);
01441     }
01442     double v, f;
01443     f = spice_get_property_value (ac, "f");
01444     v = spice_get_property_value (ac, "Phase") * f * -360.0;
01445     spice_set_property_value (ac, "Phase", v);
01446     v = spice_get_property_value (ac, "Theta") / f;
01447     spice_set_property_value (ac, "Theta", f > 0 ? v : 0);
01448   }
01449 
01450   // adjust the AC part of the source
01451   if ((prop = spice_find_property (dc->values, "AC")) != NULL) {
01452     char * Mag = NULL, * Phase = NULL;
01453     spice_value_done (prop);
01454     prop = prop->next;
01455     if (VAL_IS_NUMBER (prop)) {
01456       Mag = strdup (prop->ident);
01457       spice_value_done (prop);
01458       prop = prop->next;
01459       if (VAL_IS_NUMBER (prop)) {
01460         Phase = strdup (prop->ident);
01461         spice_value_done (prop);
01462       }
01463     }
01464     if (ac == NULL) {
01465       ac = spice_create_definition (dc, type == 'U' ? "Vac" : "Iac");
01466     }
01467     if (Mag) {
01468       spice_append_pair (ac, ui, Mag, 1);
01469       free (Mag);
01470     }
01471     else {
01472       spice_append_pair (ac, ui, "0", 0);
01473     }
01474     if (Phase) {
01475       spice_append_pair (ac, "Phase", Phase, 1);
01476       free (Phase);
01477     }
01478   }
01479 
01480   // adjust the pulse part of the source
01481   if ((prop = spice_find_property (dc->values, "PULSE")) != NULL) {
01482     pulse = spice_create_definition (dc, type == 'U' ? "Vpulse" : "Ipulse");
01483     spice_value_done (prop);
01484     prop = prop->next;
01485 
01486     // periodic
01487     if (spice_count_real_values (prop) > 6) {
01488       free (pulse->type);
01489       pulse->type = type == 'U' ? strdup ("Vrect") : strdup ("Irect");
01490       double add, off = 0;
01491       if (VAL_IS_NUMBER (prop)) {
01492         add = spice_get_property_value (dc, ui);
01493         spice_append_pair (dc, ui, prop->ident, 1);
01494         off = spice_get_property_value (dc, ui);
01495         add += off;
01496         spice_set_property_value (dc, ui, add);
01497         prop = prop->next;
01498       }
01499       if (VAL_IS_NUMBER (prop)) {
01500         struct property_field_t field =
01501           { { ui, "Td", "Tr", "Tf", "TH", "TL", NULL } };
01502         spice_extract_properties (pulse, prop, &field);
01503       }
01504       double v;
01505       v  = spice_get_property_value (pulse, ui);   // V2
01506       v -= off;
01507       spice_set_property_value (pulse, ui, v);
01508       v  = spice_get_property_value (pulse, "TH"); // PW
01509       v += spice_get_property_value (pulse, "Tr");
01510       spice_set_property_value (pulse, "TH", v);
01511       v  = spice_get_property_value (pulse, "TL"); // PER
01512       v -= spice_get_property_value (pulse, "TH");
01513       spice_set_property_value (pulse, "TL", v);
01514     }
01515     // single pulse
01516     else {
01517       if (VAL_IS_NUMBER (prop)) {
01518         spice_append_pair (pulse, type == 'U' ? "U1" : "I1", prop->ident, 0);
01519         spice_append_pair (dc, ui, "0", 0);
01520         spice_value_done (prop);
01521         prop = prop->next;
01522         struct property_field_t field =
01523           { { type == 'U' ? "U2" : "I2", "T1", "Tr", "Tf", "T2", NULL } };
01524         spice_extract_properties (pulse, prop, &field);
01525       }
01526       double v;
01527       v  = spice_get_property_value (pulse, "T1");
01528       v += spice_get_property_value (pulse, "Tr");
01529       v += spice_get_property_value (pulse, "Tf");
01530       v += spice_get_property_value (pulse, "T2");
01531       spice_set_property_value (pulse, "T2", v);
01532     }
01533   }
01534 
01535   // adjust the exponential part of the source
01536   if ((prop = spice_find_property (dc->values, "EXP")) != NULL) {
01537     expo = spice_create_definition (dc, type == 'U' ? "Vexp" : "Iexp");
01538     spice_value_done (prop);
01539     prop = prop->next;
01540     // extract pulse values, rise and fall constants
01541     struct property_field_t field =
01542       { { type == 'U' ? "U1" : "I1", type == 'U' ? "U2" : "I2", "T1", "Tr",
01543           "T2", "Tf", NULL } };
01544     spice_extract_properties (expo, prop, &field);
01545   }
01546 
01547   // set DC value to zero if necessary
01548   if (spice_find_property (dc, ui) == NULL) {
01549     spice_append_pair (def, ui, "0", 1);
01550   }
01551 
01552   // finally add sources to list of definitions
01553   if (ac) {
01554     if (type == 'U')
01555       spice_adjust_vsource_nodes (ac, dc);
01556     else
01557       spice_adjust_isource_nodes (ac, dc);
01558     root = spice_add_definition (root, ac);
01559   }
01560   if (pulse) {
01561     if (type == 'U')
01562       spice_adjust_vsource_nodes (pulse, ac ? ac : dc);
01563     else
01564       spice_adjust_isource_nodes (pulse, ac ? ac : dc);
01565     root = spice_add_definition (root, pulse);
01566   }
01567   if (expo) {
01568     if (type == 'U')
01569       spice_adjust_vsource_nodes (expo, pulse ? pulse : ac ? ac : dc);
01570     else
01571       spice_adjust_isource_nodes (expo, pulse ? pulse : ac ? ac : dc);
01572     root = spice_add_definition (root, expo);
01573   }
01574   return root;
01575 }
01576 
01577 /* This little function returns a static string containing an instance
01578    name of a parameter sweep.  Successive calls produces different
01579    names. */
01580 static char * spice_create_intern_para (void) {
01581   static int intern = 1;
01582   static char txt[32];
01583   sprintf (txt, "SW%d", intern++);
01584   return txt;
01585 }
01586 
01587 /* The function is used to translate the lin/log10/log8 sweeps into an
01588    appropriate sweep in Qucs.  Depending on the given arguments it
01589    computes the number of points in a sweep and stores the new type of
01590    sweep in the given type variable. */
01591 static int spice_evaluate_points (char ** type, double start, double stop,
01592                                   double points) {
01593   int ret = 1;
01594   if (!strcasecmp (*type, "dec")) {      // logarithmic
01595     ret = (int) ((log10 (stop) - log10 (start)) * points);
01596     free (*type);
01597     *type = strdup ("log");
01598   }
01599   else if (!strcasecmp (*type, "lin")) { // linear
01600     ret = (int) points;
01601     free (*type);
01602     *type = strdup ("lin");
01603   }
01604   else if (!strcasecmp (*type, "oct")) { // octaves
01605     ret = (int) (((log10 (stop) - log10 (start)) / log10 (8.0)) * points);
01606     free (*type);
01607     *type = strdup ("log");
01608   }
01609   return ret;
01610 }
01611 
01612 /* This function creates a new parameter sweep (for DC analysis) and
01613    adjust all properties except the 'Sim' property which must be
01614    assigned after calling this function. */
01615 static struct definition_t * spice_create_para (struct definition_t * base) {
01616   struct property_field_t props =
01617   { { "Param", "Start", "Stop", "Points", NULL } };
01618   struct definition_t * para = create_definition ();
01619 
01620   para->type = strdup ("SW");
01621   para->action = PROP_ACTION;
01622   para->instance = strdup (spice_create_intern_para ());
01623   para->define = base->define;
01624   spice_extract_properties (para, base->values, &props);
01625   spice_set_property_string (para, "Type", "lin");
01626   double v;
01627   v  = spice_get_property_value (para, "Stop");
01628   v -= spice_get_property_value (para, "Start");
01629   v /= spice_get_property_value (para, "Points");
01630   v += 1;
01631   spice_set_property_value (para, "Points", v);
01632 
01633   return para;
01634 }
01635 
01636 /* This little helper returns the number of not yet processed values
01637    in th given value list. */
01638 static int spice_count_values (struct value_t * values) {
01639   int res = 0; struct value_t * val;
01640   foreach_value (values, val) res++;
01641   return res;
01642 }
01643 
01644 /* The function looks through the list of definitions if there is a
01645    component with the given type and instance names and returns it.
01646    Otherwise the function returns NULL. */
01647 static struct definition_t *
01648 spice_find_definition (struct definition_t * root, const char * type,
01649                        char * inst) {
01650   for (struct definition_t * def = root; def != NULL; def = def->next) {
01651     if (!strcasecmp (def->type, type) && !strcasecmp (def->instance, inst))
01652       return def;
01653   }
01654   return NULL;
01655 }
01656 
01657 /* The function looks through the list of definitions if there is a
01658    component with the given type and returns it.  Otherwise the
01659    function returns NULL. */
01660 static struct definition_t *
01661 spice_find_definition (struct definition_t * root, const char * type) {
01662   for (struct definition_t * def = root; def != NULL; def = def->next) {
01663     if (!strcasecmp (def->type, type))
01664       return def;
01665   }
01666   return NULL;
01667 }
01668 
01669 /* The function appends the given key/value pair to the properties of
01670    any definition of the given type. */
01671 static void spice_add_property (struct definition_t * root, const char * type,
01672                                 const char * key, char * value) {
01673   for (struct definition_t * def = root; def != NULL; def = def->next) {
01674     if (!strcmp (def->type, type))
01675       spice_append_pair (def, key, value, 0);
01676   }
01677 }
01678 
01679 /* The following little function removes the value list of the given
01680    definition entirely if all values are marked to be processed. */
01681 static void spice_free_values (struct definition_t * def) {
01682   if (spice_count_values (def->values) <= 0) {
01683     struct value_t * val, * next;
01684     for (val = def->values; val != NULL; val = next) {
01685       next = val->next;
01686       netlist_free_value (val);
01687     }
01688     def->values = NULL;
01689   }
01690 }
01691 
01692 /* Spice node lists. */
01693 struct node_t * spice_nodes = NULL;
01694 
01695 /* Collects the nodes specified in the PLOT and PRINT statement
01696    marking them as potential "external" nodes. */
01697 static void spice_collect_external_nodes (struct definition_t * def) {
01698   struct value_t * val;
01699   foreach_value (def->values, val) {
01700     if (val->hint & HINT_MSTART && val->next && val->ident[0] == 'V') {
01701       struct node_t * n = spice_translate_node (val->next->ident);
01702       if (!qucs_find_node (spice_nodes, n->node)) {
01703         n->next = spice_nodes;
01704         spice_nodes = n;
01705       }
01706       else netlist_free_nodes (n);
01707     }
01708   }
01709 }
01710 
01711 /* This function goes through the list of device descriptions and
01712    checks whether the given model is already in the list.  Returns
01713    NULL if there is no such model. */
01714 static struct definition_t * spice_find_Model (char * instance) {
01715   struct definition_t * dev;
01716   for (dev = device_root; dev; dev = dev->next) {
01717     if (!strcmp (dev->instance, instance))
01718       return dev;
01719   }
01720   return NULL;
01721 }
01722 
01723 /* The function appends a new device model.  It creates the actual
01724    model description and adjusts the nodes and optional/required
01725    properties. */
01726 static struct definition_t * spice_add_Model (struct definition_t * def) {
01727   struct definition_t * Model;
01728   if (strcasecmp (def->type, "MODEL"))
01729     return NULL;
01730   if (spice_find_Model (def->instance))
01731     return NULL;
01732   Model = create_definition ();
01733   Model->action = PROP_COMPONENT;
01734   Model->instance = strdup (def->instance);
01735   Model->define = def->define;
01736   spice_adjust_device (Model, def);
01737   if (spice_translate_type (Model)) {
01738     spice_fixup_definition (Model);
01739     spice_adjust_optional_properties (Model);
01740     Model->next = device_root;
01741     device_root = Model;
01742   }
01743   else {
01744     free (Model->instance);
01745     free (Model);
01746     Model = NULL;
01747   }
01748   return Model;
01749 }
01750 
01751 /* Finds a second coupled inductor definition using the same inductors
01752    as the original one if there is any. */
01753 static struct definition_t *
01754 spice_find_coupled (struct definition_t * root, struct definition_t * coupled,
01755                     const char * type, char * inst) {
01756   for (struct definition_t * def = root; def != NULL; def = def->next) {
01757     if (def != coupled && !strcmp (def->type, type) && !def->action) {
01758       if (VAL_IS_DONE (def->values) || VAL_IS_DONE (def->values->next))
01759         continue;
01760       char * linst1 = def->values->ident;
01761       char * linst2 = def->values->next->ident;
01762       if (!strcasecmp (linst1, inst) || !strcasecmp (linst2, inst))
01763         return def;
01764     }
01765   }
01766   return NULL;
01767 }
01768 
01769 /* Looks for a mutual inductor instance referencing the two given
01770    inductors and returns it. */
01771 static struct definition_t *
01772 spice_find_coupled (struct definition_t * root, const char * type,
01773                     char * inst1, char * inst2) {
01774   for (struct definition_t * def = root; def != NULL; def = def->next) {
01775     if (!strcmp (def->type, type) && !def->action) {
01776       if (VAL_IS_DONE (def->values) || VAL_IS_DONE (def->values->next))
01777         continue;
01778       char * linst1 = def->values->ident;
01779       char * linst2 = def->values->next->ident;
01780       if ((!strcasecmp (linst1, inst1) && !strcasecmp (linst2, inst2)) ||
01781           (!strcasecmp (linst1, inst2) && !strcasecmp (linst2, inst1)))
01782         return def;
01783     }
01784   }
01785   return NULL;
01786 }
01787 
01788 /* Looks for the inductor definition used in a coupled inductor.
01789    Emits an error message if there is no such inductor. */
01790 static struct definition_t *
01791 spice_find_coupled_inductor (struct definition_t * root,
01792                              struct definition_t * def, const char * type,
01793                              char * inst) {
01794   static struct definition_t * target;
01795   target = spice_find_definition (root, type, inst);
01796   if (target == NULL) {
01797     fprintf (stderr, "spice error, no such inductor `%s' found as "
01798              "referenced by %s `%s'\n", inst, def->type, def->instance);
01799     spice_errors++;
01800   }
01801   return target;
01802 }
01803 
01804 // Get the coefficient of coupling.
01805 static struct value_t *
01806 spice_get_value_coupled (struct definition_t * def) {
01807   struct value_t * val = NULL;
01808   foreach_value (def->values, val) {
01809     if (val->hint & HINT_NUMBER) break;
01810   }
01811   return val;
01812 }
01813 
01814 // Generates a coupled inductor instance description.
01815 static char *
01816 spice_coupled_instance (struct definition_t * k1, struct definition_t * k2,
01817                         struct definition_t * k3) {
01818   char * inst = (char *) malloc (strlen (k1->instance) +
01819                                  strlen (k2->instance) +
01820                                  strlen (k3->instance) + 1);
01821   strcpy (inst, k1->instance);
01822   strcat (inst, k2->instance);
01823   strcat (inst, k3->instance);
01824   return inst;
01825 }
01826 
01827 /* Post translation function for coupled inductors. */
01828 static struct definition_t *
01829 spice_translate_coupled (struct definition_t * root,
01830                          struct definition_t * def) {
01831   struct definition_t * target1, * target2, * target3;
01832   char * linst1 = def->values->ident;       // get inductivity 1
01833   char * linst2 = def->values->next->ident; // get inductivity 2
01834   nr_double_t l1, l2, l3, k, t;
01835   char * n1, * n2, * n3, * n4;
01836   struct node_t * nn;
01837 
01838   // initialize local variables
01839   n1 = n2 = n3 = n4 = NULL;
01840   l1 = l2 = l3 = k = t = 0;
01841 
01842   // find and handle inductivity 1
01843   target1 = spice_find_coupled_inductor (root, def, "L", linst1);
01844 
01845   // find and handle inductivity 2
01846   target2 = spice_find_coupled_inductor (root, def, "L", linst2);
01847 
01848   // if both inductors found
01849   if (!target1 || !target2) return root;
01850 
01851   l1 = spice_get_property_value (target1, "L");
01852   l2 = spice_get_property_value (target2, "L");
01853 
01854   // check three inductors
01855   struct definition_t * k1 = def, * k2, * k3;
01856   char * k12, * k13, * k23;
01857   k2 = spice_find_coupled (root, k1, "Tr", linst1);
01858   k3 = spice_find_coupled (root, k1, "Tr", linst2);
01859 
01860   // handle three inductors
01861   if (k2 != NULL && k3 != NULL) {
01862     char * linst3, * linst4;
01863     if (!strcasecmp (k2->values->ident, linst1))
01864       linst3 = k2->values->next->ident;
01865     else
01866       linst3 = k2->values->ident;
01867     if (!strcasecmp (k3->values->ident, linst2))
01868       linst4 = k3->values->next->ident;
01869     else
01870       linst4 = k3->values->ident;
01871     spice_value_done (k1->values);
01872     spice_value_done (k1->values->next);
01873 
01874     if (strcasecmp (linst3, linst4)) {
01875       fprintf (stderr, "spice error, cannot translate coupled inductors "
01876                "`%s' and `%s'\n", linst3, linst4);
01877       spice_errors++;
01878     }
01879     else if (k2 != k3) {
01880       // find and handle inductivity 3
01881       target3 = spice_find_coupled_inductor (root, k2, "L", linst3);
01882       if (target3 != NULL) {
01883         // construct three mutual inductors
01884         struct value_t * val;
01885         char * inst = spice_coupled_instance (k1, k2, k3);
01886         free (k1->type); k1->type = strdup ("MUT2");
01887         free (k1->instance); k1->instance = inst;
01888         netlist_free_pairs (k1->pairs); k1->pairs = NULL;
01889         spice_value_done (k2->values);
01890         spice_value_done (k2->values->next);
01891         spice_value_done (k3->values);
01892         spice_value_done (k3->values->next);
01893         spice_append_node (k1, spice_get_node(target1, 1)->node);
01894         spice_append_node (k1, spice_get_node(target3, 1)->node);
01895         spice_append_node (k1, spice_get_node(target3, 2)->node);
01896         spice_append_node (k1, spice_get_node(target2, 2)->node);
01897         spice_append_node (k1, spice_get_node(target2, 1)->node);
01898         spice_append_node (k1, spice_get_node(target1, 2)->node);
01899         l3 = spice_get_property_value (target3, "L");
01900         spice_set_property_value (k1, "L1", l1);
01901         spice_set_property_value (k1, "L2", l2);
01902         spice_set_property_value (k1, "L3", l3);
01903         if ((val = spice_get_value_coupled (k1)) != NULL) {
01904           k12 = val->ident;
01905           spice_append_pair (k1, "k12", k12, 0);
01906           spice_value_done (val);
01907         }
01908         if ((val = spice_get_value_coupled (k2)) != NULL) {
01909           k13 = val->ident;
01910           spice_append_pair (k1, "k13", k13, 0);
01911           spice_value_done (val);
01912         }
01913         if ((val = spice_get_value_coupled (k3)) != NULL) {
01914           k23 = val->ident;
01915           spice_append_pair (k1, "k23", k23, 0);
01916           spice_value_done (val);
01917         }
01918         root = spice_del_definition (root, target1);
01919         root = spice_del_definition (root, target2);
01920         root = spice_del_definition (root, target3);
01921         root = spice_del_definition (root, k2);
01922         root = spice_del_definition (root, k3);
01923         return root;
01924       }
01925     }
01926   }
01927 
01928   spice_value_done (def->values);
01929   spice_value_done (def->values->next);
01930 
01931   // node replacer 1
01932   nn = spice_get_node (target1, 2);
01933   n4 = nn->node;
01934   nn->node = strdup (spice_create_intern_node ());
01935   n1 = strdup (nn->node);
01936 
01937   // node replacer 2
01938   nn = spice_get_node (target2, 2);
01939   n3 = nn->node;
01940   nn->node = strdup (spice_create_intern_node ());
01941   n2 = strdup (nn->node);
01942 
01943   // get the coefficient of coupling
01944   struct value_t * val;
01945   spice_append_pair (def, "T", "1", 1);
01946   if ((val = spice_get_value_coupled (def)) != NULL) {
01947     spice_append_pair (def, "T", val->ident, 1);
01948     spice_value_done (val);
01949   }
01950 
01951   // apply the turns ratio of the transformer and its nodes
01952   k = spice_get_property_value (def, "T");
01953   t = sqrt (l1 / l2);
01954   spice_set_property_value (def, "T", t);
01955   spice_append_node (def, n1);
01956   spice_append_node (def, n2);
01957   spice_append_node (def, n3);
01958   spice_append_node (def, n4);
01959   // adapt inductivities of original inductors
01960   spice_set_property_value (target1, "L", l1 - k * l1);
01961   spice_set_property_value (target2, "L", l2 - k * l1 / t / t);
01962   // insert the actual mutual inductance if necessary
01963   if (k > 0) {
01964     struct definition_t * Mind = spice_create_definition (def, "L");
01965     spice_append_node (Mind, n1);
01966     spice_append_node (Mind, n4);
01967     spice_set_property_value (Mind, "L", k * l1);
01968     root = spice_add_definition (root, Mind);
01969   }
01970   free (n1); free (n2); free (n3); free (n4);
01971   return root;
01972 }
01973 
01974 /* Finds an additional mutual inductor definition using the same
01975    inductors as the original one if there is any. */
01976 static struct definition_t *
01977 spice_find_coupled (struct definition_t * root,
01978                     qucs::hash<struct definition_t> * coupled,
01979                     const char * type, char * inst) {
01980   for (struct definition_t * def = root; def != NULL; def = def->next) {
01981     if (!strcmp (def->type, type) && !def->action) {
01982       if (VAL_IS_DONE (def->values) || VAL_IS_DONE (def->values->next))
01983         continue;
01984       if (!coupled->get (def->instance)) {
01985         char * linst1 = def->values->ident;
01986         char * linst2 = def->values->next->ident;
01987         if (!strcasecmp (linst1, inst) || !strcasecmp (linst2, inst))
01988           return def;
01989       }
01990     }
01991   }
01992   return NULL;
01993 }
01994 
01995 /* Looks recursively for mutual inductors.  In the end the two hash
01996    maps contain all the inductors coupled by those mutual inductors in
01997    the other hash map. */
01998 static struct definition_t *
01999 spice_search_coupled (struct definition_t * root,
02000                       qucs::hash<struct definition_t> * K_hash,
02001                       qucs::hash<struct definition_t> * L_hash,
02002                       const char * type, char * inst) {
02003   char * linst;
02004   struct definition_t * l, * k;
02005 
02006   // find mutual inductors referencing the given inductor instance
02007   while ((k = spice_find_coupled (root, K_hash, type, inst)) != NULL) {
02008     // already had this one?
02009     if (K_hash->get (k->instance))
02010       continue;
02011     K_hash->put (k->instance, k);
02012 
02013     // first referenced inductor
02014     linst = k->values->ident;
02015     if (!L_hash->get (linst)) {
02016       if ((l = spice_find_coupled_inductor (root, k, "L", linst)) != NULL) {
02017         L_hash->put (linst, l);
02018         // recurse
02019         root = spice_search_coupled (root, K_hash, L_hash, type, linst);
02020       }
02021     }
02022 
02023     // second referenced inductor
02024     linst = k->values->next->ident;
02025     if (!L_hash->get (linst)) {
02026       if ((l = spice_find_coupled_inductor (root, k, "L", linst)) != NULL) {
02027         L_hash->put (linst, l);
02028         // recurse
02029         root = spice_search_coupled (root, K_hash, L_hash, type, linst);
02030       }
02031     }
02032   }
02033   return root;
02034 }
02035 
02036 /* Post translation function for multiple coupled inductors. */
02037 static struct definition_t *
02038 spice_translate_coupled_x (struct definition_t * root,
02039                            struct definition_t * def) {
02040   char * linst1, * linst2;
02041   qucs::hash<struct definition_t> K_hash;
02042   qucs::hash<struct definition_t> L_hash;
02043   qucs::hashiterator<struct definition_t> it;
02044   struct definition_t * l;
02045 
02046   // save first 2 referenced inductors and the mutual inductor
02047   linst1 = def->values->ident;
02048   if ((l = spice_find_coupled_inductor (root, def, "L", linst1)) != NULL)
02049     L_hash.put (linst1, l);
02050   linst2 = def->values->next->ident;
02051   if ((l = spice_find_coupled_inductor (root, def, "L", linst2)) != NULL)
02052     L_hash.put (linst2, l);
02053   K_hash.put (def->instance, def);
02054 
02055   // look for more mutual inductors involving the first 2 inductors
02056   root = spice_search_coupled (root, &K_hash, &L_hash, "Tr", linst1);
02057   root = spice_search_coupled (root, &K_hash, &L_hash, "Tr", linst2);
02058 
02059   // create coupling coefficient matrix
02060   int i, o, s = L_hash.count ();
02061   nr_double_t * kval = new nr_double_t[s * s];
02062   struct definition_t * k;
02063   struct value_t * val;
02064   qucs::hashiterator<struct definition_t> iti, ito;
02065   // outer loop
02066   for (ito = qucs::hashiterator<struct definition_t> (L_hash), o = 0;
02067        *ito; ++ito, ++o) {
02068     // inner loop
02069     for (iti = qucs::hashiterator<struct definition_t> (L_hash), i = 0;
02070          *iti; ++iti, ++i) {
02071       if (i > o) {
02072         // cross-coupling coefficients
02073         nr_double_t kvalue = 0;
02074         k = spice_find_coupled (root, "Tr",
02075                                 iti.currentKey (), ito.currentKey ());
02076         if (k != NULL) {
02077           if ((val = spice_get_value_coupled (k)) != NULL) {
02078             kvalue = spice_evaluate_value (val);
02079           }
02080         }
02081         kval[s * o + i] = kvalue;
02082         kval[s * i + o] = kvalue;
02083       }
02084       else if (i == o) {
02085         // self-coupling coefficient
02086         kval[s * o + i] = 1;
02087       }
02088     }
02089   }
02090 
02091   spice_value_done (def->values);
02092   spice_value_done (def->values->next);
02093 
02094   // adjust MUTX instance
02095   free (def->type); def->type = strdup ("MUTX");
02096   netlist_free_pairs (def->pairs); def->pairs = NULL;
02097 
02098   // create L property vector
02099   struct pair_t * pair = create_pair ();
02100   pair->key = strdup ("L");
02101   def->pairs = netlist_append_pairs (def->pairs, pair);
02102   for (it = qucs::hashiterator<struct definition_t> (L_hash); *it; ++it) {
02103     spice_append_node (def, spice_get_node(it.currentVal (), 1)->node);
02104     spice_append_node (def, spice_get_node(it.currentVal (), 2)->node);
02105     val = create_value ();
02106     val->value = spice_get_property_value (it.currentVal (), "L");
02107     pair->value = netlist_append_values (pair->value, val);
02108     root = spice_del_definition (root, it.currentVal ());
02109   }
02110 
02111   // create k property vector
02112   pair = create_pair ();
02113   pair->key = strdup ("k");
02114   def->pairs = netlist_append_pairs (def->pairs, pair);
02115   for (i = 0; i < s * s; i++) {
02116     val = create_value ();
02117     val->value = kval[i];
02118     pair->value = netlist_append_values (pair->value, val);
02119   }
02120 
02121   // remove remaining coupled inductors from definition list
02122   for (it = qucs::hashiterator<struct definition_t> (K_hash); *it; ++it) {
02123     if (def != it.currentVal ()) {
02124       root = spice_del_definition (root, it.currentVal ());
02125     }
02126   }
02127 
02128   delete[] kval;
02129   return root;
02130 }
02131 
02132 /* Contructs an edd equation name. */
02133 static char *
02134 spice_create_eqnstr (struct definition_t * def, int p, char type) {
02135   char * n = (char *) malloc (strlen (def->instance) + 4 + 3);
02136   sprintf (n, "%s.%c%d", def->instance, type, p);
02137   return n;
02138 }
02139 
02140 /* The function adds edd equation properties to the given netlist
02141    definition and also adds the appropriate equation instances. */
02142 static struct definition_t *
02143 spice_add_edd_equation (struct definition_t * root,
02144                         struct definition_t * def, int p,
02145                         struct definition_t ** i, struct definition_t ** q) {
02146   struct definition_t * ieqn, * qeqn;
02147   char I_[4], Q_[4];
02148   char * ieq = spice_create_eqnstr (def, p, 'I');
02149   char * qeq = spice_create_eqnstr (def, p, 'Q');
02150   sprintf (I_, "I%d", p);
02151   sprintf (Q_, "Q%d", p);
02152   spice_set_property_string (def, Q_, qeq);
02153   spice_set_property_string (def, I_, ieq);
02154   ieqn = spice_create_definition (def, "Eqn");
02155   qeqn = spice_create_definition (def, "Eqn");
02156   spice_set_property_string (ieqn, "Export", "no");
02157   spice_set_property_string (qeqn, "Export", "no");
02158   spice_set_property_string (ieqn, ieq, "0");
02159   spice_set_property_string (qeqn, qeq, "0");
02160   root = spice_add_definition (root, qeqn);
02161   root = spice_add_definition (root, ieqn);
02162   sprintf (ieq, "Eqn%sI%d", def->instance, p);
02163   sprintf (qeq, "Eqn%sQ%d", def->instance, p);
02164   free (ieqn->instance);
02165   free (qeqn->instance);
02166   qeqn->instance = strdup (qeq);
02167   ieqn->instance = strdup (ieq);
02168   free (ieq);
02169   free (qeq);
02170   if (i) (*i) = ieqn;
02171   if (q) (*q) = qeqn;
02172   return root;
02173 }
02174 
02175 /* Since there no or little documentation about the polynom orders in
02176    the SPICE2G6 'POLY' statements the following piece of code is a
02177    straight re-implementation of the Fortran code in SPICE2G6. */
02178 static void spice2g6_nxtpwr (int * seq, int nd) {
02179   int i, k, ps;
02180 
02181   // special handling of one-dimensional polynoms
02182   if (nd == 1) {
02183     seq[0]++;
02184     return;
02185   }
02186 
02187   // two and more-dimensional polynoms
02188   k = nd;
02189   do {
02190     if (seq[k - 1] != 0) break;
02191   }
02192   while (--k != 0);
02193 
02194   if (k == 0) {
02195     seq[0]++;
02196   }
02197   else if (k != nd) {
02198     seq[k - 1]--;
02199     seq[k]++;
02200   }
02201   else {
02202     for (i = 0; i < k - 1; i++)
02203       if (seq[i] != 0) break;
02204     if (i == k - 1) {
02205       seq[0] = seq[nd - 1] + 1;
02206       seq[nd-1] = 0;
02207       return;
02208     }
02209     ps = 1;
02210     k = nd - 1;
02211     while (seq[k - 1] < 1) {
02212       ps += seq[k];
02213       seq[k] = 0;
02214       k--;
02215     }
02216     seq[k] += ps;
02217     seq[k - 1]--;
02218   }
02219 }
02220 
02221 /* The function takes the given spice value, converts it into an
02222    appropriate real value and save optional scale and unit and finally
02223    returns the actual value. */
02224 static double spice_get_value (struct value_t * val) {
02225   const char * str;
02226   char * end;
02227   double v;
02228   val->value = strtod (val->ident, &end);
02229   if (*end) {
02230     str = spice_evaluate_scale (end, &end, &v);
02231     val->value *= v;
02232     val->scale = str ? strdup (str) : NULL;
02233     if (*end) val->unit = strdup (end);
02234   }
02235   return val->value;
02236 }
02237 
02238 /* Creates a 'nd' dimensional polynomial expression extracted from the
02239    coefficient list of a value. */
02240 static char *
02241 spice_create_poly (struct value_t * prop, int nd, int integrate) {
02242   struct value_t * val;
02243 
02244   // contruct polynomial expression
02245   int * pn = (int *) calloc (nd, sizeof (int));
02246   static char expr[1024];
02247   char value[256];
02248   strcpy (expr, "");
02249 
02250   // go through spice values
02251   foreach_value (prop, val) {
02252     if (!VAL_IS_NUMBER (val)) break;
02253 
02254     double k = spice_get_value (val);
02255     spice_value_done (val);
02256 
02257     // construct single polynom
02258     if (k != 0.0) {
02259 
02260       // coefficient
02261       sprintf (value, "%+g", k);
02262       strcat (expr, value);
02263 
02264       // remaining polynom
02265       for (int i = 0; i < nd; i++) {
02266         int n = integrate ? i + 1 : i + 2;
02267         int e = integrate ? pn[i] + 2 : pn[i];
02268         switch (e) {
02269         case 0:
02270           strcpy (value, "");
02271           break;
02272         case 1:
02273           sprintf (value, "*V%d", n);
02274           break;
02275         case 2:
02276           sprintf (value, "*V%d*V%d", n, n);
02277           break;
02278         default:
02279           sprintf (value, "*V%d^%d", n, e);
02280           break;
02281         }
02282         strcat (expr, value);
02283 
02284         // coefficient correction
02285         if (integrate && e > 1) {
02286           sprintf (value, "/%d", e);
02287           strcat (expr, value);
02288         }
02289       }
02290     }
02291 
02292     // prepare next polynom
02293     spice2g6_nxtpwr (pn, nd);
02294   }
02295   free (pn);
02296   return expr;
02297 }
02298 
02299 /* Translates E and G poly sources. */
02300 static struct definition_t *
02301 spice_translate_poly (struct definition_t * root, struct definition_t * def) {
02302   struct value_t * prop;
02303   int nd, type = -1;
02304 
02305   // only handle appropriate sources
02306   if (strcasecmp (def->type, "E") && strcasecmp (def->type, "G") &&
02307       strcasecmp (def->type, "F") && strcasecmp (def->type, "H"))
02308     return root;
02309 
02310   // save source type information
02311   if (!strcasecmp (def->type, "E"))
02312     type = 0;
02313   else if (!strcasecmp (def->type, "G"))
02314     type = 1;
02315   else if (!strcasecmp (def->type, "H"))
02316     type = 2;
02317   else if (!strcasecmp (def->type, "F"))
02318     type = 3;
02319 
02320   if ((prop = spice_find_property (def->values, "POLY")) != NULL) {
02321     // retype poly source into EDD
02322     free (def->type);
02323     def->type = strdup ("EDD");
02324     spice_value_done (prop);
02325     // get number of polynomial terms
02326     prop = prop->next;
02327     nd = (int) spice_evaluate_value (prop);
02328     spice_value_done (prop);
02329 
02330     // contruct properties, equations and nodes of the EDD
02331     if (type <= 1) {
02332       // handle E and G voltage controlled sources
02333       prop = prop->next;
02334       for (int i = nd * 2 - 1; i >= 0; i--) {
02335         int p = (i + 1) / 2 + 1;
02336         struct node_t * node = spice_translate_node (prop->ident);
02337         def->nodes = netlist_append_nodes (def->nodes, node);
02338         if (i & 1) root = spice_add_edd_equation (root, def, p, NULL, NULL);
02339         spice_value_done (prop);
02340         prop = prop->next;
02341       }
02342     }
02343     else {
02344       // handle F and H current controlled sources
02345       prop = prop->next;
02346       for (int i = nd; i > 0; i--) {
02347         struct definition_t * vdc, * ibuf;
02348         char * vn, * np, * nn;
02349         int p = i + 1;
02350         // find referenced voltage source (where current flows through)
02351         vn = prop->ident;
02352         vdc = spice_find_definition (root, "Vdc", vn);
02353         if (vdc) {
02354           // create intermediate current controlled voltage source
02355           // passing voltage to an EDD branch
02356           ibuf = spice_create_definition (def, "CCVS");
02357           vn = (char *) malloc (strlen (ibuf->instance) + 3);
02358           sprintf (vn, "%sV%d", ibuf->instance, p);
02359           free (ibuf->instance);
02360           ibuf->instance = vn;
02361           struct node_t * node = spice_get_node (vdc, 1);
02362           np = strdup (spice_create_intern_node ());
02363           nn = strdup (spice_create_intern_node ());
02364           spice_append_node (ibuf, node->node);
02365           free (node->node);
02366           node->node = strdup (nn);
02367           spice_append_node (def, np);
02368           spice_append_node (def, (char *) "gnd");
02369           spice_append_node (ibuf, np);
02370           spice_append_node (ibuf, (char *) "gnd");
02371           spice_append_node (ibuf, nn);
02372           spice_set_property_string (ibuf, "G", "1");
02373           root = spice_add_definition (root, ibuf);
02374           free (nn);
02375           free (np);
02376         }
02377         else {
02378           fprintf (stderr, "spice error, no such voltage source `%s' found as "
02379                    "referenced by the %s `%s' instance\n", def->type,
02380                    def->instance, vn);
02381           spice_errors++;
02382         }
02383         root = spice_add_edd_equation (root, def, p, NULL, NULL);
02384         spice_value_done (prop);
02385         prop = prop->next;
02386       }
02387     }
02388 
02389     // add first (really evaluating) I and Q equations
02390     struct definition_t * ieqn, * qeqn;
02391     root = spice_add_edd_equation (root, def, 1, &ieqn, &qeqn);
02392 
02393     // contruct polynomial expression
02394     char * expr = spice_create_poly (prop, nd, 0);
02395 
02396     // replace first current branch to reflect polynom
02397     char * ieq = spice_create_eqnstr (def, 1, 'I');
02398     spice_set_property_string (ieqn, ieq, expr);
02399     free (ieq);
02400 
02401     // finally add buffering controlled source
02402     struct definition_t * obuf = NULL;
02403     struct node_t * pnode, * nnode;
02404     char * intp;
02405 
02406     if ((type & 1) == 0)
02407       obuf = spice_create_definition (def, "CCVS");
02408     else if ((type & 1) == 1)
02409       obuf = spice_create_definition (def, "CCCS");
02410 
02411     pnode = spice_get_node (def, 1);
02412     nnode = spice_get_node (def, 2);
02413     intp = strdup (spice_create_intern_node ());
02414 
02415     spice_append_node (obuf, intp);
02416     spice_append_node (obuf, nnode->node);
02417     spice_append_node (obuf, pnode->node);
02418     spice_append_node (obuf, (char *) "gnd");
02419 
02420     free (pnode->node);
02421     pnode->node = strdup (intp);
02422     free (nnode->node);
02423     nnode->node = strdup ("gnd");
02424     free (intp);
02425 
02426     spice_set_property_string (obuf, "G", "1");
02427     root = spice_add_definition (root, obuf);
02428   }
02429   return root;
02430 }
02431 
02432 /* Translates non-linear L and C poly definitions. */
02433 static struct definition_t *
02434 spice_translate_poly_lc (struct definition_t * root,
02435                          struct definition_t * def) {
02436   struct value_t * prop;
02437   int type = -1;
02438   double lc = 0.0;
02439 
02440   // save type information
02441   if (!strcasecmp (def->type, "C"))
02442     type = 0;
02443   else if (!strcasecmp (def->type, "L"))
02444     type = 1;
02445 
02446   if ((prop = spice_find_property (def->values, "POLY")) != NULL) {
02447     // retype poly LC into EDD
02448     free (def->type);
02449     def->type = strdup ("EDD");
02450     spice_value_done (prop);
02451 
02452     // get constant L or C value
02453     struct pair_t * p;
02454     if ((p = spice_find_property (def, "C")) != NULL) {
02455       lc = spice_get_property_value (def, "C");
02456       def->pairs = spice_del_property (def->pairs, p);
02457     }
02458     else if ((p = spice_find_property (def, "L")) != NULL) {
02459       lc = spice_get_property_value (def, "L");
02460       def->pairs = spice_del_property (def->pairs, p);
02461     }
02462 
02463     // add I and Q equations
02464     struct definition_t * ieqn, * qeqn;
02465     root = spice_add_edd_equation (root, def, 1, &ieqn, &qeqn);
02466 
02467     // contruct polynomial expression
02468     char * expr1 = strdup (spice_create_poly (prop, 1, 1));
02469     char * expr2 = expr1;
02470     if (lc != 0.0) {
02471       expr2 = (char *) malloc (strlen (expr1) + 256);
02472       sprintf (expr2, "%+g*V1%s", lc, expr1);
02473       free (expr1);
02474     }
02475 
02476     // replace first charge branch to reflect polynom
02477     char * qeq = spice_create_eqnstr (def, 1, 'Q');
02478     spice_set_property_string (qeqn, qeq, expr2);
02479     free (expr2);
02480     free (qeq);
02481 
02482     // finally add converting gyrator if necessary
02483     if (type == 1) {
02484       struct definition_t * gyra = NULL;
02485       struct node_t * pnode, * nnode;
02486       char * intp;
02487 
02488       gyra = spice_create_definition (def, "Gyrator");
02489 
02490       pnode = spice_get_node (def, 1);
02491       nnode = spice_get_node (def, 2);
02492       intp = strdup (spice_create_intern_node ());
02493 
02494       spice_append_node (gyra, intp);
02495       spice_append_node (gyra, nnode->node);
02496       spice_append_node (gyra, pnode->node);
02497       spice_append_node (gyra, (char *) "gnd");
02498 
02499       free (pnode->node);
02500       pnode->node = strdup (intp);
02501       free (nnode->node);
02502       nnode->node = strdup ("gnd");
02503       free (intp);
02504 
02505       spice_set_property_string (gyra, "R", "1");
02506       root = spice_add_definition (root, gyra);
02507     }
02508   }
02509   return root;
02510 }
02511 
02512 /* This function must be called after the actual Spice netlist
02513    translator in order to adjust some references or whatever in the
02514    resulting netlist. */
02515 static struct definition_t *
02516 spice_post_translator (struct definition_t * root) {
02517   for (struct definition_t * def = root; def != NULL; def = def->next) {
02518     // post-process parameter sweep
02519     if (def->action && !strcmp (def->type, "SW")) {
02520       // adjust the actual 'Param' name
02521       struct pair_t * prop = spice_find_property (def, "Param");
02522       char * val = spice_toupper (prop->value->ident);
02523       struct definition_t * target;
02524       // get the target voltage or current source and adjust the property
02525       target = spice_find_definition (root, "Vdc", val);
02526       if (target) {
02527         prop = spice_find_property (target, "U");
02528         prop->value->ident = strdup (val);
02529       }
02530       else {
02531         target = spice_find_definition (root, "Idc", val);
02532         if (target) {
02533           prop = spice_find_property (target, "I");
02534           prop->value->ident = strdup (val);
02535         }
02536         else {
02537           fprintf (stderr, "spice error, no such source `%s' found as "
02538                    "referenced by the .DC analysis\n", val);
02539           spice_errors++;
02540         }
02541       }
02542     }
02543     // post-process current-controlled current/voltage source
02544     if (!def->action && (!strcmp (def->type, "CCCS") ||
02545                          !strcmp (def->type, "CCVS"))) {
02546       struct definition_t * target;
02547       struct value_t * val = spice_find_device_instance (def);
02548       if (val) {
02549         char * key = val->ident;
02550         target = spice_find_definition (root, "Vdc", key);
02551         if (target) {
02552           // adjust the controlling nodes of the source
02553           spice_adjust_vsource_nodes (def, target);
02554           spice_translate_nodes (def, 1);
02555         }
02556         else {
02557           fprintf (stderr, "spice error, no such voltage source `%s' found "
02558                    "as referenced by the %s `%s' instance\n", def->type,
02559                    def->instance, key);
02560           spice_errors++;
02561         }
02562       }
02563     }
02564     // post-process F and H poly sources
02565     if (!def->action && (!strcmp (def->type, "F") ||
02566                          !strcmp (def->type, "H"))) {
02567       root = spice_translate_poly (root, def);
02568     }
02569     // post-process switches
02570     if (!def->action && !strcmp (def->type, "Relais")) {
02571       struct pair_t * pon = spice_find_property_nocase (def, "VON");
02572       struct pair_t * pof = spice_find_property_nocase (def, "VOFF");
02573       if (pon != NULL && pof != NULL) {
02574         nr_double_t von = spice_evaluate_value (pon->value);
02575         nr_double_t vof = spice_evaluate_value (pof->value);
02576         def->pairs = spice_del_property (def->pairs, pon);
02577         def->pairs = spice_del_property (def->pairs, pof);
02578         nr_double_t vh = (von - vof) / 2;
02579         nr_double_t vt = (von + vof) / 2;
02580         spice_set_property_value (def, "Vt", vt);
02581         spice_set_property_value (def, "Vh", fabs (vh));
02582       }
02583     }
02584     // post-process pulse and rectangular sources
02585     if (!def->action && (!strcmp (def->type, "Vpulse") ||
02586                          !strcmp (def->type, "Ipulse") ||
02587                          !strcmp (def->type, "Vrect") ||
02588                          !strcmp (def->type, "Irect"))) {
02589       struct definition_t * tran;
02590       struct pair_t * tr = spice_find_property (def, "Tr");
02591       struct pair_t * tf = spice_find_property (def, "Tf");
02592       if (tr == NULL || tf == NULL) {
02593         if ((tran = spice_find_definition (definition_root, "TR")) != NULL) {
02594           nr_double_t start = spice_get_property_value (tran, "Start");
02595           nr_double_t stop = spice_get_property_value (tran, "Stop");
02596           nr_double_t points = spice_get_property_value (tran, "Points");
02597           nr_double_t tstep = (stop - start) / (points - 1);
02598           nr_double_t add = 0;
02599           if (!tf) {
02600             spice_set_property_value (def, "Tf", tstep);
02601             add += tstep;
02602           }
02603           if (!tr) {
02604             spice_set_property_value (def, "Tr", tstep);
02605             add += tstep;
02606           }
02607           if (!strcmp (&def->type[1], "pulse")) {
02608             nr_double_t t2 = spice_get_property_value (def, "T2");
02609             spice_set_property_value (def, "T2", t2 + add);
02610           }
02611         }
02612       }
02613     }
02614     // post-process sinusoidal sources
02615     if (!def->action && (!strcmp (def->type, "Vac") ||
02616                          !strcmp (def->type, "Iac"))) {
02617       struct definition_t * tran;
02618       struct pair_t * f = spice_find_property (def, "f");
02619       if (f == NULL) {
02620         if ((tran = spice_find_definition (definition_root, "TR")) != NULL) {
02621           nr_double_t stop = spice_get_property_value (tran, "Stop");
02622           spice_set_property_value (def, "f", 1 / stop);
02623         }
02624       }
02625     }
02626     // post-process resistors
02627     if (!def->action && !strcmp (def->type, "R")) {
02628       // drop the second "R" given in Model
02629       struct pair_t * r1 = spice_find_property_nocase (def, "R");
02630       struct pair_t * r2 = spice_find_property_nocase (r1->next, "R");
02631       if (r2 != NULL) {
02632         def->pairs = spice_del_property (def->pairs, r2);
02633       }
02634       // calculate R value
02635       struct pair_t * L = spice_find_property_nocase (def, "L");
02636       struct pair_t * W = spice_find_property_nocase (def, "W");
02637       struct pair_t * R = spice_find_property_nocase (def, "RSH");
02638       struct pair_t * D = spice_find_property_nocase (def, "DEFW");
02639       struct pair_t * N = spice_find_property_nocase (def, "NARROW");
02640       nr_double_t l = 0, w = 0, r = 0, d = 0, n = 0;
02641       if (L) {
02642         l = spice_evaluate_value (L->value);
02643         def->pairs = spice_del_property (def->pairs, L);
02644       }
02645       if (W) {
02646         w = spice_evaluate_value (W->value);
02647         def->pairs = spice_del_property (def->pairs, W);
02648       }
02649       if (R) {
02650         r = spice_evaluate_value (R->value);
02651         def->pairs = spice_del_property (def->pairs, R);
02652       }
02653       if (D) {
02654         d = spice_evaluate_value (D->value);
02655         def->pairs = spice_del_property (def->pairs, D);
02656       }
02657       if (N) {
02658         n = spice_evaluate_value (N->value);
02659         def->pairs = spice_del_property (def->pairs, N);
02660       }
02661       if (d == 0) d = 1e-6;
02662       if (w == 0) w = d;
02663       if (l != 0 && w != 0 && r != 0) {
02664         r = r * (l - n) / (w - n);
02665         spice_set_property_value (def, "R", r);
02666       }
02667       // handle Spice 2g6 syntax
02668       struct value_t * val;
02669       foreach_value (def->values, val) {
02670         if (!(val->hint & HINT_DONE) && (val->hint & HINT_NUMBER)) {
02671           spice_append_pair (def, "Tc2", val->ident, 0);
02672           spice_value_done (val);
02673           break;
02674         }
02675       }
02676     }
02677     // post-process capacitor
02678     if (!def->action && !strcmp (def->type, "C")) {
02679       // calculate C value
02680       struct pair_t * L = spice_find_property_nocase (def, "L");
02681       struct pair_t * W = spice_find_property_nocase (def, "W");
02682       struct pair_t * C = spice_find_property_nocase (def, "CJ");
02683       struct pair_t * S = spice_find_property_nocase (def, "CJSW");
02684       struct pair_t * D = spice_find_property_nocase (def, "DEFW");
02685       struct pair_t * N = spice_find_property_nocase (def, "NARROW");
02686       nr_double_t l = 0, w = 0, c = 0, d = 0, n = 0, s = 0;
02687       if (L) {
02688         l = spice_evaluate_value (L->value);
02689         def->pairs = spice_del_property (def->pairs, L);
02690       }
02691       if (W) {
02692         w = spice_evaluate_value (W->value);
02693         def->pairs = spice_del_property (def->pairs, W);
02694       }
02695       if (C) {
02696         c = spice_evaluate_value (C->value);
02697         def->pairs = spice_del_property (def->pairs, C);
02698       }
02699       if (S) {
02700         s = spice_evaluate_value (S->value);
02701         def->pairs = spice_del_property (def->pairs, S);
02702       }
02703       if (D) {
02704         d = spice_evaluate_value (D->value);
02705         def->pairs = spice_del_property (def->pairs, D);
02706       }
02707       if (N) {
02708         n = spice_evaluate_value (N->value);
02709         def->pairs = spice_del_property (def->pairs, N);
02710       }
02711       if (d == 0) d = 1e-6;
02712       if (w == 0) w = d;
02713       if (l != 0 && w != 0 && c != 0) {
02714         c = c * (l - n) * (w - n) + 2 * s * (l + w - 2 * n);
02715         spice_set_property_value (def, "C", c);
02716       }
02717     }
02718     // post-process lossless transmission line
02719     if (!def->action && !strcmp (def->type, "TLIN4P")) {
02720       struct pair_t * pt = spice_find_property (def, "TD");
02721       struct pair_t * pf = spice_find_property (def, "F");
02722       struct pair_t * pl = spice_find_property (def, "NL");
02723       nr_double_t len = 1e-3;
02724       if (pt != NULL) {
02725         // delay given
02726         len = spice_evaluate_value (pt->value) * C0;
02727         def->pairs = spice_del_property (def->pairs, pt);
02728         spice_set_property_value (def, "L", len);
02729       }
02730       else if (pf != NULL && pl != NULL) {
02731         // frequency and normalized length given
02732         nr_double_t f = spice_evaluate_value (pf->value);
02733         nr_double_t l = spice_evaluate_value (pl->value);
02734         def->pairs = spice_del_property (def->pairs, pf);
02735         def->pairs = spice_del_property (def->pairs, pl);
02736         len = C0 / f * l;
02737         spice_set_property_value (def, "L", len);
02738       }
02739       else if (pf != NULL) {
02740         // only frequency given, default normalized length
02741         nr_double_t f = spice_evaluate_value (pf->value);
02742         def->pairs = spice_del_property (def->pairs, pf);
02743         len = C0 / f * 0.25;
02744         spice_set_property_value (def, "L", len);
02745       }
02746       else {
02747         fprintf (stderr, "spice error, either TD or F required in "
02748                  "lossless `%s' line \n", def->instance);
02749         spice_errors++;
02750       }
02751     }
02752     // post-process mutual inductors (transformer)
02753     if (!def->action && !strcmp (def->type, "Tr")) {
02754       if (1)
02755         root = spice_translate_coupled_x (root, def);
02756       else
02757         root = spice_translate_coupled (root, def);
02758     }
02759     // post-process general analysis options
02760     if (def->action && strstr (def->type, "OPT")) {
02761       struct value_t * val;
02762       if ((val = spice_find_property (def->values, "ABSTOL")) != NULL) {
02763         spice_add_property (root, "DC", "abstol", val->unit);
02764         spice_add_property (root, "TR", "abstol", val->unit);
02765       }
02766       if ((val = spice_find_property (def->values, "RELTOL")) != NULL) {
02767         spice_add_property (root, "DC", "reltol", val->unit);
02768         spice_add_property (root, "TR", "reltol", val->unit);
02769       }
02770       if ((val = spice_find_property (def->values, "VNTOL")) != NULL) {
02771         spice_add_property (root, "DC", "vntol", val->unit);
02772         spice_add_property (root, "TR", "vntol", val->unit);
02773       }
02774       if ((val = spice_find_property (def->values, "ITL1")) != NULL) {
02775         spice_add_property (root, "DC", "MaxIter", val->unit);
02776       }
02777       if ((val = spice_find_property (def->values, "ITL4")) != NULL) {
02778         spice_add_property (root, "TR", "MaxIter", val->unit);
02779       }
02780     }
02781     // post-process print and plot statements
02782     if ((def->action && !strcmp (def->type, "PRINT")) ||
02783         !strcmp (def->type, "PLOT")) {
02784       spice_collect_external_nodes (def);
02785     }
02786     // post-process untranslated netlist lines
02787     if (def->define == NULL) {
02788       def->text = spice_untranslated_text (def);
02789     }
02790     // remove values if possible
02791     spice_free_values (def);
02792   }
02793   return root;
02794 }
02795 
02796 /* The function translates special actions defined in the Spice
02797    netlist including the types of simulations. */
02798 static struct definition_t *
02799 spice_translate_action (struct definition_t * root,
02800                         struct definition_t * def) {
02801   // translate transient analysis
02802   if (!strcasecmp (def->type, "TRAN")) {
02803     free (def->type);
02804     def->type = strdup ("TR");
02805     struct value_t * val;
02806     int i = 0;
02807     foreach_value (def->values, val) {
02808       switch (i++) {
02809       case 0:
02810         spice_append_pair (def, "Points", val->ident, 0);
02811         break;
02812       case 1:
02813         spice_append_pair (def, "Stop", val->ident, 0);
02814         break;
02815       case 2:
02816         spice_append_pair (def, "Start", val->ident, 0);
02817         break;
02818       case 3:
02819         break;
02820       }
02821       spice_value_done (val);
02822     }
02823     double v;
02824     v  = spice_get_property_value (def, "Stop");
02825     v -= spice_get_property_value (def, "Start");
02826     v /= spice_get_property_value (def, "Points");
02827     v += 1;
02828     spice_set_property_value (def, "Points", v);
02829   }
02830   // translate AC analysis
02831   else if (!strcasecmp (def->type, "AC")) {
02832     struct value_t * val;
02833     char * type = NULL;
02834     int i = 0;
02835     foreach_value (def->values, val) {
02836       switch (i++) {
02837       case 0:
02838         type = strdup (val->ident);
02839         break;
02840       case 1:
02841         spice_append_pair (def, "Points", val->ident, 0);
02842         break;
02843       case 2:
02844         spice_append_pair (def, "Start", val->ident, 0);
02845         break;
02846       case 3:
02847         spice_append_pair (def, "Stop", val->ident, 0);
02848         break;
02849       }
02850       spice_value_done (val);
02851     }
02852     double v;
02853     v = spice_evaluate_points (&type,
02854                                spice_get_property_value (def, "Start"),
02855                                spice_get_property_value (def, "Stop"),
02856                                spice_get_property_value (def, "Points"));
02857     spice_set_property_value (def, "Points", v + 1);
02858     spice_set_property_string (def, "Type", type);
02859     free (type);
02860   }
02861   // translate DC analysis
02862   else if (!strcasecmp (def->type, "DC")) {
02863     struct definition_t * para1 = NULL, * para2 = NULL;
02864     if (spice_count_values (def->values) >= 4) {
02865       para1 = spice_create_para (def);
02866       spice_set_property_string (para1, "Sim",
02867                                  spice_toupper (def->instance));
02868       if (spice_count_values (def->values) >= 4) {
02869         para2 = spice_create_para (def);
02870         spice_set_property_string (para2, "Sim",
02871                                    spice_toupper (para1->instance));
02872       }
02873     }
02874     if (para1) root = spice_add_definition (root, para1);
02875     if (para2) root = spice_add_definition (root, para2);
02876   }
02877   // translate subcircuit definition
02878   else if (!strcasecmp (def->type, "SUBCKT")) {
02879     free (def->type);
02880     def->type = strdup ("Def");
02881     def->sub = spice_checker_intern (def->sub);
02882   }
02883   // translate operating point analysis
02884   else if (!strcasecmp (def->type, "OP")) {
02885     free (def->type);
02886     def->type = strdup ("DC");
02887     spice_set_property_string (def, "saveOPs", "yes");
02888   }
02889   return root;
02890 }
02891 
02892 /* The following function translates the given definition 'sub' into a
02893    valid Qucs subcircuit instance. */
02894 static void spice_translate_subcircuit (struct definition_t * sub) {
02895   struct value_t * val;
02896   free (sub->type);
02897   sub->type = strdup ("Sub");
02898   foreach_value (sub->values, val) {
02899     if (val->hint & HINT_NAME) {
02900       spice_set_property_string (sub, "Type", val->ident);
02901       break;
02902     }
02903   }
02904 }
02905 
02906 /* The function returns a static string containing successive instance
02907    names for the nodeset functionality in Qucs. */
02908 static char * spice_create_intern_nodeset (void) {
02909   static int intern = 1;
02910   static char txt[32];
02911   sprintf (txt, "NS%d", intern++);
02912   return txt;
02913 }
02914 
02915 /* The following function translates the nodeset functionality defined
02916    by Spice into appropriate definitions for Qucs. */
02917 static struct definition_t *
02918 spice_translate_nodeset (struct definition_t * root,
02919                          struct definition_t * def) {
02920   struct value_t * val;
02921   struct definition_t * node = def;
02922   free (def->type);
02923   def->type = strdup ("NodeSet");
02924   free (node->instance);
02925   node->instance = strdup (spice_create_intern_nodeset ());
02926   node->action = PROP_COMPONENT;
02927   foreach_value (def->values->next, val) {
02928     if (val->hint & HINT_NODE) {
02929       node->nodes = spice_translate_node (val->ident);
02930     }
02931     if (val->hint & HINT_NUMBER) {
02932       spice_append_pair (node, "U", val->ident, 1);
02933     }
02934     if (val->hint & HINT_NAME) {
02935       node = spice_create_definition (node, "NodeSet");
02936       root = spice_add_definition (root, node);
02937       free (node->instance);
02938       node->instance = strdup (spice_create_intern_nodeset ());
02939     }
02940   }
02941   return root;
02942 }
02943 
02944 /* This is the overall Spice netlist translator.  It adjusts the list
02945    of definitions into usable structures. */
02946 static struct definition_t * spice_translator (struct definition_t * root) {
02947   for (struct definition_t * def = root; def != NULL; def = def->next) {
02948     if ((def->define = spice_find_definition (def->type)) != NULL) {
02949       strcpy (def->type, def->define->type);
02950       def->nodes = spice_get_nodes (def);
02951       def->pairs = spice_get_pairs (def);
02952       if (!def->action) { // handle normal components
02953         // devices
02954         if (!strcasecmp (def->type, "Q") || !strcasecmp (def->type, "M") ||
02955             !strcasecmp (def->type, "J") || !strcasecmp (def->type, "D") ||
02956             !strcasecmp (def->type, "S") || !strcasecmp (def->type, "R") ||
02957             !strcasecmp (def->type, "C")) {
02958           spice_translate_device (root, def);
02959         }
02960         // controlled sources
02961         if (!strcasecmp (def->type, "E") || !strcasecmp (def->type, "G")) {
02962           root = spice_translate_poly (root, def);
02963         }
02964         // controlled sources
02965         if (!strcasecmp (def->type, "C") || !strcasecmp (def->type, "L")) {
02966           root = spice_translate_poly_lc (root, def);
02967         }
02968         // voltage sources
02969         if (!strcasecmp (def->type, "V")) {
02970           root = spice_translate_source (root, def, 'U');
02971         }
02972         // current sources
02973         if (!strcasecmp (def->type, "I")) {
02974           root = spice_translate_source (root, def, 'I');
02975         }
02976         // subcircuits
02977         if (!strcasecmp (def->type, "X")) {
02978           spice_translate_subcircuit (def);
02979         }
02980         spice_translate_type (def);
02981       }
02982       else {              // handle special actions (dot '.' commands)
02983         // nodeset functionality
02984         if (!strcasecmp (def->type, "NODESET") ||
02985             !strcasecmp (def->type, "IC")) {
02986           root = spice_translate_nodeset (root, def);
02987         }
02988         else {
02989           root = spice_translate_action (root, def);
02990         }
02991       }
02992       spice_fixup_definition (def);
02993     }
02994     else {
02995       // handle device description
02996       if (!strcasecmp (def->type, "MODEL")) {
02997         spice_add_Model (def);
02998       }
02999     }
03000     // remove values if possible
03001     spice_free_values (def);
03002   }
03003   return root;
03004 }
03005 
03006 /* TODO list for Spice Translator:
03007        - current sources
03008        - subcircuits
03009    - file includes
03010    - transmission lines
03011        - voltage dependent sources
03012        - current dependent sources
03013        - initial conditions
03014        - options (partly done)
03015        - mutual inductors (transformer)
03016    - mesfet if available in Qucs
03017    - other mosfet models if available in Qucs
03018        - three mutual inductors
03019    - current controlled switch (gyrator + voltage controlled switch)
03020    - single-frequency FM (using pm-modulator)
03021        - controlled E, G, F, and H poly sources
03022    - analog behavioural B, E, G, F, and H sources
03023    - piece-wise linear (PWL) voltage and current sources
03024    - temperature analysis (.TEMP)
03025    - temperature option (.OPTIONS TNOM=27)
03026        - non-linear L and C poly components
03027 */
03028 
03029 #if 0
03030 // My debugger...
03031 static void spice_lister (struct definition_t * root) {
03032   struct value_t * val;
03033   for (struct definition_t * def = root; def != NULL; def = def->next) {
03034     fprintf (stderr, "%s:%s", def->type, def->instance);
03035     for (val = def->values; val != NULL; val = val->next) {
03036       if (val->ident)
03037         fprintf (stderr, " %s[%d]", val->ident, val->hint);
03038       else
03039         fprintf (stderr, " %g[%d]", val->value, val->hint);
03040     }
03041     fprintf (stderr, "\n");
03042   }
03043 }
03044 #endif
03045 
03046 // Adjusts the hint value of the last entry in the value list.
03047 void spice_add_last_hint (struct value_t * val, int hint) {
03048   if (val == NULL) return;
03049   for (; val->next != NULL; val = val->next) ;
03050   val->hint |= hint;
03051 }
03052 
03053 // Adjusts the hint value of the last entry in the value list.
03054 void spice_set_last_hint (struct value_t * val, int hint) {
03055   if (val == NULL) return;
03056   for (; val->next != NULL; val = val->next) ;
03057   val->hint = hint;
03058 }
03059 
03060 /* This function is the overall spice checker and translator. */
03061 struct definition_t * spice_checker_intern (struct definition_t * root) {
03062 #if 0
03063   spice_lister (root);
03064 #endif
03065   root = spice_translator (root);
03066   root = spice_post_translator (root);
03067   return root;
03068 }
03069 
03070 /* This function is the overall spice checker and translator. */
03071 int spice_checker (void) {
03072   spice_errors = 0;
03073   definition_root = spice_checker_intern (definition_root);
03074   return spice_errors;
03075 }