2 * ss_hspice.c: HSPICE routines for SpiceStream
4 * Copyright (C) 1998-2009 Stephen G. Tell
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sys/types.h>
33 #include "spicestream.h"
35 SpiceStream
*sf_rdhdr_hspice(char *name
, FILE *fp
);
36 SpiceStream
*sf_rdhdr_hsascii(char *name
, FILE *fp
);
37 SpiceStream
*sf_rdhdr_hsbin(char *name
, FILE *fp
);
39 static int sf_readrow_hsascii(SpiceStream
*sf
, double *ivar
, double *dvars
);
40 static int sf_readrow_hsbin(SpiceStream
*sf
, double *ivar
, double *dvars
);
41 static SpiceStream
*hs_process_header(int nauto
, int nprobe
,
42 int nsweepparam
, char *line
, char *name
);
43 static int sf_readsweep_hsascii(SpiceStream
*sf
, double *svar
);
44 static int sf_readsweep_hsbin(SpiceStream
*sf
, double *svar
);
45 static int sf_readblock_hsbin(FILE *fp
, char **bufp
, int *bufsize
, int offset
);
47 struct hsblock_header
{ /* structure of binary tr0 block headers */
59 static void swap_gint32(gint32
*pi
, size_t n
);
61 /* Read spice-type file header - autosense hspice binary or ascii */
63 sf_rdhdr_hspice(char *name
, FILE *fp
)
66 if((c
= getc(fp
)) == EOF
)
71 return sf_rdhdr_hsbin(name
, fp
);
73 return sf_rdhdr_hsascii(name
, fp
);
78 /* Read spice-type file header - hspice ascii */
80 sf_rdhdr_hsascii(char *name
, FILE *fp
)
82 SpiceStream
*sf
= NULL
;
84 int nauto
, nprobe
, nsweepparam
, ntables
;
93 if(fgets(lbuf
, sizeof(lbuf
), fp
) == NULL
)
97 /* version of post format */
98 if(strncmp(&lbuf
[16], "9007", 4) != 0
99 && strncmp(&lbuf
[16], "9601", 4) != 0
100 && strncmp(&lbuf
[16], "2001", 4) != 0 )
102 strncpy(nbuf
, &lbuf
[0], 4);
106 strncpy(nbuf
, &lbuf
[4], 4);
110 strncpy(nbuf
, &lbuf
[8], 4);
112 nsweepparam
= atoi(nbuf
);
114 if(fgets(lbuf
, sizeof(lbuf
), fp
) == NULL
) /* date, time etc. */
117 /* number of sweeps, possibly with cruft at the start of the line */
118 if(fgets(lbuf
, sizeof(lbuf
), fp
) == NULL
)
120 cp
= strchr(lbuf
, ' ');
128 maxlines
= nauto
+ nprobe
+ nsweepparam
+ 100;
129 /* lines making up a fixed-field structure with variable-types and
131 * variable names can get split across lines! so we remove newlines,
132 * paste all of the lines together, and then deal with the
133 * whole header at once.
134 * A variable name of "$&%#" indicates the end!
136 line
= g_new0(char, linesize
);
140 if(fgets(lbuf
, sizeof(lbuf
), fp
) == NULL
)
143 if((cp
= strchr(lbuf
, '\n')) != NULL
)
146 if(lineused
+ len
+ 1 > linesize
) {
148 if(linesize
> 1050000) {
149 ss_msg(ERR
, "rdhdr_ascii", "internal error - failed to find end of header\n; linesize=%d line=\n%.200s\n", linesize
, line
);
153 line
= g_realloc(line
, linesize
);
158 } while(!strstr(line
, "$&%#") && lineno
< maxlines
);
159 if(lineno
== maxlines
) {
160 ss_msg(DBG
, "rdhdr_hsascii", "%s:%d: end of hspice header not found", name
,lineno
);
164 sf
= hs_process_header(nauto
, nprobe
, nsweepparam
, line
, name
);
168 sf
->readrow
= sf_readrow_hsascii
;
171 sf
->lbufsize
= linesize
;
172 sf
->ntables
= ntables
;
175 sf
->read_sweepparam
= 0;
176 sf
->readsweep
= sf_readsweep_hsascii
;
179 ss_msg(DBG
, "rdhdr_hsascii", "ntables=%d; expect %d columns",
180 sf
->ntables
, sf
->ncols
);
191 /* Read spice-type file header - hspice binary */
193 sf_rdhdr_hsbin(char *name
, FILE *fp
)
196 SpiceStream
*sf
= NULL
;
202 int nauto
, nprobe
, nsweepparam
, ntables
;
205 struct hsblock_header hh
;
208 n
= sf_readblock_hsbin(fp
, &ahdr
, &ahdrsize
, ahdrend
);
212 ahdr
[ahdrend
] = '\0';
214 } while(!strstr(ahdr
, "$&%#"));
216 /* ahdr is an ascii header that describes the variables in
217 * much the same way that the first lines of the ascii format do,
218 * except that there are no newlines
221 if(strncmp(&ahdr
[16], "9007", 4) != 0 /* version of post format */
222 && strncmp(&ahdr
[16], "9601", 4) != 0
223 && strncmp(&ahdr
[20], "2001", 4) != 0 )
226 if(strncmp(&ahdr
[20], "2001", 4) == 0)
231 strncpy(nbuf
, &ahdr
[0], 4);
233 nauto
= atoi(nbuf
); /* number of automaticly-included variables,
234 first one is independent variable */
235 strncpy(nbuf
, &ahdr
[4], 4);
237 nprobe
= atoi(nbuf
); /* number of user-requested columns */
239 strncpy(nbuf
, &ahdr
[8], 4);
241 nsweepparam
= atoi(nbuf
); /* number of sweep parameters */
243 ntables
= atoi(&ahdr
[ntable_offset
]);
247 sf
= hs_process_header(nauto
, nprobe
, nsweepparam
, &ahdr
[256], name
);
251 if(fread(&hh
, sizeof(hh
), 1, fp
) != 1) {
252 ss_msg(DBG
, "sf_rdhdr_hsbin", "EOF reading block header");
255 if(hh
.h1
== 0x04000000 && hh
.h3
== 0x04000000) {
256 /* detected endian swap */
257 sf
->flags
|= SSF_ESWAP
;
258 swap_gint32((gint32
*)&hh
, sizeof(hh
)/sizeof(gint32
));
260 if(hh
.h1
!= 4 || hh
.h3
!= 4) {
261 ss_msg(DBG
, "sf_rdhdr_hsbin", "unexepected values in data block header");
265 datasize
= hh
.block_nbytes
;
266 sf
->expected_vals
= datasize
/ sizeof(float);
269 ss_msg(DBG
, "sf_rdhdr_hsbin", "datasize=%d expect %d columns, %d values;\n reading first data block at 0x%lx", datasize
, sf
->ncols
, sf
->expected_vals
, (long)ftello64(fp
));
273 sf
->readrow
= sf_readrow_hsbin
;
274 sf
->readsweep
= sf_readsweep_hsbin
;
276 sf
->ntables
= ntables
;
279 sf
->read_sweepparam
= 0;
287 g_ptr_array_free(sf
->dvarp
, 1);
294 /* common code for reading ascii or binary hspice headers.
295 * Given a string of ascii header information, set up the
296 * SpiceStream structure appropriately.
297 * Returns NULL on failure.
300 hs_process_header(int nauto
, int nprobe
, int nsweepparam
, char *line
, char *name
)
308 /* type of independent variable */
309 cp
= strtok(line
, " \t\n");
311 ss_msg(DBG
, "hs_process_header", "%s: initial vartype not found on header line.", name
);
314 sf
= ss_new(NULL
, name
, nauto
-1 + nprobe
, nsweepparam
);
318 sf
->ivar
->type
= TIME
;
321 sf
->ivar
->type
= FREQUENCY
;
324 sf
->ivar
->type
= VOLTAGE
;
327 sf
->ivar
->type
= UNKNOWN
;
334 /* dependent variable types */
335 for(i
= 0; i
< sf
->ndv
; i
++) {
340 cp
= strtok(NULL
, " \t\n");
342 ss_msg(DBG
, "hs_process_header", "%s: not enough vartypes on header line", name
);
345 if(!isdigit(cp
[0])) {
346 ss_msg(DBG
, "hs_process_header", "%s: bad vartype %d [%s] on header line", name
, i
, cp
);
365 if(i
< nauto
-1 && sf
->ivar
->type
== FREQUENCY
) {
370 dvar
= ss_spicevar_new(NULL
, vtype
, sf
->ncols
, ncols
);
371 g_ptr_array_add(sf
->dvarp
, dvar
);
375 /* independent variable name */
376 signam
= strtok(NULL
, " \t\n");
378 ss_msg(DBG
, "hs_process_header", "%s: no IV name found on header line", name
);
381 sf
->ivar
->name
= g_strdup(signam
);
383 /* dependent variable names */
384 for(i
= 0; i
< sf
->ndv
; i
++) {
386 if((signam
= strtok(NULL
, " \t\n")) == NULL
) {
387 ss_msg(DBG
, "hs_process_header", "%s: not enough DV names found on header line", name
);
390 dvar
= ss_dvar(sf
, i
);
391 dvar
->name
= g_strdup(signam
);
393 /* sweep parameter names */
394 for(i
= 0; i
< sf
->nsweepparam
; i
++) {
395 if((signam
= strtok(NULL
, " \t\n")) == NULL
) {
396 ss_msg(DBG
, "hs_process_header", "%s: not enough sweep parameter names found on header line", name
);
399 sf
->spar
[i
].name
= g_strdup(signam
);
410 * Read a "block" from an HSPICE binary file.
411 * Returns number of bytes read, 0 for EOF, negative for error.
412 * The body of the block is copied into the buffer pointed to by the
413 * buffer-pointer pointed to by bufp, at offset offset.
414 * The buffer is expanded with g_realloc if necessary.
415 * If bufp is NULL, a new buffer is allocated. The buffer
416 * size is maintained in the int pointed to by bufsize.
420 sf_readblock_hsbin(FILE *fp
, char **bufp
, int *bufsize
, int offset
)
422 struct hsblock_header hh
;
426 if(fread(&hh
, sizeof(hh
), 1, fp
) != 1) {
427 ss_msg(DBG
, "sf_readblock_hsbin", "EOF reading block header");
430 if(hh
.h1
== 0x04000000 && hh
.h3
== 0x04000000) {
431 /* detected endian swap */
433 swap_gint32((gint32
*)&hh
, sizeof(hh
)/sizeof(gint32
));
435 if(hh
.h1
!= 0x00000004 || hh
.h3
!= 0x00000004) {
436 ss_msg(DBG
, "sf_readblock_hsbin", "unexepected values in block header");
439 if(bufp
== NULL
) { /* new buffer: exact fit */
440 *bufsize
= hh
.block_nbytes
;
441 *bufp
= g_new(char, *bufsize
);
444 /* need to expand: double buffer size or make room for two blocks
445 * this size, whichever is larger. Better to realloc more now and
446 * cut down on the number of future reallocs.
448 if(*bufsize
< offset
+ hh
.block_nbytes
) {
449 if(2 * *bufsize
> (*bufsize
+ 2 * hh
.block_nbytes
))
452 *bufsize
+= 2 * hh
.block_nbytes
;
453 *bufp
= g_realloc(*bufp
, *bufsize
);
455 if(fread(*bufp
+ offset
, sizeof(char), hh
.block_nbytes
, fp
) != hh
.block_nbytes
) {
456 ss_msg(DBG
, "sf_readblock_hsbin", "EOF reading block body");
459 if(fread(&trailer
, sizeof(gint32
), 1, fp
) != 1) {
460 ss_msg(DBG
, "sf_readblock_hsbin", "EOF reading block trailer");
464 swap_gint32(&trailer
, 1);
466 if(trailer
!= hh
.block_nbytes
) {
467 ss_msg(DBG
, "sf_readblock_hsbin", "block trailer mismatch");
470 return hh
.block_nbytes
;
474 * helper routine: get next floating-point value from data part of binary
475 * hspice file. Handles the block-structure of hspice files; all blocks
476 * encountered are assumed to be data blocks. We don't use readblock_hsbin because
477 * some versions of hspice write very large blocks, which would require a
480 * Returns 0 on EOF, 1 on success, negative on error.
483 sf_getval_hsbin(SpiceStream
*sf
, double *dval
)
487 struct hsblock_header hh
;
490 if(sf
->read_vals
>= sf
->expected_vals
) {
491 pos
= ftello64(sf
->fp
);
492 if(fread(&trailer
, sizeof(gint32
), 1, sf
->fp
) != 1) {
493 ss_msg(DBG
, "sf_getval_hsbin", "EOF reading block trailer at offset 0x%lx", (long) pos
);
496 if(sf
->flags
& SSF_ESWAP
) {
497 swap_gint32(&trailer
, 1);
499 if(trailer
!= sf
->expected_vals
* sizeof(float)) {
500 ss_msg(DBG
, "sf_getval_hsbin", "block trailer mismatch at offset 0x%lx", (long) pos
);
504 pos
= ftello64(sf
->fp
);
505 if(fread(&hh
, sizeof(hh
), 1, sf
->fp
) != 1) {
506 ss_msg(DBG
, "sf_getval_hsbin", "EOF reading block header at offset 0x%lx", (long) pos
);
509 if(hh
.h1
== 0x04000000 && hh
.h3
== 0x04000000) {
510 /* detected endian swap */
511 sf
->flags
|= SSF_ESWAP
;
512 swap_gint32((gint32
*)&hh
, sizeof(hh
)/sizeof(gint32
));
514 sf
->flags
&= ~SSF_ESWAP
;
516 if(hh
.h1
!= 0x00000004 || hh
.h3
!= 0x00000004) {
517 ss_msg(ERR
, "sf_getval_hsbin", "unexepected values in block header at offset 0x%lx", pos
);
520 sf
->expected_vals
= hh
.block_nbytes
/ sizeof(float);
523 if(fread(&val
, sizeof(float), 1, sf
->fp
) != 1) {
524 pos
= ftello64(sf
->fp
);
525 ss_msg(ERR
, "sf_getval_hsbin", "unexepected EOF in data at offset 0x%lx", (long) pos
);
530 if(sf
->flags
& SSF_ESWAP
) {
531 swap_gint32((gint32
*)&val
, 1);
538 * helper routine: get next value from ascii hspice file.
539 * the file is line-oriented, with fixed-width fields on each line.
540 * Lines may look like either of these two examples:
541 0.66687E-090.21426E+010.00000E+000.00000E+000.25000E+010.71063E-090.17877E+01
542 .00000E+00 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30092E-05
543 * There may be whitespace at the end of the line before the newline.
545 * Returns 0 on EOF, 1 on success.
548 sf_getval_hsascii(SpiceStream
*sf
, double *val
)
555 if(!sf
->linep
|| (*sf
->linep
==0) || *sf
->linep
== '\n') {
556 if(fgets(sf
->linebuf
, sf
->lbufsize
, sf
->fp
) == NULL
)
559 l
= strlen(sf
->linebuf
);
560 if(l
) { /* delete whitespace at end of line */
561 cp
= sf
->linebuf
+ l
- 1;
562 while(cp
> sf
->linebuf
&& *cp
&& isspace(*cp
))
565 sf
->linep
= sf
->linebuf
;
566 sf
->line_length
= strlen(sf
->linep
);
567 /* fprintf(stderr, "#line: \"%s\"\n", sf->linebuf); */
569 if(sf
->linep
> sf
->linebuf
+ sf
->line_length
) {
570 ss_msg(WARN
, "sf_getval_hsascii",
571 "%s: internal error or bad line in file", sf
->filename
);
575 strncpy(vbuf
, sf
->linep
, 11);
578 if(strlen(vbuf
) != 11) {
579 /* incomplete float value - probably truncated or
580 partialy-written file */
584 while(isspace(*vp
)) /* atof doesn't like spaces */
587 /* fprintf(stderr, "#vp=\"%s\" val=%f\n", vp, *val); */
591 /* Read row of values from ascii hspice-format file.
593 * 1 on success. also fills in *ivar scalar and *dvars vector
595 * -1 on error (may change some ivar/dvar values)
596 * -2 on end of table, with more tables supposedly still to be read.
600 sf_readrow_hsascii(SpiceStream
*sf
, double *ivar
, double *dvars
)
604 if(!sf
->read_sweepparam
) { /* first row of table */
605 if(sf_readsweep_hsascii(sf
, NULL
) <= 0) /* discard sweep parameters, if any */
608 if(sf_getval_hsascii(sf
, ivar
) == 0)
610 if(*ivar
>= 1.0e29
) { /* "infinity" at end of data table */
612 if(sf
->read_tables
== sf
->ntables
)
615 sf
->read_sweepparam
= 0;
617 return -2; /* end of table, more tables follow */
621 for(i
= 0; i
< sf
->ncols
-1; i
++) {
622 if(sf_getval_hsascii(sf
, &dvars
[i
]) == 0) {
623 ss_msg(WARN
, "sf_readrow_hsascii", "%s: EOF or error reading data field %d in row %d of table %d; file is incomplete.", sf
->filename
, i
, sf
->read_rows
, sf
->read_tables
);
630 /* Read row of values from binary hspice-format file.
632 * 1 on success. also fills in *ivar scalar and *dvars vector
634 * -1 on error (may change some ivar/dvar values)
637 sf_readrow_hsbin(SpiceStream
*sf
, double *ivar
, double *dvars
)
642 if(!sf
->read_sweepparam
) { /* first row of table */
643 if(sf_readsweep_hsbin(sf
, NULL
) <= 0) /* discard sweep parameters, if any */
647 rc
= sf_getval_hsbin(sf
, ivar
);
648 if(rc
== 0) /* file EOF */
652 if(*ivar
>= 1.0e29
) { /* "infinity" at end of data table */
654 if(sf
->read_tables
== sf
->ntables
)
655 return 0; /* end of data, should also be EOF but we don't check */
657 sf
->read_sweepparam
= 0;
659 return -2; /* end of table, more tables follow */
663 for(i
= 0; i
< sf
->ncols
-1; i
++) {
664 if(sf_getval_hsbin(sf
, &dvars
[i
]) != 1) {
665 ss_msg(WARN
, "sf_readrow_hsbin", "%s: EOF or error reading data field %d in row %d of table %d; file is incomplete.", sf
->filename
, i
, sf
->read_rows
, sf
->read_tables
);
673 * Read the sweep parameters from an HSPICE ascii or binary file
674 * This routine must be called before the first sf_readrow_hsascii call in each data
675 * table. If it has not been called before the first readrow call, it will be called
676 * with a NULL svar pointer to read and discard the sweep data.
683 sf_readsweep_hsascii(SpiceStream
*sf
, double *svar
)
687 for(i
= 0; i
< sf
->nsweepparam
; i
++) {
688 if(sf_getval_hsascii(sf
, &val
) == 0) {
689 ss_msg(ERR
, "sf_readsweep_hsascii", "unexpected EOF reading sweep parameters\n");
696 sf
->read_sweepparam
= 1;
701 sf_readsweep_hsbin(SpiceStream
*sf
, double *svar
)
705 for(i
= 0; i
< sf
->nsweepparam
; i
++) {
706 if(sf_getval_hsbin(sf
, &val
) != 1) {
707 ss_msg(ERR
, "sf_readsweep_hsbin", "EOF or error reading sweep parameter\n");
714 sf
->read_sweepparam
= 1;
720 * Estimate how many rows are in the file associated with sf.
721 * We base our estimate on the size of the file.
722 * This can be useful to aid in memory-use planning by programs planning to
723 * read the entire file.
725 * If the file descriptor is not associated with an ordinary file, we return 0
726 * to indicate that the length cannot be estimated.
727 * If an error occurs, -1 is returned.
730 sf_guessrows_hsbin(SpiceStream
*sf
)
735 rc
= fstat(fileno(sf
->fp
), &st
);
738 if((st
.st_mode
& S_IFMT
) != S_IFREG
)
741 return st
.st_size
/ (sizeof(float) * sf
->ncols
);
746 swap_gint32(gint32
*pi
, size_t n
)
748 union gint32bytes
*p
= (union gint32bytes
*)pi
;
751 for(i
= 0; i
< n
; i
++) {
753 p
[i
].b
[3] = p
[i
].b
[0];
757 p
[i
].b
[2] = p
[i
].b
[1];