Qucs-core
0.0.19
|
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 }