762 lines
18 KiB
C
762 lines
18 KiB
C
|
/*
|
||
|
* ss_hspice.c: HSPICE routines for SpiceStream
|
||
|
*
|
||
|
* include LICENSE
|
||
|
*/
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
// #include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <float.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
|
||
|
#include <bswap.h>
|
||
|
#include <spicestream.h>
|
||
|
|
||
|
#ifdef TRACE_MEM
|
||
|
#include <tracemem.h>
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static int hs_process_header(SpiceStream *ss, char *line, int nauto, int nprobe);
|
||
|
|
||
|
static int sf_getval_hsbin(SpiceStream *ss, double *dval);
|
||
|
static int sf_getval_hsascii(SpiceStream *ss, double *dval);
|
||
|
static int sf_readsweep_hspice(SpiceStream *ss);
|
||
|
|
||
|
|
||
|
/* structure of binary tr0 block headers */
|
||
|
struct hsblock_header {
|
||
|
gint32 h1;
|
||
|
gint32 h2;
|
||
|
gint32 h3;
|
||
|
gint32 block_nbytes;
|
||
|
};
|
||
|
|
||
|
static void
|
||
|
sf_swap_gint32(gint32 *pi, size_t n)
|
||
|
{
|
||
|
for ( ; n > 0; n-- ) {
|
||
|
*pi = be32_to_cpu(*pi) ;
|
||
|
pi++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Read spice-type file header - hspice ascii
|
||
|
*
|
||
|
* return 1 ok
|
||
|
* 0 EOF
|
||
|
* -1 Error
|
||
|
*/
|
||
|
|
||
|
int sf_rdhdr_hsascii(SpiceStream *ss)
|
||
|
{
|
||
|
char *line;
|
||
|
int nauto, nprobe, ntables;
|
||
|
char nbuf[16];
|
||
|
char *cp;
|
||
|
int maxlines;
|
||
|
DBuf *dbuf;
|
||
|
|
||
|
/* line 1 */
|
||
|
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
if ( *line < ' ' ) {
|
||
|
return -1;
|
||
|
}
|
||
|
/* version of post format */
|
||
|
if ( strncmp(&line[16], "9007", 4) != 0 && strncmp(&line[16], "9601", 4) != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
app_strncpy(nbuf, &line[0], 4);
|
||
|
nbuf[4] = 0;
|
||
|
nauto = atoi(nbuf);
|
||
|
|
||
|
app_strncpy(nbuf, &line[4], 4);
|
||
|
nbuf[4] = 0;
|
||
|
nprobe = atoi(nbuf);
|
||
|
|
||
|
app_strncpy(nbuf, &line[8], 4);
|
||
|
nbuf[4] = 0;
|
||
|
ss->nsweepparam = atoi(nbuf);
|
||
|
|
||
|
/* line 2 */
|
||
|
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL) { /* date, time etc. */
|
||
|
return 0;
|
||
|
}
|
||
|
/* number of sweeps, possibly with cruft at the start of the line */
|
||
|
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL) { /* date, time etc. */
|
||
|
return 0;
|
||
|
}
|
||
|
cp = strchr(line, ' ');
|
||
|
if ( ! cp) {
|
||
|
cp = line;
|
||
|
}
|
||
|
ntables = atoi(cp);
|
||
|
if (ntables == 0) {
|
||
|
ntables = 1;
|
||
|
}
|
||
|
ss->ntables = ntables;
|
||
|
|
||
|
maxlines = nauto + nprobe + ss->nsweepparam + 100;
|
||
|
/* lines making up a fixed-field structure with variable-types and
|
||
|
* variable names.
|
||
|
* variable names can get split across lines! so we remove newlines,
|
||
|
* paste all of the lines together, and then deal with the
|
||
|
* whole header at once.
|
||
|
* A variable name of "$&%#" indicates the end!
|
||
|
*/
|
||
|
|
||
|
dbuf = ss->dbuf;
|
||
|
dbuf_clear(dbuf);
|
||
|
do {
|
||
|
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL) { /* date, time etc. */
|
||
|
return 0;
|
||
|
}
|
||
|
dbuf_cat( dbuf, (DBuf *) ss->linebuf);
|
||
|
// dbuf_strcat( dbuf, " ");
|
||
|
int lineno = fdbuf_get_lineno( ss->linebuf);
|
||
|
|
||
|
if (lineno >= maxlines) {
|
||
|
msg_dbg("%d: end of hspice header not found", lineno);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (dbuf_get_len(dbuf) > 1050000) {
|
||
|
msg_error(_("internal error - failed to find end of header") );
|
||
|
return -1;
|
||
|
}
|
||
|
} while ( ! strstr(line, "$&%#")) ;
|
||
|
|
||
|
ss->rdSweepFunc = sf_readsweep_hspice;
|
||
|
ss->rdValFunc = sf_getval_hsascii ;
|
||
|
|
||
|
|
||
|
int ret = hs_process_header(ss, dbuf->s, nauto, nprobe);
|
||
|
msg_dbg("ntables = %d; expect %d columns", ss->ntables, ss->ncols);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int sf_read_header_block(SpiceStream *ss)
|
||
|
{
|
||
|
off_t pos; /* off64_t */
|
||
|
struct hsblock_header *hh;
|
||
|
char *line ;
|
||
|
int n;
|
||
|
|
||
|
pos = fdbuf_tello(ss->linebuf);
|
||
|
if ( (n = fdbuf_read(ss->linebuf, sizeof( struct hsblock_header) )) <= 0 ) {
|
||
|
msg_dbg("EOF reading block header at offset 0x%lx", (long) pos);
|
||
|
return 0;
|
||
|
}
|
||
|
line = ((DBuf *) ss->linebuf)->s;
|
||
|
if ( *line >= ' ' ) {
|
||
|
return -1;
|
||
|
}
|
||
|
hh = (struct hsblock_header *) line;
|
||
|
if (hh->h1 == 0x04000000 && hh->h3 == 0x04000000) {
|
||
|
/* detected endian swap */
|
||
|
ss->flags |= SSF_ESWAP;
|
||
|
sf_swap_gint32((gint32 *) hh, sizeof(struct hsblock_header) / sizeof(gint32) );
|
||
|
} else {
|
||
|
ss->flags &= ~SSF_ESWAP;
|
||
|
}
|
||
|
if (hh->h1 != 0x00000004 || hh->h3 != 0x00000004) {
|
||
|
msg_error(_("unexepected values in block header at offset 0x%lx"), pos);
|
||
|
return -1;
|
||
|
}
|
||
|
ss->read_vals = 0;
|
||
|
ss->expected_vals = hh->block_nbytes / sizeof(float);
|
||
|
return hh->block_nbytes;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int sf_read_trailer_block(SpiceStream *ss, gint32 size )
|
||
|
{
|
||
|
off_t pos; /* off64_t */
|
||
|
gint32 *trailer;
|
||
|
int n;
|
||
|
|
||
|
pos = fdbuf_tello(ss->linebuf);
|
||
|
if ( (n = fdbuf_read(ss->linebuf, sizeof(gint32) )) != sizeof(gint32) ) {
|
||
|
msg_dbg("EOF reading block trailer at offset 0x%lx", (long) pos);
|
||
|
pos = pos; /* silent the compiler */
|
||
|
return 0;
|
||
|
}
|
||
|
trailer = (gint32 *) ((DBuf *) ss->linebuf)->s;
|
||
|
if ( ss->flags & SSF_ESWAP) {
|
||
|
sf_swap_gint32( trailer, 1);
|
||
|
}
|
||
|
if (*trailer != size ) {
|
||
|
msg_dbg("block trailer mismatch at offset 0x%lx", (long) pos);
|
||
|
return -1;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* Read spice-type file header - hspice binary */
|
||
|
int sf_rdhdr_hsbin(SpiceStream *ss)
|
||
|
{
|
||
|
int n;
|
||
|
int nauto, nprobe, ntables;
|
||
|
char nbuf[16];
|
||
|
char *line ;
|
||
|
int bufsize;
|
||
|
DBuf *dbuf;
|
||
|
|
||
|
if ( (bufsize = sf_read_header_block(ss)) < 0 ){
|
||
|
return 0;
|
||
|
}
|
||
|
if ( (n = fdbuf_read(ss->linebuf, bufsize )) <= 0 ) {
|
||
|
return 0;
|
||
|
}
|
||
|
line = ((DBuf *) ss->linebuf)->s;
|
||
|
if ( ! strstr(line, "$&%#") ) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
dbuf = ss->dbuf;
|
||
|
dbuf_copy( dbuf, (DBuf *) ss->linebuf);
|
||
|
|
||
|
/* read the trailer */
|
||
|
if ( (n = sf_read_trailer_block(ss, bufsize )) <= 0 ) {
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* line is an ascii header that describes the variables in
|
||
|
* much the same way that the first lines of the ascii format do,
|
||
|
* except that there are no newlines
|
||
|
*/
|
||
|
|
||
|
/* version of post format */
|
||
|
line = dbuf->s;
|
||
|
if (strncmp(&line[16], "9007", 4) != 0 && strncmp(&line[16], "9601", 4) != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
app_strncpy(nbuf, &line[0], 4);
|
||
|
nbuf[4] = 0;
|
||
|
nauto = atoi(nbuf); /* number of automaticly-included variables,
|
||
|
first one is independent variable */
|
||
|
app_strncpy(nbuf, &line[4], 4);
|
||
|
nbuf[4] = 0;
|
||
|
nprobe = atoi(nbuf); /* number of user-requested columns */
|
||
|
|
||
|
app_strncpy(nbuf, &line[8], 4);
|
||
|
nbuf[4] = 0;
|
||
|
ss->nsweepparam = atoi(nbuf); /* number of sweep parameters */
|
||
|
|
||
|
ntables = atoi(&line[176]);
|
||
|
if (ntables == 0) {
|
||
|
ntables = 1;
|
||
|
}
|
||
|
ss->ntables = ntables;
|
||
|
ss->rdSweepFunc = sf_readsweep_hspice;
|
||
|
ss->rdValFunc = sf_getval_hsbin ;
|
||
|
|
||
|
n = hs_process_header( ss, &line[256], nauto, nprobe);
|
||
|
if ( n != 1) {
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
if ( (bufsize = sf_read_header_block(ss)) < 0 ){
|
||
|
ss->flags = 0;
|
||
|
return -2;
|
||
|
}
|
||
|
msg_dbg("datasize=%d expect %d columns, %d values;\n reading first data block at 0x%lx",
|
||
|
bufsize, ss->ncols, ss->expected_vals, (long) fdbuf_tello(ss->linebuf));
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* common code for reading ascii or binary hspice headers.
|
||
|
* Given a string of ascii header information, set up the
|
||
|
* SpiceStream structure appropriately.
|
||
|
* Returns -1 on failure.
|
||
|
*/
|
||
|
static int
|
||
|
hs_process_header(SpiceStream *ss, char *line, int nauto, int nprobe )
|
||
|
{
|
||
|
char *cp;
|
||
|
char *signam;
|
||
|
int i;
|
||
|
int hstype;
|
||
|
int ivtype;
|
||
|
int type;
|
||
|
|
||
|
ss->ndv = nauto - 1 + nprobe;
|
||
|
|
||
|
/* type of independent variable */
|
||
|
cp = strtok(line, " \t\n");
|
||
|
if ( ! cp) {
|
||
|
msg_dbg("initial vartype not found on header line.");
|
||
|
return -1;
|
||
|
}
|
||
|
hstype = atoi(cp);
|
||
|
switch (hstype) {
|
||
|
case 1:
|
||
|
ivtype = TIME;
|
||
|
break;
|
||
|
case 2:
|
||
|
ivtype = FREQUENCY;
|
||
|
break;
|
||
|
case 3:
|
||
|
ivtype = VOLTAGE;
|
||
|
break;
|
||
|
default:
|
||
|
ivtype = UNKNOWN;
|
||
|
break;
|
||
|
}
|
||
|
ss->ncols = 1;
|
||
|
spicestream_var_add( ss, NULL, ivtype, 1 );
|
||
|
|
||
|
/* dependent variable types */
|
||
|
for (i = 0; i < ss->ndv ; i++) {
|
||
|
cp = strtok(NULL, " \t\n");
|
||
|
if ( ! cp) {
|
||
|
msg_dbg("not enough vartypes on header line");
|
||
|
return -2;
|
||
|
}
|
||
|
if ( ! isdigit(cp[0])) {
|
||
|
msg_dbg("bad vartype %d [%s] on header line", i, cp);
|
||
|
return -2;
|
||
|
}
|
||
|
hstype = atoi(cp);
|
||
|
switch (hstype) {
|
||
|
case 1:
|
||
|
case 2:
|
||
|
type = VOLTAGE;
|
||
|
break;
|
||
|
case 8:
|
||
|
case 15:
|
||
|
case 22:
|
||
|
type = CURRENT;
|
||
|
break;
|
||
|
default:
|
||
|
type = UNKNOWN;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* how many columns comprise this variable? */
|
||
|
int ncols = 1;
|
||
|
if ( i < nauto - 1 && ivtype == FREQUENCY) {
|
||
|
ncols = 2;
|
||
|
}
|
||
|
ss->ncols += ncols;
|
||
|
spicestream_var_add( ss, NULL, type, ncols );
|
||
|
}
|
||
|
|
||
|
/* independent variable name */
|
||
|
signam = strtok(NULL, " \t\n");
|
||
|
if ( ! signam) {
|
||
|
msg_dbg("no IV name found on header line");
|
||
|
return -2;
|
||
|
}
|
||
|
dataset_dup_var_name( ss->wds, signam, 0 );
|
||
|
|
||
|
/* dependent variable names */
|
||
|
for (i = 0; i < ss->ndv; i++) {
|
||
|
if ((signam = strtok(NULL, " \t\n")) == NULL) {
|
||
|
msg_dbg("not enough DV names found on header line");
|
||
|
return -2;
|
||
|
}
|
||
|
dataset_dup_var_name( ss->wds, signam, i + 1 );
|
||
|
}
|
||
|
/* sweep parameter names */
|
||
|
for (i = 0; i < ss->nsweepparam ; i++) {
|
||
|
if ((signam = strtok(NULL, " \t\n")) == NULL) {
|
||
|
msg_dbg("not enough sweep parameter names found on header line" );
|
||
|
return -2;
|
||
|
}
|
||
|
wavetable_swvar_add( ss->wt, signam, UNKNOWN, 1 );
|
||
|
}
|
||
|
ss->flags |= (SSF_NORDHDR | SSF_CPVARS);
|
||
|
dbuf_clear( (DBuf *) ss->linebuf );
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* helper routine: get next floating-point value from data part of binary
|
||
|
* hspice file. Handles the block-structure of hspice files; all blocks
|
||
|
* encountered are assumed to be data blocks. We don't use readblock_hsbin because
|
||
|
* some versions of hspice write very large blocks, which would require a
|
||
|
* very large buffer.
|
||
|
*
|
||
|
* Returns 0 on EOF, 1 on success, negative on error.
|
||
|
*/
|
||
|
static int
|
||
|
sf_getval_hsbin(SpiceStream *ss, double *dval)
|
||
|
{
|
||
|
off_t pos; /* off64_t */
|
||
|
float *fval;
|
||
|
int bufsize;
|
||
|
int n;
|
||
|
|
||
|
if (ss->read_vals >= ss->expected_vals) {
|
||
|
/* read the trailer */
|
||
|
if ( (n = sf_read_trailer_block(ss, ss->expected_vals * sizeof(float) )) <= 0 ) {
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
/* read a headr block */
|
||
|
if ( (bufsize = sf_read_header_block(ss)) <= 0 ){
|
||
|
return bufsize;
|
||
|
}
|
||
|
}
|
||
|
if ( (n = fdbuf_read(ss->linebuf, sizeof(float) )) <= 0 ) {
|
||
|
pos = fdbuf_tello(ss->linebuf);
|
||
|
msg_error(_("unexepected EOF in data at offset 0x%lx"), (long) pos);
|
||
|
return 0;
|
||
|
}
|
||
|
ss->read_vals++;
|
||
|
fval = ( float *) ((DBuf *) ss->linebuf)->s;
|
||
|
|
||
|
if (ss->flags & SSF_ESWAP) {
|
||
|
sf_swap_gint32((gint32 *) fval, 1);
|
||
|
}
|
||
|
*dval = ( double) *fval;
|
||
|
// fprintf( stderr, "float %f, double %f\n", *fval, *dval );
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* helper routine: get next value from ascii hspice file.
|
||
|
* the file is line-oriented, with fixed-width fields on each line.
|
||
|
* Lines may look like either of these two examples:
|
||
|
0.66687E-090.21426E+010.00000E+000.00000E+000.25000E+010.71063E-090.17877E+01
|
||
|
.00000E+00 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30092E-05
|
||
|
* There may be whitespace at the end of the line before the newline.
|
||
|
*
|
||
|
* Returns 0 on EOF, 1 on success.
|
||
|
*/
|
||
|
static int
|
||
|
sf_getval_hsascii(SpiceStream *ss, double *val)
|
||
|
{
|
||
|
char vbuf[16];
|
||
|
int done = 0;
|
||
|
int i = 0;
|
||
|
int j = 0;
|
||
|
int c;
|
||
|
|
||
|
while ( ! done ) {
|
||
|
while ((c = dbuf_get_char( (DBuf *) ss->linebuf)) >= 0) {
|
||
|
j++;
|
||
|
if ( isspace(c) && i == 0 ) {
|
||
|
continue ;
|
||
|
}
|
||
|
if ( isspace(c) || c == 0) {
|
||
|
done = 1;
|
||
|
break;
|
||
|
}
|
||
|
vbuf[i++] = c ;
|
||
|
if ( j == 11 ) {
|
||
|
done = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
vbuf[i] = 0 ;
|
||
|
if ( done == 0 && fdbuf_get_line(ss->linebuf) == NULL) {
|
||
|
return 0; /* EOF */
|
||
|
}
|
||
|
}
|
||
|
if ( j < 11) {
|
||
|
int lineno = fdbuf_get_lineno( ss->linebuf);
|
||
|
lineno = lineno; /* gcc warning */
|
||
|
msg_dbg("%s: line %d: incomplete float value", ss->filename, lineno);
|
||
|
/* incomplete float value - probably truncated or partialy-written file */
|
||
|
return 0;
|
||
|
}
|
||
|
*val = g_ascii_strtod(vbuf, NULL);
|
||
|
// msg_dbg( "#vbuf=\"%s\" val=%f\n", vbuf, *val);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* Read row of values from ascii hspice-format file.
|
||
|
* Returns:
|
||
|
* 1 on success. also fills in *ivar scalar and *dvars vector
|
||
|
* 0 on EOF
|
||
|
* -1 on error (may change some ivar/dvar values)
|
||
|
* -2 on end of table, with more tables supposedly still to be read.
|
||
|
*/
|
||
|
|
||
|
int sf_readrow_hspice(SpiceStream *ss )
|
||
|
{
|
||
|
int i;
|
||
|
double val;
|
||
|
int ret;
|
||
|
|
||
|
ret = ss->rdValFunc ( ss, &val );
|
||
|
if ( ret != 1 ) {
|
||
|
return ret;
|
||
|
}
|
||
|
if (val >= 1.0e29) { /* "infinity" at end of data table */
|
||
|
ss->read_tables++;
|
||
|
if (ss->read_tables == ss->ntables) {
|
||
|
return 0; /* EOF end of data */
|
||
|
}
|
||
|
ss->read_sweepparam = 0;
|
||
|
return -2; /* end of table, more tables follow */
|
||
|
}
|
||
|
dataset_val_add( ss->wds, val);
|
||
|
|
||
|
for (i = 0; i < ss->ncols - 1; i++ ) {
|
||
|
if ( ss->rdValFunc ( ss, &val ) != 1) {
|
||
|
msg_warning(_("%s:\nEOF or error reading data field %d in row %d of table %d; file is incomplete."),
|
||
|
ss->filename, i, ss->read_rows, ss->read_tables);
|
||
|
return 0;
|
||
|
}
|
||
|
dataset_val_add( ss->wds, val);
|
||
|
}
|
||
|
ss->read_rows++;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Read the sweep parameters from an HSPICE ascii or binary file
|
||
|
* This routine must be called before the first sf_readrow_hsascii call in each data
|
||
|
* table. If it has not been called before the first readrow call, it will be called
|
||
|
* with a NULL svar pointer to read and discard the sweep data.
|
||
|
*
|
||
|
* returns:
|
||
|
* 1 on success
|
||
|
* -1 on error
|
||
|
*/
|
||
|
|
||
|
static int
|
||
|
sf_readsweep_hspice(SpiceStream *ss )
|
||
|
{
|
||
|
int i;
|
||
|
double val;
|
||
|
|
||
|
for (i = 0 ; i < ss->nsweepparam ; i++) {
|
||
|
if ( ss->rdValFunc ( ss, &val ) != 1) {
|
||
|
msg_error(_("EOF or error reading sweep parameter"));
|
||
|
return -1;
|
||
|
}
|
||
|
dataset_swval_add(ss->wds, val);
|
||
|
}
|
||
|
ss->read_sweepparam = 1;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int sf_buffer_copy(char *dest, char *src, int dpos, int len)
|
||
|
{
|
||
|
int i;
|
||
|
int pos = 0;
|
||
|
|
||
|
for ( i = 0 ; i < dpos ; i++ ){
|
||
|
*dest++ = ' ';
|
||
|
}
|
||
|
for ( ; i < len ; i++ ){
|
||
|
*dest = *src;
|
||
|
if (*src == '\n' ) {
|
||
|
*dest = ' ';
|
||
|
}
|
||
|
if (*src == 0 ) {
|
||
|
*dest = ' ';
|
||
|
} else {
|
||
|
src++;
|
||
|
pos++;
|
||
|
}
|
||
|
dest++;
|
||
|
}
|
||
|
*dest = 0;
|
||
|
if ( *src != 0 ) {
|
||
|
return pos; /* pos in src */
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int sf_hspice_type2str( int type)
|
||
|
{
|
||
|
int hstype;
|
||
|
|
||
|
switch (type) {
|
||
|
case VOLTAGE:
|
||
|
hstype = 1;
|
||
|
break;
|
||
|
case CURRENT:
|
||
|
hstype = 8;
|
||
|
break;
|
||
|
default:
|
||
|
hstype = 0;
|
||
|
break;
|
||
|
}
|
||
|
return hstype;
|
||
|
}
|
||
|
|
||
|
int sf_hspice_ivtype2str( int type)
|
||
|
{
|
||
|
int ivtype;
|
||
|
|
||
|
switch (type) {
|
||
|
case TIME:
|
||
|
ivtype = 1;
|
||
|
break;
|
||
|
case FREQUENCY:
|
||
|
ivtype = 2;
|
||
|
break;
|
||
|
case VOLTAGE:
|
||
|
ivtype = 3;
|
||
|
break;
|
||
|
default:
|
||
|
ivtype = 0;
|
||
|
break;
|
||
|
}
|
||
|
return ivtype;
|
||
|
}
|
||
|
|
||
|
void sf_write_file_hsascii( FILE *fd, WaveTable *wt, char *fmt)
|
||
|
{
|
||
|
int i;
|
||
|
int j;
|
||
|
int k = 0;
|
||
|
int l;
|
||
|
int m;
|
||
|
int n = 0;
|
||
|
char format[32];
|
||
|
char src[82];
|
||
|
char dest[82];
|
||
|
time_t now;
|
||
|
|
||
|
WDataSet *wds = wavetable_get_dataset( wt, n);
|
||
|
WaveVar *var = g_ptr_array_index( wds->vars, 0);
|
||
|
double min = wavevar_val_get_min(var);
|
||
|
double max = wavevar_val_get_max(var);
|
||
|
|
||
|
int nauto = 1;
|
||
|
int nprobe = wds->numVars - nauto;
|
||
|
int nsweepparam = wt->nswvars;
|
||
|
char *hsversion = "9601";
|
||
|
|
||
|
fprintf( stdout, "min %f, max %f\n", min, max);
|
||
|
|
||
|
sprintf( src, "%04d%04d%04d%04d%-8s*", nauto, nprobe, nsweepparam, n, hsversion );
|
||
|
sf_buffer_copy(dest, src, 0, 80);
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
|
||
|
time(&now) ;
|
||
|
sprintf( src, "%s Generated by Gaw", ctime(&now) );
|
||
|
sf_buffer_copy(dest, src, 16, 80);
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
|
||
|
sprintf( src, "%d", wavetable_get_ntables(wt) );
|
||
|
sf_buffer_copy(dest, src, 27, 80);
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
|
||
|
k = 19;
|
||
|
l = 0;
|
||
|
for ( i = 0 ; i < wds->numVars ; i++ ){
|
||
|
var = g_ptr_array_index( wds->vars, i);
|
||
|
if ( i == 0 ){
|
||
|
sprintf( src, "%8d", sf_hspice_ivtype2str(var->type));
|
||
|
} else {
|
||
|
sprintf( src, "%8d", sf_hspice_type2str(var->type));
|
||
|
}
|
||
|
if ( (j = sf_buffer_copy(&dest[l], src, k, 80 - l )) > 0 ){
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
k = 0;
|
||
|
l = 0;
|
||
|
sf_buffer_copy(&dest[l], &src[j], k, 80 - l ) ;
|
||
|
l += j;
|
||
|
} else {
|
||
|
l += k + strlen(src);
|
||
|
k = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
for ( i = 0 ; i < wds->numVars ; i++ ){
|
||
|
var = g_ptr_array_index( wds->vars, i);
|
||
|
sprintf( src, " %-8s ", var->varName );
|
||
|
|
||
|
if ( (j = sf_buffer_copy(&dest[l], src, k, 80 - l )) > 0 ){
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
k = 0;
|
||
|
l = 0;
|
||
|
sf_buffer_copy(&dest[l], &src[j], k, 80 - l ) ;
|
||
|
l += j;
|
||
|
} else {
|
||
|
l += k + strlen(src);
|
||
|
k = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( i = 0 ; i < wt->nswvars + 1; i++ ){
|
||
|
if ( i == wt->nswvars ) {
|
||
|
app_strcpy( src, " $&%#" );
|
||
|
} else {
|
||
|
var = g_ptr_array_index( wt->swvars, i);
|
||
|
sprintf( src, " %-8s ", var->varName );
|
||
|
}
|
||
|
if ( (j = sf_buffer_copy(&dest[l], src, k, 80 - l )) > 0 ){
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
k = 0;
|
||
|
l = 0;
|
||
|
sf_buffer_copy(&dest[l], &src[j], k, 80 - l ) ;
|
||
|
l += j;
|
||
|
} else {
|
||
|
l += k + strlen(src);
|
||
|
k = 0;
|
||
|
}
|
||
|
}
|
||
|
fprintf( fd, "%s\n", dest );
|
||
|
|
||
|
if ( ! fmt ) {
|
||
|
fmt = "%# .4E";
|
||
|
}
|
||
|
sprintf( format, "%s", fmt );
|
||
|
|
||
|
l = 0;
|
||
|
m = 0;
|
||
|
while ( (wds = wavetable_get_dataset( wt, n++)) ){
|
||
|
|
||
|
for ( i = 0 ; i < wt->nswvars ; i++ ){
|
||
|
double val = dataset_swval_get( wds, i );
|
||
|
sprintf( src, fmt, val );
|
||
|
k = strlen(src);
|
||
|
sf_buffer_copy(&dest[l], src, 0, k ) ;
|
||
|
l += k ;
|
||
|
if (++m >= 7 ){
|
||
|
m = 0;
|
||
|
l = 0;
|
||
|
fprintf( fd, "%s\n", dest);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( i = 0 ; i < wds->nrows ; i++ ){
|
||
|
for ( j = 0 ; j < wds->ncols ; j++ ){
|
||
|
double val = dataset_val_get( wds, i, j );
|
||
|
sprintf( src, fmt, val );
|
||
|
k = strlen(src);
|
||
|
sf_buffer_copy(&dest[l], src, 0, k ) ;
|
||
|
l += k ;
|
||
|
if (++m >= 7 ){
|
||
|
m = 0;
|
||
|
l = 0;
|
||
|
fprintf( fd, "%s\n", dest);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
app_strcpy( src, " 1.0000E+30");
|
||
|
k = strlen(src);
|
||
|
sf_buffer_copy(&dest[l], src, 0, k ) ;
|
||
|
l += k ;
|
||
|
m = 0;
|
||
|
l = 0;
|
||
|
fprintf( fd, "%s\n", dest);
|
||
|
}
|
||
|
}
|