Static void readStyles(void) { boolean eofstyle; Char S[256]; style_index0 l = 0; Char *TEMP; if (styleFileFound()) eofstyle = true; else eofstyle = P_eof(stylefile); while (!eofstyle) { fgets(S, 256, stylefile); TEMP = strchr(S, '\n'); if (TEMP != NULL) *TEMP = 0; if (*S != '\0') { addStyle(S); l++; orig_style_line[known_styles-1] = l; } eofstyle = P_eof(stylefile); } }
/* * initialize variables and necessary files to optimize the file in the variable "filename" * 1: Optimization Flow: should Alter and/or MonteCarlo be done? * 2: read "# Parameters #" * 3: read "# Measurements #" * 4: create <hostname>.tmp file; add measurements and replace symbols * 5: erase from memory parameters that will not be optimized * 6: use initial values stored in the <inputfile>.cfg file */ int initialize(char *filename) /* , double *x) */ { int i, ii; int ccode; char laux[LONGSTRINGSIZE], laux2[SHORTSTRINGSIZE], hostname[SHORTSTRINGSIZE] = "0"; /* <inputfile>.* <inputfile>.cfg <hostname>.tmp /extract/<file> */ FILE *fspice_source, *fspice_cfg, *fspice_tmp, *fextract; /**/ /*Step1: Optimization Flow: should Alter and/or MonteCarlo be done?*/ sprintf(laux, "%s%s", filename, ".cfg"); if ((fspice_cfg =fopen(laux ,"rt")) == 0) { printf("initialize.c - Step1 -- Cannot open config file: %s\n", laux); exit(EXIT_FAILURE); } ReadKey(lkk, "#Optimization Flow#", fspice_cfg); if (strcmp(lkk, "#Optimization Flow#")) { printf("INFO: initialize.c - Step1 -- #Optimization Flow# key not found\n"); fflush(stdout); } else { fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); /*should Alter be done?*/ Str2Lower(lkk); ii=1; ReadSubKey(laux, lkk, &ii, ':', ' ', 4); if (!strcmp(laux, "yes")) /* Alter==yes */ AlterMC+=2; else { if (strcmp(laux, "no")) { /* Alter!=no */ printf("initialize.c - Step1 -- Incorrect line format: %s\n", lkk); exit(EXIT_FAILURE); } } fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); /*should MonteCarlo be done?*/ Str2Lower(lkk); ii=1; ReadSubKey(laux, lkk, &ii, ':', ' ', 4); if (!strcmp(laux, "yes")) /*MonteCarlo==yes*/ AlterMC+=1; else { if (strcmp(laux, "no")) { /*MonteCarlo!=no*/ printf("initialize.c - Step1 -- Incorrect line format: %s\n", lkk); exit(EXIT_FAILURE); } } fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); ii=1; ReadSubKey(laux, lkk, &ii, ':', ' ', 4); AlterMCcost=asc2real(laux, 1, (int)strlen(laux)); if (AlterMCcost < 0) { printf("initialize.c - Step1 -- Minumum cost=%f, should be >= 0\n", AlterMCcost); exit(EXIT_FAILURE); } #ifdef DEBUG AlterMCcost=1.7976931348623157e+308; /*DBL_MAX from <float.h>*/ #endif fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); /*should RF parasitics be added?*/ Str2Lower(lkk); ii=1; ReadSubKey(laux, lkk, &ii, ':', ' ', 4); if (!strcmp(laux, "yes")) /*RF==yes*/ ExecuteRF=1; else { if (strcmp(laux, "no")) { /*RF!=no*/ printf("initialize.c - Step1 -- Incorrect line format: %s\n", lkk); exit(EXIT_FAILURE); } } } /**/ /*Step2: read "# Parameters #"*/ fseek(fspice_cfg, 0, SEEK_SET); ReadKey(lkk, "# Parameters #", fspice_cfg); /*configuration parameters*/ if (strcmp(lkk, "# Parameters #")) { printf("INFO: initialize.c - Step2 -- No parameters in config file\n"); fflush(stdout); } else { i=0; fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); while ((lkk[0] != '#') && (lkk[0] != '\0') && (!feof(fspice_cfg))) { if (lkk[0] != '*') { ii=strpos2(lkk, ":", 1); if (lkk[ii-1] != ':') { printf("initialize.c - Step2 -- Incorrect line format: %s\n", lkk); exit(EXIT_FAILURE); } strsub(parameters[i].name, lkk, 1, ii-1); /*name */ if (!(int)strlen(parameters[i].name)) { printf("initialize.c - Step2 -- Name size equal to zero not allowed: %s\n", lkk); exit(EXIT_FAILURE); } ReadSubKey(parameters[i].symbol, lkk, &ii, '#', '#', 5); /*symbol */ if (!(int)strlen(parameters[i].symbol)) { printf("initialize.c - Step2 -- Symbol size equal to zero not allowed: %s\n", lkk); exit(EXIT_FAILURE); } ReadSubKey(laux, lkk, &ii, ':', ':', 5); parameters[i].value=asc2real(laux, 1, (int)strlen(laux)); /*value */ ReadSubKey(laux, lkk, &ii, ':', ':', 5); parameters[i].minimum=asc2real(laux, 1, (int)strlen(laux)); /*minimum */ ReadSubKey(laux, lkk, &ii, ':', ':', 5); parameters[i].maximum=asc2real(laux, 1, (int)strlen(laux)); /*maximum */ if (parameters[i].minimum > parameters[i].maximum) { /*just to help*/ printf("initialize.c - Step2 -- Minimum is larger than Maximum in line: %s\n", lkk); exit(EXIT_FAILURE); } ReadSubKey(laux, lkk, &ii, ':', ':', 5); /*format */ if (laux[0] == 'E') { char IEC60063[] = " 3 6 12 24 48 96 192 "; strsub(laux2, laux, 2, 4); /*To keep with existing format of xxx_ while adding support for IEC 60063*/ sprintf(laux, "EEE_%s", laux2); /*preferred number series for resistors, capacitors and inductors */ if (!strpos2(IEC60063, laux2, 1)) { /*Only E3, E6, E12, E24, E48, E96 and E192 are allowed.*/ printf("initialize.c - Step2 -- Unrecognized option: %s\n", laux); exit(EXIT_FAILURE); } } if (laux[3] != 95) { /* 95="_" */ printf("initialize.c - Step2 -- Unrecognized option: %s\n", laux); exit(EXIT_FAILURE); } parameters[i].format=-1; /*number '-1' is used for posterior value validation*/ strsub(laux2, laux, 1, 3); if (!strcmp(laux2, "LIN")) parameters[i].format=0; if (!strcmp(laux2, "LOG")) parameters[i].format=2; if (!strcmp(laux2, "EEE")) parameters[i].format=8; if (parameters[i].format==-1) { /*validation*/ printf("initialize.c - Step2 -- Unrecognized option: %s\n", laux); exit(EXIT_FAILURE); } strsub(laux2, laux, 5, (int)strlen(laux)); if (!strcmp(laux2, "DOUBLE")) parameters[i].format=parameters[i].format+1; if (!strcmp(laux2, "INT")) { parameters[i].format=parameters[i].format+2; /*Enforce INT format*/ if ((parameters[i].value - (int)parameters[i].value) > 0) { printf("initialize.c - Step2 -- Number defined as INT is not integer in line: '%s'\n", lkk); exit(EXIT_FAILURE); } if ((parameters[i].minimum - (int)parameters[i].minimum) > 0) { printf("initialize.c - Step2 -- Number defined as INT is not integer in line: '%s'\n", lkk); exit(EXIT_FAILURE); } if ((parameters[i].maximum - (int)parameters[i].maximum) > 0) { printf("initialize.c - Step2 -- Number defined as INT is not integer in line: '%s'\n", lkk); exit(EXIT_FAILURE); } /* if ((parameters[i].maximum-parameters[i].minimum) <= 0) { printf("INFO: initialize.c - Step2 -- Minimum and Maximum are equal in line: '%s'\n", lkk); } */ } if (parameters[i].format==8) parameters[i].format=parameters[i].format+(((int)asc2real(laux2, 1, (int)strlen(laux2)))<<8); if (parameters[i].format==0) { /*validation*/ printf("initialize.c - Step2 -- Unrecognized option: %s\n", laux); exit(EXIT_FAILURE); } ReadSubKey(laux, lkk, &ii, ':', ':', 4); /*optimize */ if (!strcmp(laux, "OPT")) parameters[i].optimize=1; /*is it "OPT"? */ else { if (!strcmp(laux, "---")) { /*if it is "---", then */ parameters[i].optimize=0; /*do not optimize */ parameters[i].minimum=parameters[i].value; /*furthermore, if it is just to define a quantity */ parameters[i].maximum=parameters[i].value; /*then make minimum=maximum=value */ } else { printf("initialize.c - Step2 -- Unrecognized option: %s\n", laux); exit(EXIT_FAILURE); } } i++; if (i > MAXPARAMETERS) { printf("initialize.c - Step2 -- Maximum number of parameter reached (>%d). Increase MAXPARAMETERS in initialize.h\n",MAXPARAMETERS); exit(EXIT_FAILURE); } } fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); } } /**/ /*Step3: read "# Measurements #"*/ fseek(fspice_cfg, 0, SEEK_SET); ReadKey(lkk, "# Measurements #", fspice_cfg); /*configuration measurements*/ if (strcmp(lkk, "# Measurements #")) { printf("INFO: initialize.c - Step3 -- No measurements in config file\n"); fflush(stdout); } else { i=0; fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); while ((lkk[0] != '#') && (lkk[0] != '\0') && (!feof(fspice_cfg))) { if (lkk[0] != '*') { ii=strpos2(lkk, ":", 1); if (lkk[ii-1] != ':') { printf("initialize.c - Step3 -- Incorrect line format: %s\n", lkk); exit(EXIT_FAILURE); } strsub(measurements[i].meas_symbol, lkk, 1, ii-1); /*meas_symbol*/ sprintf(laux, "%i", i); strcat(measurements[i].meas_symbol, laux); /* add number to symbol (*) */ ReadSubKey(measurements[i].node, lkk, &ii, ':', ':', 5); /*node*/ ReadSubKey(laux, lkk, &ii, ':', ':', 5); /*objective_constraint*/ measurements[i].objective_constraint=0; /*number '0' is used for posterior value validation*/ if (!strcmp(laux, "MIN")) measurements[i].objective_constraint=1; if (!strcmp(laux, "MAX")) measurements[i].objective_constraint=2; if (!strcmp(laux, "MON")) measurements[i].objective_constraint=3; if (!strcmp(laux, "LE")) measurements[i].objective_constraint=4; if (!strcmp(laux, "GE")) measurements[i].objective_constraint=5; if (!strcmp(laux, "EQ")) measurements[i].objective_constraint=6; if (measurements[i].objective_constraint==0) { /*validation*/ printf("initialize.c - Step3 -- Unrecognized option: %s\n", laux); exit(EXIT_FAILURE); } ReadSubKey(laux, lkk, &ii, ':', ':', 4); measurements[i].constraint_value=asc2real(laux, 1, (int)strlen(laux)); /*constraint_value*/ i++; if (i > MAXMEASUREMENTS-1) { printf("initialize.c - Step3 -- Maximum number of measurements reached (>%d). Increase MAXMEASUREMENTS in initialize.h\n", MAXMEASUREMENTS); exit(EXIT_FAILURE); } } fgets2(lkk, LONGSTRINGSIZE, fspice_cfg); } measurements[i].meas_symbol[0]='\0'; /*just in case... zero the first remaining entry*/ } fclose(fspice_cfg); /**/ /*Step4: create <hostname>.tmp file; add measurements and replace symbols*/ switch(spice) { case 1: /*Eldo*/ sprintf(laux, "%s%s", filename, ".cir"); break; case 2: /*HSPICE*/ sprintf(laux, "%s%s", filename, ".sp"); break; case 3: /*LTspice*/ sprintf(laux, "%s%s", filename, ".net"); break; case 4: /*Spectre*/ sprintf(laux, "%s%s", filename, ".scs"); break; case 50: /*Qucs*/ sprintf(laux, "%s%s", filename, ".txt"); break; case 51: /*ngspice*/ sprintf(laux, "%s%s", filename, ".sp"); break; case 100: /*general*/ sprintf(laux, "%s%s", filename, ".txt"); break; default: printf("initialize.c - Step4 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } if ((fspice_source=fopen(laux, "rt")) == 0) { /*source netlist*/ printf("initialize.c - Step4 -- Cannot open input file: %s\n", laux); exit(EXIT_FAILURE); } /**/ if ((ccode = gethostname(hostname, sizeof(hostname))) != 0) { /* !=0 can most likelly be deleted from all lines */ printf("initialize.c - Step4 -- gethostname failed, ccode = %d\n", ccode); exit(EXIT_FAILURE); } /* printf("host name: %s\n", hostname); */ ii=strpos2(hostname, ".", 1); if (ii) /* hostname is "longmorn.xx.xx.xx" */ hostname[ii-1]='\0'; sprintf(lkk, "%s%s", hostname, ".tmp"); /* hostname is "longmorn" */ if ((fspice_tmp =fopen(lkk ,"wt")) == 0) { /* netlist to simulate given by "hostname" */ printf("initialize.c - Step4 -- Cannot write to tmp file: %s\n", lkk); exit(EXIT_FAILURE); } /*Step4.1: ".end" not yet found*/ fgets2(lkk, LONGSTRINGSIZE, fspice_source); /*read and */ fprintf(fspice_tmp, "%s\n", lkk); /*write the first line */ while (!P_eof(fspice_source)) { fgets2(lkk, LONGSTRINGSIZE, fspice_source); strcpy(laux, lkk); /*detect ".end", ".END", ".End", ... */ Str2Lower(laux); StripSpaces(laux); /* avoid spaces after the command ".end" */ if (!strcmp(laux, ".end")) break; /***** -------------- *********** -------------- *****/ /***** -------------- ** BEGIN ** -------------- *****/ if (lkk[0]!='*') { i=inlinestrpos(lkk); ii=1; ReadSubKey(laux, lkk, &ii, '#', '#', 0); if ( (laux[0]=='\0') || (ii>(int)strlen(lkk)) || ((i<ii) && (i!=0)) ) { /*does it contains #<text>#? */ if ((int)strlen(lkk) && (!RFModule(lkk, 0, fspice_tmp)) ) fprintf(fspice_tmp, "%s\n", lkk); /* no: write line to <hostname>.tmp */ } else { /* yes: replace #<text># in this line */ if (!RFModule(lkk, 0, fspice_tmp)) { /* -Symbol replaced in the RFmodule*/ ReplaceSymbol(lkk, 0); /* -Symbol yet to be replaced */ fprintf(fspice_tmp, "%s\n", lkk); /* write line to <hostname>.tmp */ } } } /***** -------------- ** END ** -------------- *****/ /***** -------------- *********** -------------- *****/ } switch(spice) { case 1: /*Eldo*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("initialize.c - Step4.1 -- End not found in %s.cir\n", filename); exit(EXIT_FAILURE); } break; case 2: /*HSPICE*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("initialize.c - Step4.1 -- End not found in %s.sp\n", filename); exit(EXIT_FAILURE); } break; case 3: /*LTspice*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("initialize.c - Step4.1 -- End not found in %s.net\n", filename); exit(EXIT_FAILURE); } break; case 4: /*Spectre*/ /* ".end" does not exist in Spectre syntax */ break; case 50: /*Qucs*/ /* ".end" does not exist in Qucs syntax */ break; case 51: /*ngspice*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("initialize.c - Step4.1 -- End not found in %s.sp\n", filename); exit(EXIT_FAILURE); } break; case 100: /*general*/ break; default: printf("initialize.c - Step4.1 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } /*Special case to deal with Spectre MDL*/ switch(spice) { case 1: /*Eldo*/ break; case 2: /*HSPICE*/ break; case 3: /*LTspice*/ break; case 4: /*Spectre*/ fclose(fspice_tmp); sprintf(lkk, "%s%s", hostname, ".mdl"); /* hostname is "longmorn" */ if ((fspice_tmp =fopen(lkk ,"wt")) == 0) { /* netlist to simulate given by "hostname" */ printf("initialize.c - Step4.1 -- Cannot write to tmp file: %s\n", lkk); exit(EXIT_FAILURE); } fseek(fspice_source, 0, SEEK_SET); while (!P_eof(fspice_source)) { fgets2(lkk, LONGSTRINGSIZE, fspice_source); if ( (lkk[0] != '*') && (lkk[0] != '\0') && (!strpos2(lkk, "//", 1)) ) { strcpy(laux, lkk); /*detect "TRAN", "tran", "TRan", ... */ Str2Lower(laux); StripSpaces(laux); /*avoid spaces after the command*/ if (strpos2(laux, " dc ", 1)) { fprintf(fspice_tmp, "alias measurement dc_run {\n"); i=strpos2(laux, " dc ", 1); strsub(laux, lkk, 1, i); StripSpaces(laux); fprintf(fspice_tmp, "run %s\n", laux); } if (strpos2(laux, " ac ", 1)) { fprintf(fspice_tmp, "alias measurement ac_run {\n"); i=strpos2(laux, " ac ", 1); strsub(laux, lkk, 1, i); StripSpaces(laux); fprintf(fspice_tmp, "run %s\n", laux); } if (strpos2(laux, " tran ", 1)) { fprintf(fspice_tmp, "alias measurement tran_run {\n"); i=strpos2(laux, " tran ", 1); strsub(laux, lkk, 1, i); StripSpaces(laux); fprintf(fspice_tmp, "run %s\n", laux); } } } break; case 50: /*Qucs*/ break; case 51: /*ngspice*/ break; case 100: /*general*/ break; default: printf("initialize.c - Step4.1 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } /*Special case to deal with Spectre MDL*/ /*Step4.2: End of file is found and now add measurements*/ i=0; fprintf(fspice_tmp, "\n"); while (strcmp(measurements[i].meas_symbol,"\0") ) { /*until the end of all symbols*/ sprintf(lkk, "%i", i); /* to remove integer added in (*) */ ii=(int)strlen(lkk); /* to remove integer added in (*) */ sprintf(lkk, "%s%s", "extract/", measurements[i].meas_symbol); /* to remove integer added in (*) */ lkk[(int)strlen(lkk)-ii]='\0'; /* to remove integer added in (*) */ if ((fextract =fopen(lkk ,"rt")) == 0) { printf("initialize.c - Step4.2 -- Cannot find measurement file: %s\n", lkk); exit(EXIT_FAILURE); } strcpy(laux,lkk); ReadKey(lkk, "# Commands #", fextract); if (strcmp(lkk, "# Commands #")) { /*finds "# Commands #" and writes to <hostname>.tmp until the end of file*/ printf("initialize.c - Step4.2 -- Wrong format in file: %s\n", laux); exit(EXIT_FAILURE); } /*Step4.2.1: Add the measurement to <hostname>.tmp*/ /*---------------------------------------------------------------*/ sprintf(lkk, "%i", i); /* to remove integer added in (*) */ ii=(int)strlen(lkk); /* to remove integer added in (*) */ strcpy(lkk, measurements[i].meas_symbol); /* to remove integer added in (*) */ lkk[(int)strlen(lkk)-ii]='\0'; /* to remove integer added in (*) */ switch(spice) { case 1: /*Eldo*/ fprintf(fspice_tmp, "* %i) Extract \'%s\'\n", i+1, lkk); break; case 2: /*HSPICE*/ fprintf(fspice_tmp, "* %i) Extract \'%s\'\n", i+1, lkk); break; case 3: /*LTspice*/ fprintf(fspice_tmp, "* %i) Extract \'%s\'\n", i+1, lkk); break; case 4: /*Spectre*/ fprintf(fspice_tmp, "// %i) Extract \'%s\'\n", i+1, lkk); break; case 50: /*Qucs*/ fprintf(fspice_tmp, "# %i) Extract \'%s\'\n", i+1, lkk); break; case 51: /*ngspice*/ fprintf(fspice_tmp, "* %i) Extract \'%s\'\n", i+1, lkk); break; case 100: /*general*/ fprintf(fspice_tmp, "* %i) Extract \'%s\'\n", i+1, lkk); break; default: printf("initialize.c - Step4.2.1 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } fgets2(lkk, LONGSTRINGSIZE, fextract); /* reads from directory "extract/" */ while ((lkk[0] != '#') && (lkk[0] != '\0') && (!feof(fextract))) { switch(spice) { case 1: /*Eldo*/ strcpy(laux,lkk); StripSpaces(laux); Str2Lower(laux); if (strpos2(laux, ".meas ", 1)) { sprintf(lkk, "%i", i); /* to remove integer added in (*) */ ii=(int)strlen(lkk); /* to remove integer added in (*) */ sprintf(lkk, "%s%s", "extract/", measurements[i].meas_symbol); /* to remove integer added in (*) */ lkk[(int)strlen(lkk)-ii]='\0'; /* to remove integer added in (*) */ printf("initialize.c - Step4.2.1 -- .MEAS not supported in file: %s. Use .EXTRACT instead.\n", lkk); exit(EXIT_FAILURE); } break; case 2: /*HSPICE*/ break; case 3: /*LTspice*/ break; case 4: /*Spectre*/ break; case 50: /*Qucs*/ break; case 51: /*ngspice*/ break; case 100: /*general*/ break; default: printf("initialize.c - Step4.2.1 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } ii=1; ReadSubKey(laux, lkk, &ii, '#', '#', 0); if (laux[0]!='\0') { DecodeSymbolNode(lkk, i); /*has to replace #<text># in this line*/ } if (lkk[0]!='#') { /*if end of block has not been reached*/ fprintf(fspice_tmp, "%s\n", lkk); /* writes to <hostname>.tmp */ } fgets2(lkk, LONGSTRINGSIZE, fextract); /*reads from directory "extract/"*/ } fprintf(fspice_tmp, "\n"); /*Step4.2.2: Add entry to variable 'measure[i].var_name' and 'measure[i].search'*/ /*---------------------------------------------------------------*/ fseek(fextract, 0, SEEK_SET); ReadKey(lkk, "MEASURE_VAR", fextract); { measure[0].search[0]=10;/*"ProcessOutputFile", line 1231: makes data to read not found on measure[0]*/ } ii=1; while ((*measure[ii].var_name) != '\0') /* finds the proper entry */ ii++; /* place. Store in 'ii' */ if (ii > MAXMEAS-1) { printf("initialize.c - Step4.2.2 -- Maximum number of measurements reached (>%d). Increase MAXMEAS in auxfunc_measurefromlis.h\n", MAXMEAS); exit(EXIT_FAILURE); } if (strcmp((sprintf(laux, "%.11s", lkk), laux), "MEASURE_VAR")) { /*general case, if it's not a "MEASURE_VAR"; data from "/extract/<file>"*/ sprintf(lkk, "%s%s", UNIQUECHAR,measurements[i].meas_symbol); strcpy(measure[ii].var_name, lkk); /*measure[ii].var_name*/ switch(spice) { /* the format in which the variables are written in the output file: fast read */ case 1: /*Eldo*/ sprintf(lkk, " %s%s =", UNIQUECHAR, measurements[i].meas_symbol); Str2Upper(lkk); break; case 2: /*HSPICE*/ sprintf(lkk, " %s%s=", UNIQUECHAR, measurements[i].meas_symbol); Str2Lower(lkk); break; case 3: /*LTspice*/ sprintf(lkk, "%s%s:", UNIQUECHAR, measurements[i].meas_symbol); Str2Lower(lkk); break; case 4: /*Spectre*/ sprintf(lkk, "%s%s", UNIQUECHAR, measurements[i].meas_symbol); ccode=(int)strlen(lkk); while (ccode<18) { strcat(lkk, " "); ccode++; } strcat(lkk, " ="); break; case 50: /*Qucs*/ break; case 51: /*ngspice*/ sprintf(lkk, "%s%s", UNIQUECHAR, measurements[i].meas_symbol); Str2Lower(lkk); ccode=(int)strlen(lkk); while (ccode<20) { strcat(lkk, " "); ccode++; } strcat(lkk, "="); break; case 100: /*general*/ break; default: printf("initialize.c - Step4.2.2 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } strcpy(measure[ii].search, lkk); /*measure[ii].var_name*/ } else { /*a line with "MEASURE_VAR" exist in "/extract/<file>"*/ while (!strcmp((sprintf(laux, "%.11s", lkk), laux), "MEASURE_VAR")) { DecodeSymbolNode(lkk, i); #ifndef __MINGW32__ ii=ProcessMeasureVar(lkk, ii, "/dev/null"); #else ii=ProcessMeasureVar(lkk, ii, "NUL"); #endif switch(spice) { case 1: /*Eldo*/ ccode=strpos2(measure[ii].search, UNIQUECHAR, 1); //if (ccode) { // Str2Upper(measure[ii].search); //} break; case 2: /*HSPICE*/ ccode=strpos2(measure[ii].search, UNIQUECHAR, 1); //if (ccode) { // Str2Lower(measure[ii].search); //} break; case 3: /*LTspice*/ ccode=strpos2(measure[ii].search, UNIQUECHAR, 1); //if (ccode) { // Str2Lower(measure[ii].search); //} break; case 4: /*Spectre*/ break; case 50: /*Qucs*/ break; case 51: /*ngspice*/ ccode=strpos2(measure[ii].search, "MATH", 1); /*DO NOT change MATH lines character case*/ if (!ccode){ ccode=strpos2(measure[ii].search, UNIQUECHAR, 1); if (ccode) { Str2Lower(measure[ii].search); } } break; case 100: /*general*/ break; default: printf("initialize.c - Step4.2.2 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } ReadKey(lkk, "MEASURE_VAR", fextract); if ((int)strlen(lkk)) { ii++; if (ii > MAXMEAS-1) { printf("initialize.c - Step4.2.2 -- Maximum number of measurements reached (>%d). Increase MAXMEAS in auxfunc_measurefromlis.h\n", MAXMEAS); exit(EXIT_FAILURE); } } } } /*---------------------------------------------------------------*/ /*Step4.2.3: Continues ... */ fclose(fextract); i++; } /*Step4.3: Add ".end" where required*/ switch(spice) { case 1: /*Eldo*/ fprintf(fspice_tmp, "%s\n", ".end"); break; case 2: /*HSPICE*/ fprintf(fspice_tmp, "%s\n", ".end"); break; case 3: /*LTspice*/ fprintf(fspice_tmp, "%s\n", ".end"); break; case 4: /*Spectre*/ /*Special case to deal with Spectre MDL*/ ccode=0; /* at this momment, only one measurement can exist in the <inputfile>.scs */ fseek(fspice_source, 0, SEEK_SET); fprintf(fspice_tmp, "}\n\n"); while (!P_eof(fspice_source)) { fgets2(lkk, LONGSTRINGSIZE, fspice_source); if ( (lkk[0] != '*') && (lkk[0] != '\0') && (!strpos2(lkk, "//", 1)) ) { strcpy(laux, lkk); /*detect "TRAN", "tran", "TRan", ... */ Str2Lower(laux); StripSpaces(laux); /*avoid spaces after the command*/ if (strpos2(laux, " dc ", 1)) { if (ccode!=0) { printf("initialize.c - Step4.3 -- Only one type of simulation is implememted at this time!\n"); exit(EXIT_FAILURE); } ccode++; i=strpos2(laux, " dc ", 1); strsub(laux, lkk, 1, i); StripSpaces(laux); fprintf(fspice_tmp, "run dc_run as dc1\n"); } if (strpos2(laux, " ac ", 1)) { if (ccode!=0) { printf("initialize.c - Step4.3 -- Only one type of simulation is implememted at this time!\n"); exit(EXIT_FAILURE); } ccode++; i=strpos2(laux, " ac ", 1); strsub(laux, lkk, 1, i); StripSpaces(laux); fprintf(fspice_tmp, "run ac_run as ac1\n"); } if (strpos2(laux, " tran ", 1)) { if (ccode!=0) { printf("initialize.c - Step4.3 -- Only one type of simulation is implememted at this time!\n"); exit(EXIT_FAILURE); } ccode++; i=strpos2(laux, " tran ", 1); strsub(laux, lkk, 1, i); StripSpaces(laux); fprintf(fspice_tmp, "run tran_run as tran1\n"); } } } /*Special case to deal with Spectre MDL*/ break; case 50: /*Qucs*/ break; case 51: /*ngspice*/ fprintf(fspice_tmp, "%s\n", ".end"); break; case 100: /*general*/ break; default: printf("initialize.c - Step4.3 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } fclose(fspice_source); fclose(fspice_tmp); /**/ /*Step5: erase from memory parameters that will not be optimized*/ ii=0; for (i = 0; i < MAXPARAMETERS; i++) { if ((parameters[i].optimize == 1) && (i>ii)) { /*if ... then move*/ strcpy (parameters[ii].name, parameters[i].name); strcpy (parameters[ii].symbol,parameters[i].symbol); parameters[ii].value = parameters[i].value; parameters[ii].minimum = parameters[i].minimum; parameters[ii].maximum = parameters[i].maximum; parameters[ii].format = parameters[i].format; parameters[ii].optimize = parameters[i].optimize; ii++; } else if (parameters[i].optimize) ii++; } for (i = ii; i < MAXPARAMETERS; i++) { /*just in case... zero all remaining entries*/ parameters[i].name[0] ='\0'; parameters[i].symbol[0]='\0'; parameters[i].value = 0; parameters[i].minimum = 0; parameters[i].maximum = 0; parameters[i].format = 0; parameters[i].optimize = 0; } /**/ /*Initialization6: use initial values stored in the <inputfile>.cfg file */ /*for (ii = 0; ii < MAXPARAMETERS; ii++) { */ /* x[ii] = scaleto(parameters[ii].value, parameters[ii].minimum, parameters[ii].maximum, -10, +10); */ /*} */ /**/ /*Initialization7*/ return EXIT_SUCCESS; }
/* * This is the main function * 1: scale input parameters from [-10, +10] to fit within desired range values * 2: read from <hostname>.tmp and write to <hostname>.* * 3: execute 'SPICE <hostname>.*' * 4: read output <hostname>.out * 5: find cost * 6: save log information to file <hostname>.log * 7: ALTER and MC simulation * 8: return cost */ double errfunc(char *filename, double *x) { /*double currentcost;*/ /*total cost*/ int i, ii; int ccode; char laux[LONGSTRINGSIZE], hostname[SHORTSTRINGSIZE] = "0", filename_x[SHORTSTRINGSIZE] = "0"; /* <hostname>.* <hostname>.out <hostname>.tmp <hostname>.log*/ FILE *fspice_input, *fspice_output, *fspice_tmp, *fspice_log; /**/ /*Step1: scale input parameters from [-10, +10] to fit within desired range values*/ #ifdef DEBUG printf("DEBUG: errfunc.c - Step1\n"); #endif for (i = 0; i < MAXPARAMETERS; i++) { if (parameters[i].format) { parameters[i].value = scaleto(x[i], -10, +10, parameters[i].minimum, parameters[i].maximum, parameters[i].format); if (parameters[i].value<0) { ii=1; /*printf("INFO: errfunc.c - Step1 -- Negative values\n");*/ } } } /**/ /*Step2: read from <hostname>.tmp and write to <hostname>.**/ /* */ /* It is not necessary to check every time for the possibility to read/write. Move to initicialization if possible!! */ /* */ #ifdef DEBUG printf("DEBUG: errfunc.c - Step2\n"); #endif if ((ccode = gethostname(hostname, sizeof(hostname))) != 0) { printf("errfunc.c - Step2 -- gethostname failed, ccode = %d\n", ccode); exit(EXIT_FAILURE); } /* printf("host name: %s\n", hostname); */ ii=strpos2(hostname, ".", 1); if (ii) /* hostname is "longmorn.xx.xx.xx" */ hostname[ii-1]='\0'; sprintf(lkk, "%s%s", hostname, ".tmp"); /* hostname is "longmorn" */ if ((fspice_tmp =fopen(lkk ,"rt")) == 0) { /* netlist to simulate given by "hostname" */ printf("errfunc.c - Step2 -- Cannot read from tmp file: %s\n", lkk); exit(EXIT_FAILURE); } switch(spice) { case 1: /*Eldo*/ sprintf(lkk, "%s%s", hostname, ".cir"); break; case 2: /*HSPICE*/ sprintf(lkk, "%s%s", hostname, ".sp"); break; case 3: /*LTspice*/ sprintf(lkk, "%s%s", hostname, ".net"); break; case 4: /*Spectre*/ sprintf(lkk, "%s%s", hostname, ".scs"); break; case 50: /*Qucs*/ sprintf(lkk, "%s%s", hostname, ".txt"); break; case 51: /*ngspice*/ sprintf(lkk, "%s%s", hostname, ".sp"); break; case 100: /*general*/ sprintf(lkk, "%s%s", hostname, ".txt"); break; default: printf("errfunc.c - Step2 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } if ((fspice_input =fopen(lkk ,"wt")) == 0) { /*netlist to simulate given by 'hostname'*/ printf("errfunc.c - Step2 -- Cannot write to output file: %s\n", lkk); exit(EXIT_FAILURE); } /*Step2.1: ".end" not yet found*/ fgets2(lkk, LONGSTRINGSIZE, fspice_tmp); /*read and*/ fprintf(fspice_input, "%s\n", lkk); /*write the first line*/ while (!P_eof(fspice_tmp)) { fgets2(lkk, LONGSTRINGSIZE, fspice_tmp); strcpy(laux, lkk); /*detect ".end", ".END", ".End", ... */ Str2Lower(laux); StripSpaces(laux); /* avoid spaces after the command ".end" */ if (!strcmp(laux, ".end")) break; /***** -------------- *********** -------------- *****/ /***** -------------- ** BEGIN ** -------------- *****/ if (lkk[0]!='*') { i=inlinestrpos(lkk); ii=1; ReadSubKey(laux, lkk, &ii, '#', '#', 0); if ( (laux[0]=='\0') || (ii>(int)strlen(lkk)) || ((i<ii) && (i!=0)) ) { /* does it contains #<text>#? */ if ((int)strlen(lkk) && (!RFModule(lkk, 1, fspice_input)) ) fprintf(fspice_input, "%s\n", lkk); /*no, write line to <hostname>.* */ } else { /*yes, replace #<text># in this line */ if (!RFModule(lkk, 1, fspice_input)) { ReplaceSymbol(lkk, 1); fprintf(fspice_input, "%s\n", lkk); /* write line to <hostname>.* */ } } } /***** -------------- ** END ** -------------- *****/ /***** -------------- *********** -------------- *****/ } switch(spice) { case 1: /*Eldo*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("errfunc.c - Step2.1 -- End not found in %s.cir\n", filename); exit(EXIT_FAILURE); } break; case 2: /*HSPICE*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("errfunc.c - Step2.1 -- End not found in %s.sp\n", filename); exit(EXIT_FAILURE); } break; case 3: /*LTspice*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("errfunc.c - Step2.1 -- End not found in %s.net\n", filename); exit(EXIT_FAILURE); } break; case 4: /*Spectre*/ /* ".end" does not exist in Spectre syntax */ break; case 50: /*Qucs*/ /* ".end" does not exist in Qucs syntax */ break; case 51: /*ngspice*/ if (strcmp(laux, ".end")) { /*Exit if ".end" is not found*/ printf("errfunc.c - Step2.1 -- End not found in %s.sp\n", filename); exit(EXIT_FAILURE); } break; case 100: /*general*/ break; default: printf("errfunc.c - Step2.1 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } /*Step2.3: Add ".end" where required*/ switch(spice) { case 1: /*Eldo*/ fprintf(fspice_input, "%s\n", ".end"); break; case 2: /*HSPICE*/ fprintf(fspice_input, "%s\n", ".end"); break; case 3: /*LTspice*/ fprintf(fspice_input, "%s\n", ".end"); break; case 4: /*Spectre*/ break; case 50: /*Qucs*/ break; case 51: /*ngspice*/ fprintf(fspice_input, "%s\n", ".end"); break; case 100: /*general*/ break; default: printf("errfunc.c - Step2.3 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } fclose(fspice_input); fclose(fspice_tmp); /**/ /*Step3: execute 'SPICE <hostname>.*'*/ #ifdef DEBUG printf("DEBUG: errfunc.c - Step3\n"); #endif switch(spice) { case 1: /*Eldo*/ sprintf(lkk, "nice -n 19 eldo -noconf -i %s.cir > %s.out", hostname, hostname); break; case 2: /*HSPICE*/ #ifndef __MINGW32__ sprintf(lkk, "nice -n 19 hspice -i %s.sp -o %s.lis > /dev/null", hostname, hostname); #else sprintf(lkk, "hspice -i %s.sp -o %s.lis > NUL", hostname, hostname); #endif break; case 3: /*LTspice*/ #ifndef __MINGW32__ sprintf(lkk, "nice -n 19 ltspice -b %s.net > /dev/null", hostname); #else sprintf(lkk, "ltspice -b %s.net > NUL", hostname); #endif break; case 4: /*Spectre*/ sprintf(lkk, "nice -n 19 spectremdl -batch %s.mdl -design %s.scs > /dev/null", hostname, hostname); break; case 50: /*Qucs*/ #ifndef __MINGW32__ sprintf(lkk, "nice -n 19 qucsator -i %s.txt -o %s.dat > /dev/null", hostname, hostname); #else sprintf(lkk, "qucsator -i %s.txt -o %s.dat > NUL", hostname, hostname); #endif break; case 51: /*ngspice*/ #ifndef __MINGW32__ sprintf(lkk, "nice -n 19 ngspice -b -o %s.out %s.sp > /dev/null 2>&1", hostname, hostname); #else sprintf(lkk, "ngspice -o %s.out %s.sp > NUL", hostname, hostname); #endif break; case 100: /*general*/ #ifndef __MINGW32__ sprintf(lkk, "nice -n 19 ./general.sh %s %s", hostname, hostname); #else sprintf(lkk, "./general.sh %s %s", hostname, hostname); #endif break; default: printf("errfunc.c - Step3 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } ii=system(lkk); #ifndef __MINGW32__ if (WIFSIGNALED(ii) && (WTERMSIG(ii) == SIGINT || WTERMSIG(ii) == SIGQUIT)) { printf("errfunc.c - Step3 -- Ctrl-C key pressed. Exiting optimization loop.\n"); fflush(stdout); #ifdef MPI /* exit(EXIT_FAILURE); */ #else return(0); /*returned simulation cost is zero; Ctrl-C detection*/ #endif } #endif /**/ /*Step4: read output <hostname>.out, find maxcost and save log information to file <hostname>.log*/ #ifdef DEBUG printf("DEBUG: errfunc.c - Step4\n"); #endif switch(spice) { case 1: /*Eldo*/ sprintf(lkk, "%s.out", hostname); break; case 2: /*HSPICE*/ sprintf(lkk, "%s.lis", hostname); break; case 3: /*LTspice*/ sprintf(lkk, "%s.log", hostname); break; case 4: /*Spectre*/ sprintf(lkk, "%s.measure", hostname); break; case 50: /*Qucs*/ sprintf(lkk, "%s.dat", hostname); break; case 51: /*ngspice*/ sprintf(lkk, "%s.out", hostname); break; case 100: /*general*/ sprintf(lkk, "%s.out", hostname); break; default: printf("errfunc.c - Step4 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } maxcost=0; #ifdef DEBUG ProcessOutputFile(lkk, 3); /* =>3:mem+file */ #else ProcessOutputFile(lkk, 1); /* =>1:mem */ #endif /**/ /*Step5: find cost*/ /* #ifdef DEBUG */ /* printf("DEBUG: errfunc.c - Step5\n"); */ /* #endif */ /* currentcost=CostFunction(); */ /* if (maxcost<currentcost) */ /* maxcost=currentcost; */ /**/ /*Step6: save log information to file <hostname>.log*/ /* #ifdef DEBUG */ /* printf("DEBUG: errfunc.c - Step6\n"); */ /* #endif */ /* if (LOG) { */ /* LogtoFile(currentcost); */ /* } */ /**/ /*Step7: ALTER and MC simulation*/ #ifdef DEBUG printf("DEBUG: errfunc.c - Step7\n"); #endif if ( (((AllConstraintsMet()) && (AlterMCcost > maxcost)) || (AlterMCcost > maxcost)) && (AlterMC)) { switch (AlterMC) { case 1: /*Monte Carlo simulation*/ /* bla bla bla*/ printf("INFO: errfunc.c - Step7 -- altermc=%d\n", AlterMC); fflush(stdout); if (LOG) { sprintf(laux, "%s.log", hostname); if ((fspice_log=fopen(laux,"at")) == 0) { printf("errfunc.c - Step7 -- Cannot open log file: %s\n", laux); exit(EXIT_FAILURE); } fprintf(fspice_log, "Alter: 1 - altermc=%d\n", AlterMC); fclose(fspice_log); } strcpy (filename_x, filename); strcat(filename_x, ".cfg"); sprintf(lkk, "%s%s", hostname, ".tmp"); /* hostname is "longmorn" */ sprintf(laux, "%s%s", hostname, ".mc"); /* hostname is "longmorn" */ MonteCarlo(filename_x, lkk, laux); /* execute the 'monte' tool */ sprintf(lkk, "%s%s", hostname, ".mc"); /* hostname is "longmorn" */ if ((fspice_input =fopen(lkk ,"rt")) == 0) { /*netlist to simulate given by "hostname" */ printf("errfunc.c - Step7 -- Cannot read from mc file: %s\n", lkk); exit(EXIT_FAILURE); } sprintf(lkk, "%s%s", hostname, ".tmp"); if ((fspice_output =fopen(lkk ,"wt")) == 0) { /*netlist to simulate given by 'hostname' */ printf("errfunc.c - Step7 -- Cannot write to tmp file: %s\n", lkk); exit(EXIT_FAILURE); } while (!P_eof(fspice_input)) { /* reads from <hostname>.mc and writes to <hostname>.tmp */ fgets2(lkk, LONGSTRINGSIZE, fspice_input); /* read line from <hostname>.mc */ strcpy(laux, lkk); Str2Lower(laux); fprintf(fspice_output, "%s\n", lkk); /* write line to <hostname>.tmp */ } fclose(fspice_input); fclose(fspice_output); AlterMC=AlterMC-1; /*decrease by one; nothing more will be executed*/ break; case 2: /*Alter simulation - variable 'AlterMC'=2*/ case 3: /*Alter simulation - variable 'AlterMC'=3 and will execute a MonteCarlo simulation afterwards*/ /* bla bla bla*/ printf("INFO: errfunc.c - Step7 -- altermc=%d\n", AlterMC); fflush(stdout); if (LOG) { sprintf(laux, "%s.log", hostname); if ((fspice_log=fopen(laux,"at")) == 0) { printf("errfunc.c - Step7 -- Cannot open log file: %s\n", laux); exit(EXIT_FAILURE); } fprintf(fspice_log, "Alter: 2 - altermc=%d\n", AlterMC); fclose(fspice_log); } sprintf(lkk, "%s%s", hostname, ".tmp"); /*hostname is "longmorn"*/ if ((fspice_tmp =fopen(lkk ,"r+t")) == 0) { /*netlist to simulate given by "hostname"*/ printf("errfunc.c - Step7 -- Cannot read from tmp file: %s\n", lkk); exit(EXIT_FAILURE); } if ((fspice_log =fopen("alter.inc" ,"rt")) == 0) { /*If file 'alter.inc' does not exist */ strcpy (filename_x, filename); strcat(filename_x, ".cfg"); CreateALTERinc(filename_x, lkk, 1); /*execute the 'alter' tool*/ fseek(fspice_tmp, 0, SEEK_END); /*properly position the pointer*/ } else { /* file 'alter.inc', so use it instead of the 'alter' tool */ #ifndef __MINGW32__ fseek(fspice_tmp, -5, SEEK_END); /*properly position the pointer*/ #else fseek(fspice_tmp, -6, SEEK_END); /*properly position the pointer*/ #endif fprintf(fspice_tmp, ".INCLUDE alter.inc\n"); /*write*/ fclose(fspice_log); } /* fseek(fspice_tmp, 0, SEEK_END); */ /*properly position the pointer*/ fprintf(fspice_tmp, ".end\n"); /*add ".end"*/ fclose(fspice_tmp); AlterMC=AlterMC-2; /*decrease by two; it will not execute a Monte Carlo simulation next time if equal to zero*/ break; default: printf("errfunc.c - Step7 -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } } /**/ /*Step8: return maximum cost (ALTER on MONTECARLO)*/ #ifdef DEBUG printf("DEBUG: errfunc.c - Step8\n"); #endif return (maxcost); }
/* * update the *.lis file with the state of the transistor */ void UpdateLIS(char *ConfigFile, char *InputFile) { int i, j, k; char ltitle[LONGSTRINGSIZE]; /*title: found .alter @*/ char lelement[LONGSTRINGSIZE]; /*lmodel,*/ /*transistor/model name*/ char lVGS[LONGSTRINGSIZE], lVDS[LONGSTRINGSIZE], lVth[LONGSTRINGSIZE], lVDSAT[LONGSTRINGSIZE], fileLJR[LONGSTRINGSIZE]; FILE *fLJR; /**.ljr*/ FILE *fLIS, *fNoSat; FILE *fsweepINI; /*skip: array [1..100] of string [20];*/ /*100 transistor to skip*/ char laux[LONGSTRINGSIZE]; double Vovd, Voff, Vdst; /*overdrive, off and 'Vds-Vdsat' voltage read from sweep.ini file*/ ThreeLines stats; fNoSat = NULL; fLIS = NULL; fLJR = NULL; if ((fLIS=fopen(InputFile,"rt")) == 0) { printf("auxfunc_updatelis.c - Cannot open input file: %s\n", InputFile); exit(EXIT_FAILURE); } sprintf(fileLJR, "%.*sjr", (int)(strlen(InputFile) - 2), InputFile); if ((fLJR=fopen(fileLJR,"wt")) == 0) { printf("auxfunc_updatelis.c - Cannot open input file: %s\n", fileLJR); exit(EXIT_FAILURE); } if ((fNoSat=fopen(NoSat,"wt")) == 0) { printf("auxfunc_updatelis.c - Cannot open input file: %s\n", NoSat); exit(EXIT_FAILURE); } for (i = 0; i < SKIPTRAN; i++) /*INITIALIZE: read transistors to skip*/ *skip[i] = '\0'; if ((fsweepINI=fopen(ConfigFile,"rt")) == 0) { printf("auxfunc_updatelis.c - Cannot open input file: %s\n", ConfigFile); exit(EXIT_FAILURE); } ReadKey(lkk, "SKIP_NOSAT", fsweepINI); j = strpos2(lkk, "$", 1); if (j != 0) /*This will skip the characters after '$', the inline comment used by the sweep tools*/ lkk[j-1]='\0'; StripSpaces(lkk); k = 1; if (!lkk[0]) printf("INFO: auxfunc_updatelis.c - 'SKIP_NOSAT' not found\n"); else { while (!strcmp((sprintf(laux, "%.10s", lkk), laux), "SKIP_NOSAT")) { /*read SKIP_NOSAT from file*/ i = 1; lkk[10] = ';'; while (i < (int)strlen(lkk)) { ReadSubKey(laux, lkk, &i, ';', ';', 0); StripSpaces(laux); strcpy(skip[k - 1], laux); k++; if (k == SKIPTRAN) { printf("auxfunc_updatelis.c - Maximum number of %d transistors to skip reached. Increase SKIPTRAN in auxfunc_updatelis\n", SKIPTRAN); exit(EXIT_FAILURE); } } ReadKey(lkk, "SKIP_NOSAT", fsweepINI); j = strpos2(lkk, "$", 1); if (j != 0) /*This will skip the characters after '$', the inline comment used by the sweep tools*/ lkk[j-1]='\0'; StripSpaces(lkk); } } Vovd = 0.05; /*default OVERDRIVE VOLTAGE value is 50mV*/ fseek(fsweepINI, 0, SEEK_SET); ReadKey(lkk, "VOVD", fsweepINI); if (strcmp((sprintf(laux, "%.4s", lkk), laux), "VOVD")) printf("INFO: auxfunc_updatelis.c - No Vovd, default value (50mV) will be used instead\n"); else { i = 1; i = (sscanf(ReadSubKey(laux, lkk, &i, ':', 'm', 5), "%lg", &Vovd) == 0); if (i) { /*if (i=0) then laux contains a number and not text*/ printf("auxfunc_updatelis.c - Incorrect format: number must exist in '%s'\n", lkk); exit(EXIT_FAILURE); } Vovd /= 1000; /*the following line will print information about the symbols in 'fNoSat' file*/ fprintf(fNoSat, "` `:weak inversion if Vgs<Vth+%smV\n", laux); } Voff = 0.1; /*default OFF VOLTAGE value is 100mV*/ fseek(fsweepINI, 0, SEEK_SET); ReadKey(lkk, "VOFF", fsweepINI); if (strcmp((sprintf(laux, "%.4s", lkk), laux), "VOFF")) printf("INFO: auxfunc_updatelis.c - No Voff: default value (100mV) will be used instead\n"); else { i = 1; i = (sscanf(ReadSubKey(laux, lkk, &i, ':', 'm', 5), "%lg", &Voff) == 0); if (i) { /*if (i=0) then laux contains a number and not text*/ printf("auxfunc_updatelis.c - Incorrect format: number must exist in '%s'\n", lkk); exit(EXIT_FAILURE); } Voff /= 1000; } Vdst = 0.0; /*default DST VOLTAGE value is 000mV*/ fseek(fsweepINI, 0, SEEK_SET); ReadKey(lkk, "VDST", fsweepINI); if (strcmp((sprintf(laux, "%.4s", lkk), laux), "VDST")) printf("INFO: auxfunc_updatelis.c - No Vdst: default value (0mV) will be used instead\n"); else { i = 1; i = (sscanf(ReadSubKey(laux, lkk, &i, ':', 'm', 5), "%lg", &Vdst) == 0); /*read 'Vds-Vdsat' from file*/ if (i) {/*if (i=0) then laux contains a number and not text*/ printf("auxfunc_updatelis.c - Incorrect format: number must exist in '%s'\n", lkk); exit(EXIT_FAILURE); } Vdst /= 1000; /*the following lines will print information about the symbols in 'fNoSat' file*/ if (Vdst != 0) fprintf(fNoSat, "`#`:Vds<Vdsat+%smV\n", laux); fprintf(fNoSat, "`*`:Vds<Vdsat\n\n"); } if (fsweepINI != NULL) fclose(fsweepINI); fsweepINI = NULL; /* */ /* */ *ltitle = '\0'; while (!P_eof(fLIS)) { switch(spice) { case 1: /* Eldo */ while ((strcmp((sprintf(laux, "%.37s", lkk), laux), "0**** OPERATING POINT") != 0) & (!P_eof(fLIS))) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); StripSpaces(lkk); /*required due to Solaris OS*/ //if (lkk[0] == '@' && strcmp(lkk, ltitle)) { if (strpos2(lkk, " .ALTER @", 1) !=0) { fprintf(fNoSat, "%s | ", lkk); strcpy(ltitle, lkk); } } sprintf(laux, "%.37s", lkk); if (!strcmp(laux, "0**** OPERATING POINT")) { for (i = 1; i <= 6; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } while ( (strpos2(lkk, " M", 1) != 0) || (strpos2(lkk, " X", 1) != 0)) { /*find operating region for all transistors*/ strcpy(lelement, lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); //if (strpos2(lkk, "region", 1) !=0) { /* Due to HSPICE 2001.2 line */ // fgets2(lkk, LONGSTRINGSIZE, fLIS); // fprintf(fLJR, "%s\n", lkk); /* with the operation region */ //} /* fgets2(lkk, LONGSTRINGSIZE, fLIS); */ /* fprintf(fLJR, "%s\n", lkk); */ fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVGS, LONGSTRINGSIZE, fLIS); /*Vgs*/ fprintf(fLJR, "%s\n", lVGS); fgets2(lVDS, LONGSTRINGSIZE, fLIS); /*Vds*/ fprintf(fLJR, "%s\n", lVDS); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); fgets2(lVDSAT, LONGSTRINGSIZE, fLIS); /*Vdsat*/ fprintf(fLJR, "%s\n", lVDSAT); for (i = 1; i <= 24; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } DoCalculations(lelement, lVGS, lVDS, lVth, lVDSAT, Vovd, Voff, Vdst, stats, &fNoSat); /*gets three lines with operating region*/ fprintf(fLJR, "%s\n", stats[0]); fprintf(fLJR, "%s\n", stats[1]); fprintf(fLJR, "%s\n\n\n", stats[2]); for (i = 1; i <= 2; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); if (i > 1) fprintf(fLJR, "%s\n", lkk); } } putc('\n', fNoSat); } break; case 2: /* HSPICE */ i=0; while ((strcmp((sprintf(laux, "%.12s", lkk), laux), "**** mosfets") != 0) & (!P_eof(fLIS))) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); StripSpaces(lkk); /*required due to Solaris OS*/ if (lkk[0] == '@' && strcmp(lkk, ltitle)) { if (i>0) { fprintf(fNoSat, "\n"); } i++; fprintf(fNoSat, "%s | ", lkk); strcpy(ltitle, lkk); } } sprintf(laux, "%.12s", lkk); if (!strcmp(laux, "**** mosfets")) { for (i = 1; i <= 4; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } while (strpos2(lkk, "element ", 1) != 0) { /*find operating region for all transistors*/ strcpy(lelement, lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); if (strpos2(lkk, "region", 1) !=0) { /* Due to HSPICE 2001.2 line */ fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); /* with the operation region */ } fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVGS, LONGSTRINGSIZE, fLIS); /*Vgs*/ fprintf(fLJR, "%s\n", lVGS); fgets2(lVDS, LONGSTRINGSIZE, fLIS); /*Vds*/ fprintf(fLJR, "%s\n", lVDS); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); fgets2(lVDSAT, LONGSTRINGSIZE, fLIS); /*Vdsat*/ fprintf(fLJR, "%s\n", lVDSAT); for (i = 1; i <= 12; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } DoCalculations(lelement, lVGS, lVDS, lVth, lVDSAT, Vovd, Voff, Vdst, stats, &fNoSat); /*gets three lines with operating region*/ fprintf(fLJR, "%s\n", stats[0]); fprintf(fLJR, "%s\n", stats[1]); fprintf(fLJR, "%s\n\n\n", stats[2]); for (i = 1; i <= 4; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); if (i > 2) fprintf(fLJR, "%s\n", lkk); } } putc('\n', fNoSat); } break; case 3: /* LTspice */ while ((strcmp((sprintf(laux, "%.21s", lkk), laux), "--- BSIM3 MOSFETS ---") != 0) & (!P_eof(fLIS))) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); StripSpaces(lkk); /*required due to Solaris OS*/ if (lkk[0] == '@' && strcmp(lkk, ltitle)) { fprintf(fNoSat, "%s | ", lkk); strcpy(ltitle, lkk); } } sprintf(laux, "%.21s", lkk); if (!strcmp(laux, "--- BSIM3 MOSFETS ---")) { for (i = 1; i <= 1; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } while (strpos2(lkk, "Name: ", 1) != 0) { /*find operating region for all transistors*/ strcpy(lelement, lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); //fgets2(lkk, LONGSTRINGSIZE, fLIS); //fprintf(fLJR, "%s\n", lkk); //if (strpos2(lkk, "region", 1) !=0) { /* Due to HSPICE 2001.2 line */ // fgets2(lkk, LONGSTRINGSIZE, fLIS); // fprintf(fLJR, "%s\n", lkk); /* with the operation region */ //} //fgets2(lkk, LONGSTRINGSIZE, fLIS); //fprintf(fLJR, "%s\n", lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVGS, LONGSTRINGSIZE, fLIS); /*Vgs*/ fprintf(fLJR, "%s\n", lVGS); fgets2(lVDS, LONGSTRINGSIZE, fLIS); /*Vds*/ fprintf(fLJR, "%s\n", lVDS); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); fgets2(lVDSAT, LONGSTRINGSIZE, fLIS); /*Vdsat*/ fprintf(fLJR, "%s\n", lVDSAT); for (i = 1; i <= 17; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } DoCalculations(lelement, lVGS, lVDS, lVth, lVDSAT, Vovd, Voff, Vdst, stats, &fNoSat); /*gets three lines with operating region*/ fprintf(fLJR, "%s\n", stats[0]); fprintf(fLJR, "%s\n", stats[1]); fprintf(fLJR, "%s\n\n", stats[2]); for (i = 1; i <= 2; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); if (i > 1) fprintf(fLJR, "%s\n", lkk); } } putc('\n', fNoSat); } break; case 4: /* Spectre */ // in input.scs put "dcOp dc oppoint=logfile" // run spectre with "spectre input.scs =log input.lis" // // Code specific for "Primitive: bsim3v3" and is quite possible // not to work on future Spectre versions and other transistor models // while ((strcmp((sprintf(laux, "%.31s", lkk), laux), "operating-point information `dc") != 0) & (!P_eof(fLIS))) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); StripSpaces(lkk); /*required due to Solaris OS*/ if (lkk[0] == '@' && strcmp(lkk, ltitle)) { fprintf(fNoSat, "%s | ", lkk); strcpy(ltitle, lkk); } Str2Lower(lkk); //required because versions until 2007 have "... Information" and after have "... information" } if (P_eof(fLIS)) break; char l1[LONGSTRINGSIZE], l2[LONGSTRINGSIZE]; /*l1 and l2 are hold places for previous lines*/ fgets2(l1, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", l1); fgets2(l2, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", l2); /*bsim3v3*/ while ((strcmp((sprintf(laux, "%.18s", lkk), laux), "Primitive: bsim3v3") != 0) & (!P_eof(fLIS))) { /*bsim4*/ // while ((strcmp((sprintf(laux, "%.16s", lkk), laux), "Primitive: bsim4") != 0) & (!P_eof(fLIS))) { strcpy(l1, l2); strcpy(l2, lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); StripSpaces(lkk); if (lkk[0] == '@' && strcmp(lkk, ltitle)) { fprintf(fNoSat, "%s | ", lkk); strcpy(ltitle, lkk); } } /*bsim3v3*/ sprintf(laux, "%.18s", lkk); /*bsim3v3*/ if (!strcmp(laux, "Primitive: bsim3v3")) { /*bsim4*/ // sprintf(laux, "%.16s", lkk); /*bsim4*/ // if (!strcmp(laux, "Primitive: bsim4")) { for (i = 1; i <= 0; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } /*bsim3v3*/ while (strpos2(lkk, "Primitive: bsim3v3", 1) != 0) { /*find operating region for all transistors*/ /*bsim4*/ // while (strpos2(lkk, "Primitive: bsim4", 1) != 0) { /*find operating region for all transistors*/ strcpy(lelement, l1); if (strpos2(lelement, " of ", 1)) { /*to remove the library name if and when it appears*/ lelement[strpos2(lelement, " of ", 1)]='\0'; } /*bsim3v3*/ for (i = 1; i <= 9; i++) { /*bsim4*/ // for (i = 1; i <= 7; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } fgets2(lVGS, LONGSTRINGSIZE, fLIS); /*Vgs*/ fprintf(fLJR, "%s\n", lVGS); { i=1; ReadSubKey(laux, lVGS, &i, '=', 'V', 5); i=strpos2(laux, " ", 2); if ((laux[i]==109)) { /* 109=m; mV */ laux[i-1]='\0'; strcat(laux, "e-3"); } if ((laux[i]==117)) { /* 117=u; uV */ laux[i-1]='\0'; strcat(laux, "e-6"); } if ((laux[i]==110)) { /* 110=n; nV */ laux[i-1]='\0'; strcat(laux, "e-9"); } sprintf(lVGS, " %s", laux); /* Puts the value on the expected column for DoCalculations */ } fgets2(lVDS, LONGSTRINGSIZE, fLIS); /*Vds*/ fprintf(fLJR, "%s\n", lVDS); { i=1; ReadSubKey(laux, lVDS, &i, '=', 'V', 5); i=strpos2(laux, " ", 2); if ((laux[i]==109)) { /* 109=m; mV */ laux[i-1]='\0'; strcat(laux, "e-3"); } if ((laux[i]==117)) { /* 117=u; uV */ laux[i-1]='\0'; strcat(laux, "e-6"); } if ((laux[i]==110)) { /* 110=n; nV */ laux[i-1]='\0'; strcat(laux, "e-9"); } sprintf(lVDS, " %s", laux); /* Puts the value on the expected column for DoCalculations */ } fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); { //begin -- required for versions after the 2nd half of 2006 who have 3 more lines in between "vds" and "vth" if (!strpos2(lVth, "vth =", 1)) { fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); fgets2(lVth, LONGSTRINGSIZE, fLIS); /*Vth*/ fprintf(fLJR, "%s\n", lVth); } if (!strpos2(lVth, "vth =", 1)) { /*Double-check just to be sure that vth was found*/ printf("auxfunc_updatelis.c - Spectre netlist format not supported\n"); exit(EXIT_FAILURE); } } //end -- required for versions after the 2nd half of 2006 who have 3 more lines in between "vds" and "vth" { i=1; ReadSubKey(laux, lVth, &i, '=', 'V', 5); i=strpos2(laux, " ", 2); if ((laux[i]==109)) { /* 109=m; mV */ laux[i-1]='\0'; strcat(laux, "e-3"); } if ((laux[i]==117)) { /* 117=u; uV */ laux[i-1]='\0'; strcat(laux, "e-6"); } if ((laux[i]==110)) { /* 110=n; nV */ laux[i-1]='\0'; strcat(laux, "e-9"); } sprintf(lVth, " %s", laux); /* Puts the value on the expected column for DoCalculations */ } fgets2(lVDSAT, LONGSTRINGSIZE, fLIS); /*Vdsat*/ fprintf(fLJR, "%s\n", lVDSAT); { i=1; ReadSubKey(laux, lVDSAT, &i, '=', 'V', 5); i=strpos2(laux, " ", 2); if ((laux[i]==109)) { /* 109=m; mV */ laux[i-1]='\0'; strcat(laux, "e-3"); } if ((laux[i]==117)) { /* 117=u; uV */ laux[i-1]='\0'; strcat(laux, "e-6"); } if ((laux[i]==110)) { /* 110=n; nV */ laux[i-1]='\0'; strcat(laux, "e-9"); } sprintf(lVDSAT, " %s", laux); /* Puts the value on the expected column for DoCalculations */ } for (i = 1; i <= 45; i++) { fgets2(lkk, LONGSTRINGSIZE, fLIS); fprintf(fLJR, "%s\n", lkk); } { //begin -- required for versions after the 2nd half of 2006 who have 3 more lines in between "vds" and "vth" fgets2(lkk, LONGSTRINGSIZE, fLIS); //fprintf(fLJR, "%s\n", lkk); //if ((int)(strlen(InputFile))) { /*empty line has been found, goes ahead*/ // i=0; //} while (strpos2(lkk, " = ", 1)) { /*empty line has been found, goes ahead*/ fprintf(fLJR, "%s\n", lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); } } //end -- required for versions after the 2nd half of 2006 who have 3 more lines in between "vds" and "vth" DoCalculations(lelement, lVGS, lVDS, lVth, lVDSAT, Vovd, Voff, Vdst, stats, &fNoSat); /*gets three lines with operating region*/ fprintf(fLJR, "%s\n", stats[0]); fprintf(fLJR, "%s\n", stats[1]); fprintf(fLJR, "%s\n\n", stats[2]); for (i = 1; i <= 3; i++) { strcpy(l1, l2); strcpy(l2, lkk); fgets2(lkk, LONGSTRINGSIZE, fLIS); if (i > 0) fprintf(fLJR, "%s\n", lkk); } } putc('\n', fNoSat); } break; case 50: /*Qucs*/ printf("auxfunc_updatelis.c - UpdateLIS -- Updatelis not implemente for Qucs\n"); exit(EXIT_FAILURE); case 100: /* rosen */ printf("auxfunc_updatelis.c - UpdateLIS -- Updatelis not implemente for rosen\n"); exit(EXIT_FAILURE); break; default: printf("auxfunc_updatelis.c - UpdateLIS -- Something unexpected has happened!\n"); exit(EXIT_FAILURE); } } if (fLIS != NULL) fclose(fLIS); fLIS = NULL; if (fLJR != NULL) fclose(fLJR); fLJR = NULL; if (fNoSat != NULL) fclose(fNoSat); fNoSat = NULL; if (fLJR != NULL) fclose(fLJR); if (fLIS != NULL) fclose(fLIS); if (fNoSat != NULL) fclose(fNoSat); } /*UpdateLIS*/
void CreateStatistics(char *InputFile, char *OutputFile) { int i, j, k; char lkk1[LONGSTRINGSIZE], llog[LONGSTRINGSIZE]; statistics stats; FILE *fIn, *fOut, *fcfg; double aux; int num_measures; /* ------------------------------------------------------------------ ------------------------------------------------------------------ */ /*create summary: table version*/ for (i = 0; i <= (MAXMEAS-1); i++) { stats.avg[i] = 0.0; /*initialization of statistics variables*/ stats.sig[i] = 0.0; stats.max[i] = -1.7e38; stats.min[i] = 1.7e38; } if ((fIn=fopen(InputFile,"rt")) == 0) { printf("auxfunc_log.c - Cannot open input file: %s\n", InputFile); exit(EXIT_FAILURE); } if ((fOut=fopen(OutputFile,"wt")) == 0) { printf("auxfunc_log.c - Cannot open output file: %s\n", OutputFile); exit(EXIT_FAILURE); } fgets2(lkk, LONGSTRINGSIZE, fIn); if (P_eof(fIn)) /*if there is only 1 line*/ fseek(fIn, 0, SEEK_SET); strsub(lkk1, lkk, 1, strpos2(lkk, ":", 1)-1); i=0; j=1; k=0; while (!P_eof(fIn)) { aux = asc2real(lkk1, 1, (int)strlen(lkk1)); stats.avg[i] += aux; stats.sig[i] += aux * aux; /*variancia=sum(x^2)/n - (avg(x))^2 # sigma=sqrt(variancia)*/ if (aux > stats.max[i]) stats.max[i] = aux; if (aux < stats.min[i]) stats.min[i] = aux; if (j==(int)strlen(lkk)) { num_measures=i; i=0;j=1;k++; fgets2(lkk, LONGSTRINGSIZE, fIn); strsub(lkk1, lkk, 1, strpos2(lkk, ":", 1)-1); } else { ReadSubKey(lkk1, lkk, &j, ':', ':', 1); i++; j--; } } WriteStats(num_measures-1, k, stats, &fOut); /* -- */ i=0; dd_ffblk fb; char *mask="*.cfg"; if (!dd_findfirst( mask, &fb, DD_DIREC )) { /*Find first file having extension .cfg */ if (!strcmp(fb.dd_name, "rfmodule.cfg")) /*and make sure that it is not rfmodule.cfg*/ i=dd_findnext(&fb); /*otherwise find next .cfg file */ if (i==0) printf("Opening config file: %s\n", fb.dd_name); } /* -- */ fprintf(fOut, "\n\n# Parameters #\n"); /*--------*/ strcpy(llog,lkk); /*last line from log file*/ fcfg=NULL; if ((fcfg=fopen(fb.dd_name,"rt")) == 0) { if (fb.dd_name) { printf("auxfunc_log.c - Cannot open config file: %s\n", fb.dd_name); /*exit(EXIT_FAILURE);*/ } SimpleParametersCategory(num_measures-1, llog, stats, &fOut); } else { ReadKey(lkk, "# Parameters #", fcfg); /*configuration parameters*/ if (strcmp(lkk, "# Parameters #")) { printf("INFO: auxfunc_log.c - Step2 -- No parameters in config file\n"); SimpleParametersCategory(num_measures-1, llog, stats, &fOut); } else { ComplexParametersCategory(llog, stats, &fOut, &fcfg); } } /*--------*/ fprintf(fOut, "#\n"); if (fOut != NULL) fclose(fOut); fOut = NULL; if (fIn != NULL) fclose(fIn); fIn = NULL; /* ------------------------------------------------------------------ ------------------------------------------------------------------ */ }