From 4ed89173f22f642d18bc4a38c8591e7c9c28e94b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 2 Aug 2026 16:00:36 +0200 Subject: [PATCH] Enable spice notations like 2n or 5m in filesource inputs Tests that spaces or tabs are o.k. --- examples/xspice/filesource/my-source.txt | 22 +- src/xspice/icm/analog/file_source/cfunc.mod | 230 +++++++++++++++++++- 2 files changed, 231 insertions(+), 21 deletions(-) diff --git a/examples/xspice/filesource/my-source.txt b/examples/xspice/filesource/my-source.txt index be21b6805..71caf1466 100644 --- a/examples/xspice/filesource/my-source.txt +++ b/examples/xspice/filesource/my-source.txt @@ -1,12 +1,12 @@ * input test -0 0 1 -10e-6 0.1 0.9 -20e-6 0.2 0.8 -30e-6 0.3 0.7 -40e-6 0.4 0.6 -50e-6 0.5 0.5 -60e-6 0.6 0.4 -70e-6 0.7 0.3 -80e-6 0.8 0.2 -90e-6 0.9 0.1 -100e-6 1 0 +0 0 1m +10u 0.1m 0.9m +20u 0.2m 0.8m +30u 0.3m 0.7m +40u 0.4m 0.6m +50u 0.5m 0.5m +60u 0.6m 0.4m +70u 0.7m 0.3m +80u 0.8m 0.2m +90u 0.9m 0.1m +100u 1m 0 diff --git a/src/xspice/icm/analog/file_source/cfunc.mod b/src/xspice/icm/analog/file_source/cfunc.mod index 73eb12e68..595f940cb 100644 --- a/src/xspice/icm/analog/file_source/cfunc.mod +++ b/src/xspice/icm/analog/file_source/cfunc.mod @@ -15,6 +15,7 @@ AUTHORS 27 Feb 2017 Marcel Hendrix 23 JUL 2018 Holger Vogt 11 Aug 2025 Holger Vogt + 01 Aug 2026 Holger Vogt MODIFICATIONS @@ -55,8 +56,8 @@ NON-STANDARD FEATURES /*=== CONSTANTS ========================*/ - - +#define OK 0 +#define FAIL 1 /*=== MACROS ===========================*/ @@ -104,13 +105,220 @@ typedef struct { } Local_Data_t; +typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */ + /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ +/*=== Static CNV_get_spice_value ROUTINE =============*/ + +/* + Function takes as input a string token from a SPICE +deck and returns a floating point equivalent value. +*/ + + +static int cnv_get_spice_value( +char *str, /* IN - The value text e.g. 1.2K */ +double *p_value ) /* OUT - The numerical value */ +{ + + + /* the following were "int4" devices - jpm */ + size_t len; + size_t i; + int n_matched; + + line_t val_str; + + /*char *suffix;*/ + char c = ' '; + char c1; + + double scale_factor; + double value; + + + /* Scan the input string looking for an alpha character that is not */ + /* 'e' or 'E'. Such a character is assumed to be an engineering */ + /* suffix as defined in the Spice 2G.6 user's manual. */ + + len = strlen(str); + if( len > (sizeof(val_str) - 1)) + len = sizeof(val_str) - 1; + + for(i = 0; i < len; i++) { + c = str[i]; + if( isalpha_c(c) && (c != 'E') && (c != 'e') ) + break; + else if( isspace_c(c) ) + break; + else + val_str[i] = c; + } + val_str[i] = '\0'; + + + /* Determine the scale factor */ + + if( (i >= len) || (! isalpha_c(c)) ) + scale_factor = 1.0; + else { + + if(isupper_c(c)) + c = tolower_c(c); + + switch(c) { + + case 't': + scale_factor = 1.0e12; + break; + + case 'g': + scale_factor = 1.0e9; + break; + + case 'k': + scale_factor = 1.0e3; + break; + + case 'u': + scale_factor = 1.0e-6; + break; + + case 'n': + scale_factor = 1.0e-9; + break; + + case 'p': + scale_factor = 1.0e-12; + break; + + case 'f': + scale_factor = 1.0e-15; + break; + + case 'a': + scale_factor = 1.0e-18; + break; + + case 'm': + i++; + if(i >= len) { + scale_factor = 1.0e-3; + break; + } + c1 = str[i]; + if(! isalpha_c(c1)) { + scale_factor = 1.0e-3; + break; + } + if(islower_c(c1)) + c1 = toupper_c(c1); + if(c1 == 'E') + scale_factor = 1.0e6; + else if(c1 == 'I') + scale_factor = 25.4e-6; + else + scale_factor = 1.0e-3; + break; + + default: + scale_factor = 1.0; + } + } + + /* Convert the numeric portion to a float and multiply by the */ + /* scale factor. */ + + n_matched = sscanf(val_str,"%le",&value); + + if(n_matched < 1) { + *p_value = 0.0; + return(FAIL); + } + + *p_value = value * scale_factor; + return(OK); +} + + + +/*=== Static CNVgettok ROUTINE ================*/ +/* +Get the next token from the input string. The input string pointer +is advanced to the following token and the token from the input +string is copied to malloced storage and a pointer to that storage +is returned. The original input string is undisturbed. +*/ + +#include + +static char *CNVgettok(char **s) + +{ + + char *buf; /* temporary storage to copy token into */ + /*char *temp;*/ /* temporary storage to copy token into */ + char *ret_str; /* storage for returned string */ + + int i; + + /* allocate space big enough for the whole string */ + + buf = (char *) malloc(strlen(*s) + 1); + + /* skip over any white space */ + + while(isspace_c(**s) || (**s == '=') || + (**s == '(') || (**s == ')') || (**s == ',')) + (*s)++; + + /* isolate the next token */ + + switch(**s) { + + case '\0': /* End of string found */ + if(buf) free(buf); + return(NULL); + + + default: /* Otherwise, we are dealing with a */ + /* string representation of a number */ + /* or a mess o' characters. */ + i = 0; + while( (**s != '\0') && + (! ( isspace_c(**s) || (**s == '=') || + (**s == '(') || (**s == ')') || + (**s == ',') + ) ) ) { + buf[i] = **s; + i++; + (*s)++; + } + buf[i] = '\0'; + break; + } + + /* skip over white space up to next token */ + + while(isspace_c(**s) || (**s == '=') || + (**s == '(') || (**s == ')') || (**s == ',')) + (*s)++; + + /* make a copy using only the space needed by the string length */ + + + ret_str = (char *) malloc(strlen(buf) + 1); + ret_str = strcpy(ret_str,buf); + + if(buf) free(buf); + + return(ret_str); +} - /*============================================================================== FUNCTION void cm_filesource() @@ -277,13 +485,14 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. free(cpdel); continue; } - t = strtod(cp, &cp2); - if (cp2 == cp) { + char *ncp = CNVgettok(&cp); + int ret = cnv_get_spice_value(ncp, &t); + free(ncp); + if (ret == FAIL) { free(cpdel); terr = MIF_TRUE; continue; } - cp = cp2; if (!PARAM_NULL(timescale)) t *= PARAM(timescale); if (!PARAM_NULL(timerelative) && PARAM(timerelative) == MIF_TRUE) @@ -295,7 +504,7 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. /* before storing, check if vector size is large enough. If not, add another 1000*size doubles */ - if (count > (int) loc->indata->vecallocated - size) { + if (count > (int) loc->indata->vecallocated - stepsize) { loc->indata->vecallocated += (size_t) (size * 1000); void * const p = realloc(loc->indata->datavec, sizeof(double) * loc->indata->vecallocated); @@ -311,12 +520,13 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. for (i = 0; i < size; ++i) { while (*cp && (isspace_c(*cp) || *cp == ',')) ++cp; - d = strtod(cp, &cp2); - if (cp2 == cp) { + char *ncp = CNVgettok(&cp); + int ret = cnv_get_spice_value(ncp, &d); + free(ncp); + if (ret == FAIL) { derr = MIF_TRUE; break; } - cp = cp2; if (i < amplscalesize) d *= PARAM(amplscale[i]); if (i < amploffssize)