From 8dc8bb950be310018e3c9f2829baf1b611296fdf Mon Sep 17 00:00:00 2001 From: stefanjones Date: Tue, 10 Aug 2004 23:28:45 +0000 Subject: [PATCH] cl --- ChangeLog | 25 + src/frontend/Makefile.am | 2 + src/frontend/com_measure.c | 943 ++++++++++++++++++++++++++++++ src/frontend/com_measure.h | 10 + src/frontend/commands.c | 5 + src/include/cktdefs.h | 4 + src/measure.tcl | 86 ++- src/nodeDialog.tcl | 45 +- src/pkgIndex.tcl.in | 9 +- src/spicelib/devices/Makefile.am | 3 +- src/spicelib/devices/cktcrte.c | 9 +- src/spicelib/devices/cktfinddev.c | 26 +- src/spicelib/devices/cktinit.c | 2 + src/spicelib/devices/names.c | 290 +++++++++ src/spicelib/devices/names.h | 62 ++ src/spicepp.pl.in | 32 +- src/spicewish | 12 +- src/spicewish.tcl | 10 +- src/tclspice.c | 60 ++ src/viewer.tcl | 72 ++- 20 files changed, 1648 insertions(+), 59 deletions(-) create mode 100644 src/frontend/com_measure.c create mode 100644 src/frontend/com_measure.h create mode 100644 src/spicelib/devices/names.c create mode 100644 src/spicelib/devices/names.h diff --git a/ChangeLog b/ChangeLog index 8e01f7127..845a3e371 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2004-08-10 Adrian Dawe + + * src/measure.tcl + src/nodeDialog.tcl + src/pkgIndex.tcl.in + src/spicepp.pl.in + src/spicewish + src/spicewish.tcl + src/tclspice.c + src/viewer.tcl + src/frontend/Makefile.am + src/frontend/com_measure.c + src/frontend/com_measure.h + src/frontend/commands.c + src/include/cktdefs.h + src/spicelib/devices/Makefile.am + src/spicelib/devices/cktcrte.c + src/spicelib/devices/cktfinddev.c + src/spicelib/devices/cktinit.c + src/spicelib/devices/names.c + src/spicelib/devices/names.h: + Added hash table for circuit elements + Update TCL gui + Added measure command + 2004-08-04 Stefan Jones * src/tclspice.c: diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am index 86edb8421..62e4ef85b 100644 --- a/src/frontend/Makefile.am +++ b/src/frontend/Makefile.am @@ -39,6 +39,8 @@ libfte_a_SOURCES = \ com_dl.h \ com_plot.c \ com_plot.h \ + com_measure.c \ + com_measure.h \ com_rehash.c \ com_set.c \ com_set.h \ diff --git a/src/frontend/com_measure.c b/src/frontend/com_measure.c new file mode 100644 index 000000000..13ed62b97 --- /dev/null +++ b/src/frontend/com_measure.c @@ -0,0 +1,943 @@ +#include +#include + +#include +#include + +#include "vectors.h" +#include + +#ifdef TCL_MODULE + +typedef struct measure +{ + char *result; + + char *m_vec; // name of the output variable which determines the beginning of the measurement + char *m_vec2; + int m_rise; + int m_fall; + int m_cross; + float m_val; // value of the m_ver at which the counter for crossing, rises or falls is incremented by one + float m_td; // amount of delay before the measurement should start + float m_from; + float m_to; + float m_at; + float m_measured; + float m_measured_at; + +} measure; + +enum AnalysisType { + AT_DELAY, AT_TRIG, + AT_FIND, AT_WHEN, + AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP, + AT_INTEG, AT_DERIV, + AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3 +}; + +void com_measure_when(struct measure *meas) { + + int i, first; + int riseCnt =0; + int fallCnt =0; + int crossCnt =0; + int section = -1; + float value, prevValue; + float timeValue, prevTimeValue; + + enum ValSide { S_ABOVE_VAL, S_BELOW_VAL }; + enum ValEdge { E_RISING, E_FALLING }; + + struct dvec *d, *dTime; + + d = vec_get(meas->m_vec); + dTime = plot_cur->pl_scale; + + if (d == NULL) { + fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); + return; + } + + if (dTime == NULL) { + fprintf(cp_err, "Error: no such vector as time.\n"); + return; + } + + prevValue =0; + prevTimeValue =0; + first =0; + + for (i=0; i < d->v_length; i++) { + + value = d->v_realdata[i]; + timeValue = dTime->v_realdata[i]; + + if (timeValue < meas->m_td) + continue; + + if (first == 1) { + // initialise + crossCnt =0; + if (value < meas->m_val) { + section = S_BELOW_VAL; + if ( (prevValue <= meas->m_val) && (value >= meas->m_val) ) { + fallCnt =1; + crossCnt =1; + } + + } else { + section = S_ABOVE_VAL; + if ( (prevValue <= meas->m_val) && (value >= meas->m_val) ) { + riseCnt =1; + crossCnt =1; + } + } + printf(""); + } + + if (first > 1) { + + if ( (section == S_BELOW_VAL) && (value >= meas->m_val) ) { + section = S_ABOVE_VAL; + crossCnt++; + riseCnt++; + + } else if ( (section == S_ABOVE_VAL) && (value <= meas->m_val) ) { + section = S_BELOW_VAL; + crossCnt++; + fallCnt++; + } + + if ((crossCnt == meas->m_cross) || (riseCnt == meas->m_rise) || (fallCnt == meas->m_fall)) { + meas->m_measured = prevTimeValue + (meas->m_val - prevValue) * (timeValue - prevTimeValue) / (value - prevValue); + return; + + } + } + first ++; + + prevValue = value; + prevTimeValue = timeValue; + } + + meas->m_measured = 0.0e0; + return; +} + +void measure_at(struct measure *meas, float at) { + + int i; + float value, pvalue, svalue, psvalue; + struct dvec *d, *dScale; + + psvalue = pvalue = 0; + d = vec_get(meas->m_vec); + dScale = plot_cur->pl_scale; + + if (d == NULL) { + fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); + return; + } + + if (dScale == NULL) { + fprintf(cp_err, "Error: no such vector time.\n"); + return; + } + + for (i=0; i < d->v_length; i++) { + value = d->v_realdata[i]; + svalue = dScale->v_realdata[i]; + + if ( (i > 0) && (psvalue <= at) && (svalue >= at) ) { + meas->m_measured = pvalue + (at - psvalue) * (value - pvalue) / (svalue - psvalue); + // meas->m_measured = value; + return; + } + + psvalue = svalue; + pvalue = value; + } + + meas->m_measured = 0.0e0; + return; +} + +void measure_avg( ) { + // AVG (Average): + // Calculates the area under the 'out_var' divided by the periods of intrest + return; +} + +void measure_minMaxAvg( struct measure *meas, int minMax ) { + + int i, avgCnt; + struct dvec *d, *dScale; + float value, svalue, mValue, mValueAt; + int first; + + mValue =0; + mValueAt = svalue =0; + meas->m_measured = 0.0e0; + meas->m_measured_at = 0.0e0; + first =0; + avgCnt =0; + + d = vec_get(meas->m_vec); + if (d == NULL) { + fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); + return; + } + + dScale = vec_get("time"); + if (d == NULL) { + fprintf(cp_err, "Error: no such vector as time.\n"); + return; + } + + for (i=0; i < d->v_length; i++) { + value = d->v_realdata[i]; + svalue = dScale->v_realdata[i]; + + if (svalue < meas->m_from) + continue; + + if ((meas->m_to != 0.0e0) && (svalue > meas->m_to) ) + break; + + if (first ==0) { + mValue = value; + mValueAt = svalue; + first =1; + + } else { + switch (minMax) { + case AT_MIN: { + if (value <= mValue) { + mValue = value; + mValueAt = svalue; + } + break; + } + case AT_MAX: { + if (value >= mValue) { + mValue = value; + mValueAt = svalue; + } + break; + } + case AT_AVG: + case AT_RMS: { + mValue = mValue + value; + avgCnt ++; + break; + } + } + + } + } + + switch (minMax) + { + case AT_AVG: { + meas->m_measured = (mValue / avgCnt); + meas->m_measured_at = svalue; + break; + } + case AT_RMS: { + // printf(" mValue %e svalue %e avgCnt %i, ", mValue, svalue, avgCnt); + meas->m_measured = sqrt(mValue) / avgCnt; + meas->m_measured_at = svalue; + break; + } + case AT_MIN: + case AT_MAX: { + meas->m_measured = mValue; + meas->m_measured_at = mValueAt; + break; + } + } + + return; +} + +void measure_rms( ) { + // RMS (root mean squared): + // Calculates the square root of the area under the 'out_var2' curve + // divided be the period of interest + return; +} + +void measure_integ( ) { + // INTEGRAL INTEG + return; +} + +void measure_deriv( ) { + // DERIVATIVE DERIV + return; +} + +// ERR Equations +void measure_ERR( ) { + return; +} + +void measure_ERR1( ) { + return; +} + +void measure_ERR2( ) { + return; +} + +void measure_ERR3( ) { + return; +} + +void measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg) { + + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s %s(%s) :\n", mName, mFunction, trigTarg); + printf("\t%s\n",errMsg); + return; +} + +void com_dotmeasure( ) { + + // simulation info +// printf("*%s\n", plot_cur->pl_title); +// printf("\t %s, %s\n", plot_cur->pl_name, plot_cur->pl_date); // missing temp + + return; +} + +int measure_valid_vector(char *vec) { + + struct dvec *d; + + d = vec_get(vec); + if (d == NULL) + return 0; + + return 1; +} + +int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBreak, char *errbuf) { + + int pCnt; + char *p, *pName, *pValue; + double *engVal, engVal1; + + pCnt =0; + while (wl != wlBreak) { + p = wl->wl_word; + pName = strtok(p, "="); + pValue = strtok(NULL, "="); + + if (pValue == NULL) { + sprintf(errbuf,"bad syntax of ??\n"); + return 0; + } + + if (!(engVal = ft_numparse(&pValue, FALSE))) { + sprintf(errbuf,"bad syntax of ??\n"); + return 0; + } + + engVal1 = *engVal; + + if(strcasecmp(pName,"RISE")==0) { + meas->m_rise = engVal1; + meas->m_fall = -1; + meas->m_cross = -1; + } else if(strcasecmp(pName,"FALL")==0) { + meas->m_fall = engVal1; + meas->m_rise = -1; + meas->m_cross = -1; + } else if(strcasecmp(pName,"CROSS")==0) { + meas->m_cross = engVal1; + meas->m_rise = -1; + meas->m_fall = -1; + } else if(strcasecmp(pName,"VAL")==0) { + meas->m_val = engVal1; + } else if(strcasecmp(pName,"TD")==0) { + meas->m_td = engVal1; + } else if(strcasecmp(pName,"FROM")==0) { + meas->m_from = engVal1; + } else if(strcasecmp(pName,"TO")==0) { + meas->m_to = engVal1; + } else if(strcasecmp(pName,"AT")==0) { + meas->m_at = engVal1; + } else { + sprintf(errbuf,"no such parameter as '%s'\n",pName); + return 0; + } + + pCnt ++; + wl = wl->wl_next; + } + + if (pCnt == 0) { + sprintf(errbuf,"bad syntax of ??\n"); + return 0; + } + + // valid vector + if (measure_valid_vector(meas->m_vec)==0) { + sprintf(errbuf,"no such vector as '%s'\n", meas->m_vec); + return 0; + } + + // valid vector2 + if (meas->m_vec2 != NULL) { + if (measure_valid_vector(meas->m_vec2)==0) { + sprintf(errbuf,"no such vector as '%s'\n", meas->m_vec2); + return 0; + } + } + + return 1; +} + +int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, char *errbuf) { + + int pCnt; + char *p, *pName, *pVal; + double *engVal, engVal1; + + meas->m_vec = NULL; + meas->m_vec2 = NULL; + meas->m_val = -1; + meas->m_cross = -1; + meas->m_fall = -1; + meas->m_rise = -1; + meas->m_td = 0; + meas->m_from = 0.0e0; + meas->m_to = 0.0e0; + meas->m_at = -1; + + pCnt =0; + while(wl != wlBreak) { + p = wl->wl_word; + + if (pCnt == 0 ) { +// meas->m_vec =(char *)malloc(strlen(wl->wl_word)+1); + // strcpy(meas->m_vec, cp_unquote(wl->wl_word)); + meas->m_vec= cp_unquote(wl->wl_word); + } else if (pCnt == 1) { + + pName = strtok(p, "="); + pVal = strtok(NULL, "="); + + if (pVal == NULL) { + sprintf(errbuf,"bad syntax of WHEN\n"); + return 0; + } + + if (strcasecmp(pName,"AT")==0) { + + if (!(engVal = ft_numparse(&pVal, FALSE))) { + sprintf(errbuf,"bad syntax of WHEN\n"); + return 0; + } + + engVal1 = *engVal; + + meas->m_at = engVal1; + + } else { + sprintf(errbuf,"bad syntax of WHEN\n"); + return 0; + } + } else { + if (measure_parse_stdParams(meas, wl, NULL, errbuf) == 0) + return 0; + } + + wl = wl->wl_next; + pCnt ++; + } + + return 1; +} + +int measure_parse_when (struct measure *meas, wordlist *wl, char *errBuf) { + + int pCnt; + char *p, *pVar1, *pVar2; + + meas->m_vec = NULL; + meas->m_vec2 = NULL; + meas->m_val = -1; + meas->m_cross = -1; + meas->m_fall = -1; + meas->m_rise = -1; + meas->m_td = 0; + meas->m_from = 0.0e0; + meas->m_to = 0.0e0; + meas->m_at = -1; + + pCnt =0; + while (wl) { + p= wl->wl_word; + + if (pCnt == 0) { + pVar1 = strtok(p, "="); + pVar2 = strtok(NULL, "="); + + if (pVar2 == NULL) { + sprintf(errBuf,"bad syntax\n"); + return 0; + } + + meas->m_vec = pVar1; + if (measure_valid_vector(pVar2)==1) + meas->m_vec2 = pVar2; + else + meas->m_val = atof(pVar2); + } else { + if (measure_parse_stdParams(meas, wl, NULL, errBuf) == 0) + return 0; + break; + } + + wl = wl->wl_next; + pCnt ++; + } + return 1; +} + + +int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlTarg, char *trigTarg, char *errbuf) { + + int pcnt; + char *p; + + meas->m_vec = NULL; + meas->m_vec2 = NULL; + meas->m_cross = -1; + meas->m_fall = -1; + meas->m_rise = -1; + meas->m_td = 0; + meas->m_from = 0.0e0; + meas->m_to = 0.0e0; + meas->m_at = -1; + + pcnt =0; + while (words != wlTarg) { + p = words->wl_word; + + if (pcnt ==0) { +// meas->m_vec =(char *)malloc(strlen(words->wl_word)+1); + // strcpy(meas->m_vec, cp_unquote(words->wl_word)); + meas->m_vec= cp_unquote(words->wl_word); + } else { + + if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0) + return 0; + break; + + } + + words = words->wl_next; + pcnt ++; + } + + if (pcnt == 0) { + sprintf(errbuf,"bad syntax of '%s'\n", trigTarg); + return 0; + } + + // valid vector + if (measure_valid_vector(meas->m_vec)==0) { + sprintf(errbuf,"no such vector as '%s'\n", meas->m_vec); + return 0; + } + + return 1; +} + +float +get_measure(wordlist *wl) +{ + wordlist *words, *wlTarg, *wlWhen; + char errbuf[100]; + char *mType = NULL; // analysis type + char *mName = NULL; // name given to the measured output + char *mFunction = NULL; + int mFunctionType, wl_cnt; + char *p; + + mFunctionType = -1; + + if (!wl) { + printf("usage: measure .....\n"); + return 0.0e0; + } + + if (!plot_cur || !plot_cur->pl_dvecs || !plot_cur->pl_scale) { + fprintf(cp_err, "Error: no vectors available\n"); + return 0.0e0; + } + + if (!ciprefix("tran", plot_cur->pl_typename)) { + fprintf(cp_err, "Error: measure limited to transient analysis\n"); + return 0.0e0; + } + + words =wl; + wlTarg = NULL; + wlWhen = NULL; + + if (!words) { + fprintf(cp_err, "Error: no assignment found.\n"); + return 0.0e0; + } + + wl_cnt = 0; + while (words) { + + switch(wl_cnt) + { + case 0: + mType = cp_unquote(words->wl_word); + break; + case 1: + mName = cp_unquote(words->wl_word); + break; + case 2: + { + mFunction = cp_unquote(words->wl_word); + // Functions + if (strcasecmp(mFunction,"DELAY")==0) + mFunctionType = AT_DELAY; + else if (strcasecmp(mFunction,"TRIG")==0) + mFunctionType = AT_DELAY; + else if (strcasecmp(mFunction,"FIND")==0) + mFunctionType = AT_FIND; + else if (strcasecmp(mFunction,"WHEN")==0) + mFunctionType = AT_WHEN; + else if (strcasecmp(mFunction,"AVG")==0) + mFunctionType = AT_AVG; + else if (strcasecmp(mFunction,"MIN")==0) + mFunctionType = AT_MIN; + else if (strcasecmp(mFunction,"MAX")==0) + mFunctionType = AT_MAX; + else if (strcasecmp(mFunction,"RMS")==0) + mFunctionType = AT_RMS; + else if (strcasecmp(mFunction,"PP")==0) + mFunctionType = AT_PP; + else if (strcasecmp(mFunction,"INTEG")==0) + mFunctionType = AT_INTEG; + else if (strcasecmp(mFunction,"DERIV")==0) + mFunctionType = AT_DERIV; + else if (strcasecmp(mFunction,"ERR")==0) + mFunctionType = AT_ERR; + else if (strcasecmp(mFunction,"ERR1")==0) + mFunctionType = AT_ERR1; + else if (strcasecmp(mFunction,"ERR2") == 0) + mFunctionType = AT_ERR2; + else if (strcasecmp(mFunction,"ERR3") == 0) + mFunctionType = AT_ERR3; + else { + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s :\n", mName); + printf("\tno such function as '%s'\n", mFunction); + return 0.0e0; + } + break; + } + default: + { + p = words->wl_word; + + if (strcasecmp(p,"targ")==0) + wlTarg = words; + + if (strcasecmp(p,"when")==0) + wlWhen = words; + + break; + } + } + wl_cnt ++; + words = words->wl_next; + } + + if (wl_cnt < 3) { + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s :\n", mName); + printf("\tinvalid num params\n"); + return 0.0e0; + } + + //------------------------ + + + words =wl; + + if (words) + words = words->wl_next; // skip + if (words) + words = words->wl_next; // results name + if (words) + words = words->wl_next; // Function + + + // switch here + switch(mFunctionType) + { + case AT_DELAY: + case AT_TRIG: + { + // trig parameters + measure *measTrig, *measTarg; + measTrig = (struct measure*)malloc(sizeof(struct measure)); + measTarg = (struct measure*)malloc(sizeof(struct measure)); + + if (measure_parse_trigtarg(measTrig, words , wlTarg, "trig", errbuf)==0) { + measure_errMessage(mName, mFunction, "TRIG", errbuf); + return 0.0e0; + } + + if ((measTrig->m_rise == -1) && (measTrig->m_fall == -1) && (measTrig->m_cross == -1)) { + sprintf(errbuf,"rise, fall or cross must be given\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf); + return 0.0e0; + } + + while (words != wlTarg) + words = words->wl_next; // hack + + if (words) + words = words->wl_next; // skip targ + + if (measure_parse_trigtarg(measTarg, words , NULL, "targ", errbuf)==0) { + measure_errMessage(mName, mFunction, "TARG", errbuf); + return 0.0e0; + } + + if ((measTarg->m_rise == -1) && (measTarg->m_fall == -1) && (measTarg->m_cross == -1)) { + sprintf(errbuf,"rise, fall or cross must be given\n"); + measure_errMessage(mName, mFunction, "TARG", errbuf); + return 0.0e0; + } + + // measure trig + if (measTrig->m_at == -1) + com_measure_when(measTrig); + else + measTrig->m_measured = measTrig->m_at; + + + if (measTrig->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf); + return 0.0e0; + } + // measure targ + com_measure_when(measTarg); + + if (measTarg->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TARG", errbuf); + return 0.0e0; + } + + // print results + printf("%-20s= %e targ= %e trig= %e\n", mName, (measTarg->m_measured - measTrig->m_measured), measTarg->m_measured, measTrig->m_measured); + + return (measTarg->m_measured - measTrig->m_measured); + } + case AT_FIND: + { + measure *meas, *measFind; + meas = (struct measure*)malloc(sizeof(struct measure)); + measFind = (struct measure*)malloc(sizeof(struct measure)); + + if (measure_parse_find(meas, words, wlWhen, errbuf) == 0) { + measure_errMessage(mName, mFunction, "FIND", errbuf); + return 0.0e0; + } + + if (meas->m_at == -1 ) { + // find .. when statment + + while (words != wlWhen) + words = words->wl_next; // hack + + if (words) + words = words->wl_next; // skip targ + + if (measure_parse_when(measFind, words, errbuf) ==0) { + measure_errMessage(mName, mFunction, "WHEN", errbuf); + return 0.0e0; + } + + com_measure_when(measFind); + + if (measFind->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "WHEN", errbuf); + return 0.0e0; + } + + measure_at(measFind, measFind->m_measured); + meas->m_measured = measFind->m_measured; + + } else { + measure_at(meas, meas->m_at); + } + + if (meas->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "WHEN", errbuf); + return 0.0e0; + } + + // print results + printf("%-20s= %e\n", mName, meas->m_measured); + return meas->m_measured; + } + case AT_WHEN: + { + measure *meas; + meas = (struct measure*)malloc(sizeof(struct measure)); + + if (measure_parse_when(meas, words, errbuf) ==0) { + measure_errMessage(mName, mFunction, "WHEN", errbuf); + return 0.0e0; + } + + com_measure_when(meas); + + if (meas->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "WHEN", errbuf); + return 0.0e0; + } + + // print results + printf("%-20s= %e\n", mName, meas->m_measured); + + return (meas->m_measured); + } + case AT_RMS: + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s :\n", mName); + printf("\tfunction '%s' currently not supported\n", mFunction); + break; + case AT_AVG: + { + // trig parameters + measure *meas; + meas = (struct measure*)malloc(sizeof(struct measure)); + + if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) { + measure_errMessage(mName, mFunction, "TRIG", errbuf); + return 0.0e0; + } + + // measure + measure_minMaxAvg(meas, mFunctionType); + + if (meas->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf); // ?? + return 0.0e0; + } + + if (meas->m_at == -1) + meas->m_at = 0.0e0; + + // print results + printf("%-20s= %e from= %e to= %e\n", mName, meas->m_measured, meas->m_at, meas->m_measured_at); + return meas->m_measured; + + } + case AT_MIN: + case AT_MAX: + { + // trig parameters + measure *measTrig; + measTrig = (struct measure*)malloc(sizeof(struct measure)); + + if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { + measure_errMessage(mName, mFunction, "TRIG", errbuf); + return 0.0e0; + } + + // measure + if (mFunctionType == AT_MIN) + measure_minMaxAvg(measTrig, AT_MIN); + else + measure_minMaxAvg(measTrig, AT_MAX); + + + if (measTrig->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf); // ?? + return 0.0e0; + } + + // print results + printf("%-20s= %e at= %e\n", mName, measTrig->m_measured, measTrig->m_measured_at); + return measTrig->m_measured; + } + case AT_PP: + { + float minValue, maxValue; + + measure *measTrig; + measTrig = (struct measure*)malloc(sizeof(struct measure)); + + if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { + measure_errMessage(mName, mFunction, "TRIG", errbuf); + return 0.0e0; + } + + // measure min + measure_minMaxAvg(measTrig, AT_MIN); + if (measTrig->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf); // ?? + return 0.0e0; + } + minValue = measTrig->m_measured; + + // measure max + measure_minMaxAvg(measTrig, AT_MAX); + if (measTrig->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf); // ?? + return 0.0e0; + } + maxValue = measTrig->m_measured; + + // print results + printf("%-20s= %e from= %e to= %e\n", mName, (maxValue - minValue), measTrig->m_from, measTrig->m_to); + return (maxValue - minValue); + } + case AT_INTEG: + case AT_DERIV: + case AT_ERR: + case AT_ERR1: + case AT_ERR2: + case AT_ERR3: + { + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s :\n", mName); + printf("\tfunction '%s' currently not supported\n", mFunction); + break; + } + } + return 0.0e0; +} + +void com_measure(wordlist *wl) { + get_measure(wl); + return; +} + +#endif diff --git a/src/frontend/com_measure.h b/src/frontend/com_measure.h new file mode 100644 index 000000000..5c3605aec --- /dev/null +++ b/src/frontend/com_measure.h @@ -0,0 +1,10 @@ +#ifndef _COM_MEASURE_H +#define _COM_MEASURE_H + +#include +#ifdef TCL_MODULE +void com_measure(wordlist *wl); +float get_measure(wordlist *wl); +#endif + +#endif diff --git a/src/frontend/commands.c b/src/frontend/commands.c index da81b36d4..c6f795e0f 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -48,6 +48,7 @@ #include "com_setscale.h" #include "com_xgraph.h" #include "com_state.h" +#include "com_measure.h" #include "fourier.h" #ifdef EXPERIMENTAL_CODE @@ -116,6 +117,10 @@ struct comm spcp_coms[] = { { 041000, 041000, 041000, 041000 }, E_BEGINNING | E_HASPLOTS, 1, LOTS, arg_plot, "expr ... [vs expr] [xl xlo xhi] [yl ylo yhi] : Plot things." }, + { "measure", com_measure, FALSE, FALSE, TRUE, + { 041000, 041000, 041000, 041000 }, E_BEGINNING | E_HASPLOTS, 1, LOTS, + arg_plot, + "measure..." }, { "plot", com_bltplot, FALSE, FALSE, TRUE, { 041000, 041000, 041000, 041000 }, E_BEGINNING | E_HASPLOTS, 1, LOTS, arg_plot, diff --git a/src/include/cktdefs.h b/src/include/cktdefs.h index 8891fcbd7..d9406e289 100644 --- a/src/include/cktdefs.h +++ b/src/include/cktdefs.h @@ -258,6 +258,10 @@ typedef struct { #endif /* gtri - evt - wbk - 5/20/91 - add event-driven and enhancements data */ + + void *element_lookup_table; /* names_t * maps strings to pointers to GENELEMENTS */ + + } CKTcircuit; /* Now function prottypes */ diff --git a/src/measure.tcl b/src/measure.tcl index 5b710d06e..24b78714b 100644 --- a/src/measure.tcl +++ b/src/measure.tcl @@ -313,5 +313,89 @@ namespace eval meas_markers { bind $w { spicewish::meas_markers::riseTime %W.g %x %y } bind $w { spicewish::meas_markers::propDelay %W.g %x %y} } - +} + + + + +namespace eval motionMeasure { + + variable measInfo + + proc create { graph } { + eval "bind $graph { [namespace current]::SetMeasPoint %W %x %y }" + eval "bind $graph { [namespace current]::removeMarker %W }" + } + + proc InitVars { graph } { + variable measInfo + set measInfo($graph,A,x) {} + set measInfo($graph,A,y) {} + set measInfo($graph,B,x) {} + set measInfo($graph,B,y) {} + set measInfo($graph,corner) A + } + + proc removeMarker { graph } { + variable measInfo + bind $graph {} + $graph marker delete "zoomOutlineV" + $graph marker delete "zoomOutlineH" + } + + proc SetMeasPoint { graph x y } { + variable measInfo + + if { ![info exists measInfo($graph,corner)] } { + InitVars $graph + } + GetCoords $graph $x $y $measInfo($graph,corner) + + eval "bind $graph { [namespace current]::GetCoords %W %x %y B; [namespace current]::Box %W }" + } + + proc GetCoords { graph x y index } { + variable measInfo + if { [$graph cget -invertxy] } { + set measInfo($graph,$index,x) $y + set measInfo($graph,$index,y) $x + + } else { + set measInfo($graph,$index,x) $x + set measInfo($graph,$index,y) $y + } + } + + proc Box { graph } { + variable measInfo + if { $measInfo($graph,A,x) > $measInfo($graph,B,x) } { + set x1 [$graph xaxis invtransform $measInfo($graph,B,x)] + set y1 [$graph yaxis invtransform $measInfo($graph,B,y)] + set x2 [$graph xaxis invtransform $measInfo($graph,A,x)] + set y2 [$graph yaxis invtransform $measInfo($graph,A,y)] + } else { + set x1 [$graph xaxis invtransform $measInfo($graph,A,x)] + set y1 [$graph yaxis invtransform $measInfo($graph,A,y)] + set x2 [$graph xaxis invtransform $measInfo($graph,B,x)] + set y2 [$graph yaxis invtransform $measInfo($graph,B,y)] + } + set coords { $x1 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x1 $y1 } + if { [$graph marker exists "zoomOutlineV"] } { + $graph marker configure "zoomOutlineV" -coords "$x1 $y1 $x1 $y2" + $graph marker configure "zoomOutlineH" -coords "$x1 $y2 $x2 $y2" + } else { + set X [lindex [$graph xaxis use] 0] + set Y [lindex [$graph yaxis use] 0] + + $graph marker create line -coords "$x1 $y1 $x1 $y2" -name "zoomOutlineV" -linewidth 2 + $graph marker create line -coords "$x1 $y2 $x2 $y2" -name "zoomOutlineH" -linewidth 2 + } + + set ::spicewish::viewer::meas_x1($graph) $x1 + set ::spicewish::viewer::meas_y1($graph) $y1 + set ::spicewish::viewer::meas_x2($graph) $x2 + set ::spicewish::viewer::meas_y2($graph) $y2 + set ::spicewish::viewer::meas_dx($graph) [expr $x2 - $x1] + set ::spicewish::viewer::meas_dy($graph) [expr $y2 - $y1] + } } diff --git a/src/nodeDialog.tcl b/src/nodeDialog.tcl index 39187c2e1..a48f082f6 100644 --- a/src/nodeDialog.tcl +++ b/src/nodeDialog.tcl @@ -6,6 +6,7 @@ namespace eval nodeDialog { variable selection variable selected "const" variable selectionCnt + variable vecFilter "" proc create { } { variable w @@ -21,7 +22,6 @@ namespace eval nodeDialog { wm title $w "Vectors" # Plot names - #pack [frame $w.plots] -fill x frame $w.plots pack [listbox $w.plots.lst -height 4 \ -width 50 \ @@ -34,7 +34,6 @@ namespace eval nodeDialog { ] -fill y -side right # vector names - #pack [frame $w.nodes] -fill both -expand 1 frame $w.nodes pack [blt::hierbox $w.nodes.hb -hideroot 1 \ -yscrollcommand {.nodeSelect.nodes.sx set} \ @@ -46,8 +45,14 @@ namespace eval nodeDialog { -command {.nodeSelect.nodes.hb yview} \ ] -fill y -side right + # vector Filter + frame $w.filter + pack [label $w.filter.l -text "Filter:"] -side left + pack [entry $w.filter.e \ + -textvariable spicewish::nodeDialog::vecFilter \ + ] -side left -expand 1 -fill x + # control frame - #pack [frame $w.fcont] -fill x frame $w.fcont pack [label $w.fcont.lselected -text "Selected: "] -side left pack [button $w.fcont.bNodeCnt -textvariable spicewish::nodeDialog::selectionCnt \ @@ -62,9 +67,10 @@ namespace eval nodeDialog { blt::table $w \ 0,0 $w.plots -fill x \ 1,0 $w.nodes -fill both \ - 2,0 $w.fcont -fill x + 2,0 $w.filter -fill x\ + 3,0 $w.fcont -fill x - blt::table configure $w r0 r2 -resize none + blt::table configure $w r0 r2 r3 -resize none # bindings $w.nodes.hb bind all { @@ -72,7 +78,7 @@ namespace eval nodeDialog { set index [$hierbox_path index current] set nodeName [$hierbox_path entry cget $index -label] set plotTypeName [spice::plot_typename [.nodeSelect.plots.lst curselection]] - set listPos [lsearch $::spicewish::nodeDialog::selection($plotTypeName) $nodeName] + set listPos [lsearch $::spicewish::nodeDialog::selection($plotTypeName) [spicewish::viewer::evaluate $nodeName]] if { [ $hierbox_path entry cget $index -labelcolor] == "black"} { $hierbox_path entry configure $index -labelcolor "blue" @@ -85,9 +91,7 @@ namespace eval nodeDialog { $hierbox_path entry configure $index -labelcolor "black" $hierbox_path configure -selectforeground black - set spicewish::nodeDialog::selection($plotTypeName) [lreplace $::spicewish::nodeDialog::selection($plotTypeName) $listPos $listPos] - - + set spicewish::nodeDialog::selection($plotTypeName) [lreplace $::spicewish::nodeDialog::selection($plotTypeName) $listPos $listPos] } set spicewish::nodeDialog::selectionCnt [llength $::spicewish::nodeDialog::selection($plotTypeName)] } @@ -100,6 +104,7 @@ namespace eval nodeDialog { bind $w.nodes.hb [list %W yview scroll 5 units] bind $w.nodes.hb [list %W yview scroll -5 units] + bind $w.filter.e { spicewish::nodeDialog::Update } wm protocol $w WM_TAKE_FOCUS { spicewish::nodeDialog::Update } Update @@ -112,7 +117,6 @@ namespace eval nodeDialog { set plotTypeName [spice::plot_typename $plotNum] if {$selection($plotTypeName) == ""} {return} - eval "spicewish::viewer::oplot $plotTypeName $selection($plotTypeName)" } @@ -190,19 +194,32 @@ namespace eval nodeDialog { proc populateTree { index } { + variable vecFilter + set w ".nodeSelect.nodes.hb" $w delete 0 set defaultScale [spice::plot_defaultscale $index] - foreach node [spice::plot_variables $index] { - set text ": [spicewish::vectors::type $index $node], real, [spice::plot_datapoints $index]" - if {$node == $defaultScale} { + set data [spice::plot_variablesInfo $index] + set data [lsort -dictionary $data] + + for {set i 0} {$i < [llength $data]} {incr i} { + set v_data [lindex $data $i] + set v_name [lindex $v_data 0] + set v_type [lindex $v_data 1] + set v_length [lindex $v_data 2] + + if {(![string match $vecFilter $v_name]) && ($vecFilter != "")} { continue } + + set text ": $v_type, real, $v_length" + if {$v_name == $defaultScale} { set text "$text \[default scale\]" } - $w insert -at 0 end $node -labelfont {times 9} -text $text -labelcolor "black" + $w insert -at 0 end $v_name -labelfont {times 9} -text $text -labelcolor "black" } + loadSelection } diff --git a/src/pkgIndex.tcl.in b/src/pkgIndex.tcl.in index ccff46f2f..62ec633e6 100755 --- a/src/pkgIndex.tcl.in +++ b/src/pkgIndex.tcl.in @@ -72,7 +72,7 @@ proc Loadspice { version dir } { puts "DefineLinestyle $linestyleid $mask" } - proc spice_init_gui { fileName {gui 0} {batchMode 0}} { + proc spice_init_gui { fileName {gui 0} {batchMode 0} {rawFileName ""}} { # source tclcode if {[info procs spicewish::plot] == ""} { @@ -94,8 +94,11 @@ proc Loadspice { version dir } { spice::source $fileName if {$batchMode} { - spice::run - spice::write out.raw + spice::run + if {$rawFileName != ""} { + spice::set filetype=binary + spice::write $rawFileName + } exit } } diff --git a/src/spicelib/devices/Makefile.am b/src/spicelib/devices/Makefile.am index 686187710..654fd840f 100644 --- a/src/spicelib/devices/Makefile.am +++ b/src/spicelib/devices/Makefile.am @@ -60,7 +60,8 @@ libdev_a_SOURCES = \ cktbindnode.c \ cktcrte.c \ cktfinddev.c \ - cktinit.c + cktinit.c \ + names.c INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices diff --git a/src/spicelib/devices/cktcrte.c b/src/spicelib/devices/cktcrte.c index 9ce11a073..69f12fb8c 100644 --- a/src/spicelib/devices/cktcrte.c +++ b/src/spicelib/devices/cktcrte.c @@ -11,8 +11,9 @@ Author: 1985 Thomas L. Quarles #include #include #include - +#include #include "dev.h" +#include "names.h" int CKTcrtElt(void *ckt, void *inModPtr, void **inInstPtr, IFuid name) @@ -60,5 +61,11 @@ CKTcrtElt(void *ckt, void *inModPtr, void **inInstPtr, IFuid name) if(inInstPtr != NULL) *inInstPtr = (void *)instPtr; + + { + names_t *np= ((CKTcircuit *)ckt)->element_lookup_table; + names_add(np,instPtr,(char*)(name)); + } + return OK; } diff --git a/src/spicelib/devices/cktfinddev.c b/src/spicelib/devices/cktfinddev.c index 66b29eb64..fb7650b68 100644 --- a/src/spicelib/devices/cktfinddev.c +++ b/src/spicelib/devices/cktfinddev.c @@ -6,7 +6,7 @@ Author: 1985 Thomas L. Quarles #include #include #include - +#include "names.h" int CKTfndDev(void *Ckt, int *type, void **fast, IFuid name, void *modfast, IFuid modname) @@ -24,6 +24,30 @@ CKTfndDev(void *Ckt, int *type, void **fast, IFuid name, void *modfast, IFuid mo return(OK); } + /* LOG(N) lookup code: Conrad Ziesler */ + { + GENinstance *p; + names_t *np= ((CKTcircuit *)Ckt)->element_lookup_table; + p= names_check(np,(char*)(name)); + if(p!=NULL) + { + if (modname == (char *)NULL || p->GENmodPtr->GENmodName == modname) { + + if (p->GENname == name) { + if (fast != 0) + *(GENinstance **)fast = p; + if(modfast) if (type) + *type = p->GENmodPtr->GENmodType; + return OK; + } + + } + } + return E_NODEV; + } + + + if(modfast) { /* have model, just need device */ mods = (GENmodel*)modfast; diff --git a/src/spicelib/devices/cktinit.c b/src/spicelib/devices/cktinit.c index bfd7d966a..9a2f9e178 100644 --- a/src/spicelib/devices/cktinit.c +++ b/src/spicelib/devices/cktinit.c @@ -14,6 +14,7 @@ Modifed: 2000 AlansFixes #include #include #include +#include "names.h" #ifdef XSPICE /* gtri - add - wbk - 11/26/90 - add include for MIF global data */ @@ -31,6 +32,7 @@ CKTinit(void **ckt) /* new circuit to create */ sckt = (CKTcircuit *)(*ckt); if (sckt == NULL) return(E_NOMEM); + sckt->element_lookup_table=names_new(); /* gtri - begin - dynamically allocate the array of model lists */ /* CKThead used to be statically sized in CKTdefs.h, but has been changed */ /* to a ** pointer */ diff --git a/src/spicelib/devices/names.c b/src/spicelib/devices/names.c new file mode 100644 index 000000000..871e51f31 --- /dev/null +++ b/src/spicelib/devices/names.c @@ -0,0 +1,290 @@ +/******************** + This file is part of the software library CADLIB written by Conrad Ziesler + Copyright 2003, Conrad Ziesler, all rights reserved. + +************************* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************/ +/* names.c, efficient string table support + Conrad Ziesler +*/ + + + +#include +#include +#include +#include +#include + +#define __NAMES_PRIVATE__ +#include "names.h" + +static namehash_t *names_newhash(names_t *nt, void * refp, const char *str) +{ + namehash_t *b; + int q=strlen(str); + b=malloc(sizeof(namehash_t)+q); + assert(b!=NULL); + b->refp=refp; + b->magic=NAME_MAGIC; + strcpy(b->str,str); + nt->bytesalloc+=sizeof(namehash_t)+q; + nt->namebytes+=q; + nt->qtynames++; + + return b; +} + + +static unsigned int names_ptrhash(names_t *nt, void * refp) +{ + unsigned q=nt->qtybins; + unsigned int v, r=0; + + v=(unsigned)refp; + /* + v>>=2; + r= ((v%(7*q+(q/3)+5))^v) % q; + */ + r= v ^ (v>>3) ^ ((v/3)>>15) ^ ((~v)>>11); + return r%q; +} + +static unsigned int names_strhash(names_t *nt, const char *str) +{ + unsigned q=nt->qtybins; + unsigned int r=0; + + while(*str!=0) + { + r+= (str[0]^(r%q)); + r%=q; + str++; + } + + return r%q; +} + + +char *names_lookup(names_t *nt, void * refp) +{ + unsigned int id; + namehash_t *nh; + int i=0; + + id=names_ptrhash(nt,refp); + + for(nh=nt->cref[id];nh!=NULL;nh=nh->cref,i++) + { + assert(nh->magic==NAME_MAGIC); + if(refp==nh->refp){ return nh->str; } + } + + return NULL; +} + +void * names_check(names_t *nt, const char *name) +{ + unsigned int id; + namehash_t *nh; + int i=0; + + id=names_strhash(nt,name); + + for(nh=nt->cstr[id];nh!=NULL;nh=nh->cstr,i++) + { + assert(nh->magic==NAME_MAGIC); + if(strcmp(name,nh->str)==0){ return nh->refp; } + } + return NULL; +} + + + +void names_add(names_t *nt, void * refp, const char *name) +{ + unsigned int idn,idr,id; + namehash_t *nh,*nhref=NULL,*nhstr=NULL; + int i=0; + + if(nt->qtynames>((5*nt->qtybins)/4)) /* double table size each time we outgrow old table */ + names_rehash(nt, (2*nt->qtynames) ); + + idn=names_strhash(nt,name); + idr=names_ptrhash(nt,refp); + + for(nh=nt->cref[idr];nh!=NULL;nh=nh->cref,i++) + { + assert(nh->magic==NAME_MAGIC); + if(refp==nh->refp){ nt->avg_refl=(nt->avg_refl+i)/2; nhref=nh; break; } + } + + for(nh=nt->cstr[idn];nh!=NULL;nh=nh->cstr,i++) + { + assert(nh->magic==NAME_MAGIC); + if(strcmp(name,nh->str)==0){ nt->avg_strl=(nt->avg_strl+i)/2; nhstr=nh; break; } + } + + if(nhstr==NULL) /* adding new name entry */ + { + if(nhref!=NULL) /* but refp was the same */ + { + fprintf(stderr,"**** DUPLICATE KEY NAME ****\n"); + if(1)assert(0&&"duplicate key in names"); + } + + nh=names_newhash(nt, refp, name); + nh->cstr=nt->cstr[idn]; + nt->cstr[idn]=nh; + nh->cref=nt->cref[idr]; + nt->cref[idr]=nh; + } + else /* replacing old name entry */ + { + namehash_t *prev=NULL; + assert(0 && "Replacing strings in names has a bug. do not use"); + /* lookup refp of old name and unlink */ + id=names_ptrhash(nt,nhstr->refp); + for(nh=nt->cref[id];nh!=NULL;prev=nh,nh=nh->cref,i++) + if(nhstr->refp==nh->refp) + { + if(prev==NULL)nt->cref[id]=nh->cref; + else prev->cref=nh->cref; + break; + } + /* relink new name, refp */ + nhstr->refp=refp; + nhstr->cref=nt->cref[idr]; + nt->cref[idr]=nhstr; + } +} + +char * names_stats(names_t *nt) +{ + static char buf[1024]; + int i,qs=0,qp=0,ms=0,mp=0,j,ks=0,kp=0; + namehash_t *nh; + + for(i=0;iqtybins;i++) + { + + for(j=0,nh=nt->cstr[i];nh!=NULL;nh=nh->cstr,j++) assert(nh->magic==NAME_MAGIC); + if(j>0)ks++; + if(mscref[i];nh!=NULL;nh=nh->cref,j++) assert(nh->magic==NAME_MAGIC); + if(mp0)kp++; + qp+=j; + } + + qp/=kp; + qs/=ks; + + sprintf(buf,"names: %i bins (%i totaling %i) , alloc %i, avg: %i %i max: %i %i",nt->qtybins,nt->qtynames,nt->namebytes,nt->bytesalloc,qp,qs,mp,ms); + + return buf; +} + + + +/* this should optimize our hash table for memory usage */ +void names_rehash(names_t *nt, int newbins) +{ + int i; + int oldqty; + namehash_t *hp; + + oldqty=nt->qtybins; + nt->qtybins=newbins; + + nt->bytesalloc+= ( (newbins-oldqty)*sizeof(void *)*2 ); + /* do cref first, using cstr */ + if(nt->cref!=NULL) + free(nt->cref); + nt->cref=malloc(sizeof(void *)*(nt->qtybins+1)); + assert(nt->cref!=NULL); + memset(nt->cref,0,sizeof(void*)*nt->qtybins); + + /* iterate through list of string hashes, adding to ref hashes */ + for(i=0;icstr[i];hp!=NULL;hp=hp->cstr) + { + unsigned id; + id=names_ptrhash(nt,hp->refp); + hp->cref=nt->cref[id]; + nt->cref[id]=hp; + } + + /* next do cstr, using new cref */ + if(nt->cstr!=NULL) + free(nt->cstr); + nt->cstr=malloc(sizeof(void *)*(nt->qtybins+1)); + assert(nt->cstr!=NULL); + memset(nt->cstr,0,sizeof(void*)*nt->qtybins); + + for(i=0;iqtybins;i++) + for(hp=nt->cref[i];hp!=NULL;hp=hp->cref) + { + unsigned id; + id=names_strhash(nt,hp->str); + hp->cstr=nt->cstr[id]; + nt->cstr[id]=hp; + } +} + + + +names_t *names_new(void) +{ + names_t *p; + p=malloc(sizeof(names_t)); + assert(p!=NULL); + memset(p,0,sizeof(names_t)); + p->bytesalloc=sizeof(names_t); + p->namebytes=0; + p->qtynames=0; + p->avg_strl=0; + p->avg_refl=0; + + p->qtybins=0; + p->cstr=NULL; + p->cref=NULL; + names_rehash(p,13); /* start small, grow bigger */ + return p; +} + +void names_free(names_t *nt) +{ + int i; + namehash_t *nh,*next; + if(nt!=NULL) + { + for(i=0;iqtybins;i++) + { + for(nh=nt->cstr[i];nh!=NULL;nh=next) + { + assert(nh->magic==NAME_MAGIC); + next=nh->cstr; + free(nh); + } + } + free(nt->cstr); + free(nt->cref); + free(nt); + } +} diff --git a/src/spicelib/devices/names.h b/src/spicelib/devices/names.h new file mode 100644 index 000000000..54fc73c9a --- /dev/null +++ b/src/spicelib/devices/names.h @@ -0,0 +1,62 @@ +/******************** + This file is part of the software library CADLIB written by Conrad Ziesler + Copyright 2003, Conrad Ziesler, all rights reserved. + +************************* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************/ +/* names.h, definitions for name storage + Conrad Ziesler +*/ + +#ifndef __NAMES_H__ +#define __NAMES_H__ +#ifdef __NAMES_PRIVATE__ + +#define NAME_MAGIC 0x52a01250 +typedef struct name_hash_st +{ + int magic; + struct name_hash_st *cref,*cstr; + void * refp; + char str[1]; +}namehash_t; + +typedef struct names_st +{ + namehash_t **cref,**cstr; + int avg_refl; + int avg_strl; + int qtybins; + int qtynames; + int namebytes; + int bytesalloc; +}names_t; +#else + +struct names_st; +typedef struct names_st names_t; +#endif + +char *names_stats(names_t *nt); +char *names_lookup(names_t *nt, void * refp); +void * names_check(names_t *nt, const char *name); +void names_add(names_t *nt, void * refp, const char *name); +names_t *names_new(void); +void names_free(names_t *nt); +void names_rehash(names_t *nt, int newbins); /* private-ish */ + +#endif diff --git a/src/spicepp.pl.in b/src/spicepp.pl.in index f01158674..2ebf3a97e 100755 --- a/src/spicepp.pl.in +++ b/src/spicepp.pl.in @@ -639,7 +639,7 @@ sub change_models { sub change_instances { - local($i,$model,$l,$w,$p,$ad,$as,$pd,$ps); + local($i,$model,$l,$w,$p,$m,$ad,$as,$pd,$ps); for ($i=0;$i<@deck;$i++) { $_ = $deck[$i]; if(/^m\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)/) { @@ -677,6 +677,10 @@ sub change_instances { next; model_found: #W & L mangling and acm stuff + #Get m + if($deck[$i] =~ s/(.*)\bm\s*=\s*([0-9]+)\b(.*)/$1$3/){ + $m = $2;}else {$m = 1;} + #get and remove pd, ps, ad, as if($deck[$i] =~ s/(.*)\bpd\s*=\s*(\S+)\b(.*)/$1$3/){ $pd = &unit($2); @@ -699,7 +703,7 @@ sub change_instances { }else{ $ad = 0;} #Calculate Leff and Weff - $w = ($w * $$model{"wmlt"} + $$model{"xw"}); + $w = $m * ($w * $$model{"wmlt"} + $$model{"xw"}); $l = $l * $$model{"lmlt"} + $$model{"xl"}; #Now do the ACM stuff...... @@ -709,10 +713,10 @@ sub change_instances { #calculated using hspice methods.. if( $$model{"acm"} == 0){ #pg 869, 19-33 - $ad = $ad * $$model{"wmlt"} * $$model{"wmlt"}; - $as = $as * $$model{"wmlt"} * $$model{"wmlt"}; - $pd = $pd * $$model{"wmlt"}; - $ps = $ps * $$model{"wmlt"}; + $ad = $m * $ad * $$model{"wmlt"} * $$model{"wmlt"}; + $as = $m * $as * $$model{"wmlt"} * $$model{"wmlt"}; + $pd = $m * $pd * $$model{"wmlt"}; + $ps = $m * $ps * $$model{"wmlt"}; } @@ -725,23 +729,23 @@ sub change_instances { elsif( $$model{"acm"} == 2){ #pg 874, 19-39 if($ad){ - $ad = $ad * $$model{"wmlt"} * $$model{"wmlt"}; + $ad = $ad * $m * $$model{"wmlt"} * $$model{"wmlt"}; }else { $ad = 2 * $$model{"hdif"} * $w;} if($as){ - $as = $as * $$model{"wmlt"} * $$model{"wmlt"}; + $as = $m * $as * $$model{"wmlt"} * $$model{"wmlt"}; }else{ $as = 2 * $$model{"hdif"} * $w;} if($pd){ - $pd = $pd * $$model{"wmlt"}; + $pd = $m * $pd * $$model{"wmlt"}; }else { $pd = 4 * $$model{"hdif"} + 2 * $w; } if($ps){ - $ps = $ps * $$model{"wmlt"}; + $ps = $m * $ps * $$model{"wmlt"}; }else{ $ps = 4 * $$model{"hdif"} + 2 * $w; } @@ -750,7 +754,7 @@ sub change_instances { elsif( $$model{"acm"} == 3){ #pg 879, 19-43 if($ad){ - $ad = $ad * $$model{"wmlt"} * $$model{"wmlt"};} + $ad = $m * $ad * $$model{"wmlt"} * $$model{"wmlt"};} elsif($$model{"geo"} == 0 || $$model{"geo"} == 2){ $ad = 2 * $$model{"hdif"} * $w; }else{ @@ -758,7 +762,7 @@ sub change_instances { } if($as){ - $as = $as * $$model{"wmlt"} * $$model{"wmlt"};} + $as = $m * $as * $$model{"wmlt"} * $$model{"wmlt"};} elsif($$model{"geo"} == 0 || $$model{"geo"} == 1){ $as = 2 * $$model{"hdif"} * $w; }else{ @@ -766,7 +770,7 @@ sub change_instances { } if($pd){ - $pd = $pd * $$model{"wmlt"};} + $pd = $m * $pd * $$model{"wmlt"};} elsif($$model{"geo"} == 0 || $$model{"geo"} == 2){ $pd = 4 * $$model{"hdif"} + $w; }else{ @@ -774,7 +778,7 @@ sub change_instances { } if($ps){ - $ps = $ps * $$model{"wmlt"};} + $ps = $m * $ps * $$model{"wmlt"};} elsif($$model{"geo"} == 0 || $$model{"geo"} == 1){ $ps = 4 * $$model{"hdif"} + $w; }else{ diff --git a/src/spicewish b/src/spicewish index 9e34df484..0268729a7 100755 --- a/src/spicewish +++ b/src/spicewish @@ -1,8 +1,8 @@ -# +#!/bin/sh # 22/6/04 -ad # the next line starts SpiceWish interactively with the given file name \ -exec wish "$0" "$@" +exec wish "$0" "$@" package require spice package require tclreadline @@ -41,6 +41,7 @@ proc run_spicepp { fileName } { proc spicewish_load { argv argc } { set fileName "" + set rawFileName "" set mode_batch 0 set mode_spicePP 0 @@ -57,7 +58,8 @@ proc spicewish_load { argv argc } { break } -h - -help { spicewish_usage } - -b { set ::mode_batch 1 } + -b { set mode_batch 1 } + -r { set rawFileName $val; incr i} -version { spice::version; exit } -pp { set mode_spicePP 1 } default { spicewish_usage } @@ -68,7 +70,7 @@ proc spicewish_load { argv argc } { } if {$fileName == "" } { - spice_init_gui "" 0 $mode_batch + spice_init_gui "" 0 $mode_batch $rawFileName return } @@ -78,7 +80,7 @@ proc spicewish_load { argv argc } { set fileName [ run_spicepp $fileName ] } - spice_init_gui $fileName 0 $mode_batch + spice_init_gui $fileName 0 $mode_batch $rawFileName } proc Tclreadline { } { diff --git a/src/spicewish.tcl b/src/spicewish.tcl index 1539a367c..cd90da33a 100644 --- a/src/spicewish.tcl +++ b/src/spicewish.tcl @@ -20,7 +20,13 @@ namespace eval spicewish { spicewish::nodeDialog::create return } - eval spicewish::viewer::plot $args + + set l "" + foreach p $args { + set l "$l\\\"[spicewish::viewer::evaluate $p]\\\" " + } + #eval spice::bltplot $l + eval spice::bltplot $args } proc gui { } { @@ -106,7 +112,7 @@ proc spice_gr_Plot { args } { set yType [lindex $args 4] set yUnits [lindex $args 5] set viewerCnt [lindex $args 6] - + set plotNum [spicewish::vectors::get_plotNum [spice::getplot]] if {$spicewish::viewer::vecUpdate_flag} { diff --git a/src/tclspice.c b/src/tclspice.c index 26cc1b779..8dff035f3 100755 --- a/src/tclspice.c +++ b/src/tclspice.c @@ -76,6 +76,7 @@ typedef pthread_t threadId_t; #include #include +#include #ifndef HAVE_GETRUSAGE #ifdef HAVE_FTIME @@ -667,6 +668,39 @@ static int plot_variables TCL_CMDPROCARGS(clientData,interp,argc,argv) { } return TCL_OK; } + +static int plot_variablesInfo TCL_CMDPROCARGS(clientData,interp,argc,argv){ + + struct plot *pl; + int plot; + struct dvec *v; + char buf[256]; + char *name; + int length; + + if (argc != 2) { + Tcl_SetResult(interp, "Wrong # args. spice::plot_variablesInfo plot",TCL_STATIC); + return TCL_ERROR; + } + + plot = atoi(argv[1]); + + if(!(pl = get_plot(plot))){ + Tcl_SetResult(interp,"Bad plot given",TCL_STATIC); + return TCL_ERROR; + } + + Tcl_ResetResult(interp); + for(v = pl->pl_dvecs;v;v = v->v_next){ + name = v->v_name; + length = v->v_length; + + sprintf(buf,"{%s %s %i} ",name, ft_typenames(v->v_type), length); + Tcl_AppendResult(interp, (char *)buf, TCL_STATIC); + } + return TCL_OK; +} + /*returns the value of a variable */ static int plot_get_value TCL_CMDPROCARGS(clientData,interp,argc,argv) { @@ -1947,6 +1981,29 @@ static int listTriggers TCL_CMDPROCARGS(clientData,interp,argc,argv){ return TCL_OK; } +static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){ + + wordlist *wl= NULL; + float mvalue; + + if (argc <= 2) { + Tcl_SetResult(interp, "Wrong # args. spice::listTriggers",TCL_STATIC); + return TCL_ERROR; + } + + wl =wl_build(argv); + + mvalue = get_measure(wl); + + printf(" %e \n", mvalue); + + Tcl_ResetResult(spice_interp); + + Tcl_SetObjResult(interp,Tcl_NewDoubleObj((double) mvalue)); + + return TCL_OK; +} + /*******************************************************/ /* Initialise spice and setup native methods */ @@ -2080,6 +2137,7 @@ bot: Tcl_CreateCommand(interp, TCLSPICE_prefix "delta", delta, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, TCLSPICE_prefix "maxstep", maxstep, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_variables", plot_variables, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_variablesInfo", plot_variablesInfo, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_get_value", plot_get_value, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_datapoints", plot_datapoints, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, TCLSPICE_prefix "plot_title", plot_title, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); @@ -2104,6 +2162,8 @@ bot: Tcl_CreateCommand(interp, TCLSPICE_prefix "running", running, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); #endif + Tcl_CreateCommand(interp, TCLSPICE_prefix "tmeasure", tmeasure, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, TCLSPICE_prefix "registerStepCallback", registerStepCallback, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_LinkVar(interp, TCLSPICE_prefix "steps_completed", (char *)&steps_completed, TCL_LINK_READ_ONLY|TCL_LINK_INT); diff --git a/src/viewer.tcl b/src/viewer.tcl index 4f8e1dcff..902f52363 100644 --- a/src/viewer.tcl +++ b/src/viewer.tcl @@ -56,8 +56,14 @@ namespace eval viewer { blt::table configure $w r0 r2 c0 c2 r3 -resize none # graph settings - Blt_ZoomStack $w.g - Blt_Crosshairs $w.g + Blt_Crosshairs $w.g + if {0} { + Blt_ZoomStack $w.g + } else { + blt::ZoomStack $w.g "ButtonPress-3" "ButtonPress-2" + blt::ZoomStack $w.g "ButtonPress-3" "Shift-ButtonPress-3" + } + $w.g grid on $w.g axis configure x -command { spicewish::viewer::axis_callback } -subdivisions 2 @@ -68,6 +74,8 @@ namespace eval viewer { eval "wm protocol $w WM_DELETE_WINDOW {spicewish::viewer::Destroy $w}" + bind $w { spicewish::viewer::Update } + incr viewCnt return [expr $viewCnt -1] } @@ -120,17 +128,25 @@ namespace eval viewer { pack [ label $w_meas.x1 -text "x1 :" -background "grey" ] -side right bind $w_meas.x1v { regexp {(.[0-9A-z]+)} %W w; puts "x1 : $::spicewish::viewer::meas_x1($w.g)"} - # cursor motion bindings - bind $w.g { - if { $::zoomInfo(%W,B,x) != "" } { - set ::spicewish::viewer::meas_x2(%W) [%W xaxis invtransform $::zoomInfo(%W,B,x)] - set ::spicewish::viewer::meas_y2(%W) [%W yaxis invtransform $::zoomInfo(%W,B,y)] - set ::spicewish::viewer::meas_x1(%W) [%W xaxis invtransform $::zoomInfo(%W,A,x)] - set ::spicewish::viewer::meas_y1(%W) [%W yaxis invtransform $::zoomInfo(%W,A,y)] - set ::spicewish::viewer::meas_dx(%W) [expr ($::spicewish::viewer::meas_x2(%W) - $::spicewish::viewer::meas_x1(%W))] - set ::spicewish::viewer::meas_dy(%W) [expr ($::spicewish::viewer::meas_y2(%W) - $::spicewish::viewer::meas_y1(%W))] - } - } + if {1} { + catch {::spicewish::motionMeasure::create $w.g} + + } else { + + # cursor motion bindings + bind $w.g { + if { $::zoomInfo(%W,B,x) != "" } { + set ::spicewish::viewer::meas_x2(%W) [%W xaxis invtransform $::zoomInfo(%W,B,x)] + set ::spicewish::viewer::meas_y2(%W) [%W yaxis invtransform $::zoomInfo(%W,B,y)] + set ::spicewish::viewer::meas_x1(%W) [%W xaxis invtransform $::zoomInfo(%W,A,x)] + set ::spicewish::viewer::meas_y1(%W) [%W yaxis invtransform $::zoomInfo(%W,A,y)] + set ::spicewish::viewer::meas_dx(%W) [expr ($::spicewish::viewer::meas_x2(%W) - $::spicewish::viewer::meas_x1(%W))] + set ::spicewish::viewer::meas_dy(%W) [expr ($::spicewish::viewer::meas_y2(%W) - $::spicewish::viewer::meas_y1(%W))] + } + } + } + + } proc names { } { @@ -142,7 +158,6 @@ namespace eval viewer { proc plot { args } { if {$args == ""} {return} - spice::bltplot $args } @@ -154,7 +169,11 @@ namespace eval viewer { spice::setplot $plotTypeName - spice::bltplot $args + set l "" + foreach p $args { + set l "$l\\\"[spicewish::viewer::evaluate $p]\\\" " + } + eval spice::bltplot $l spice::setplot $currentPlotType } @@ -353,7 +372,7 @@ namespace eval viewer { spice::setplot $view_plotName($index) ::spice::X_Data set "" - spice::bltplot $trace + spice::bltplot [evaluate $trace] eval $\{::$view_plotName($index):v:$trace\} set \"::spice::Y_Data\" @@ -378,6 +397,25 @@ namespace eval viewer { destroy $w } + + proc evaluate { list } { + + foreach char "\[ \]" { + set repList "" + for {set i 0} {$i < [string length $list]} {incr i} { + if {[string range $list $i $i] == $char} { + lappend repList $i + } + } + set cnt 0 + foreach index $repList { + set list [string replace $list [expr $index + $cnt] [expr $index + $cnt] "\\$char"] + incr cnt + } + } + + return $list + } } namespace eval vectors { @@ -396,7 +434,7 @@ namespace eval vectors { return $name } else { ::spice::Y_Data set "" - uplevel #0 ::spice::bltplot $name + uplevel #0 ::spice::bltplot [spicewish::viewer::evaluate $name] if {[::spice::Y_Data length] != 0} { return $name