Merge branch 'pre-master-42' into bt_dev
This commit is contained in:
commit
df38aa24ce
|
|
@ -16,7 +16,8 @@
|
|||
# external OpenVAF Verilig-A compiler, will allow access to advanced compact
|
||||
# device models writen in Verilog-A.
|
||||
# Please see the ngspice manual, chapt. 13, for more info on using OSDI/OpenVAF.
|
||||
# CIDER, XSPICE, and OpenMP may be selected at will.
|
||||
# --enable-klu will add the new matrix solver in addition to Sparse 1.3.
|
||||
# CIDER, XSPICE, KLU, and OpenMP may be selected at will.
|
||||
# --disable-debug will give O2 optimization (versus O0 for debug) and removes all debugging info.
|
||||
|
||||
# ngspice as shared library:
|
||||
|
|
@ -48,13 +49,13 @@ if test "$1" = "d"; then
|
|||
if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi
|
||||
echo "configuring for 64 bit debug"
|
||||
echo
|
||||
../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --with-readline=yes --enable-openmp CFLAGS="-g -m64 -O0 -Wall -Wno-unused-but-set-variable" LDFLAGS="-m64 -g"
|
||||
../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --enable-klu --with-readline=yes --enable-openmp --prefix="/usr/local" --libdir="/usr/local/lib" CFLAGS="-g -m64 -O0 -Wall -Wno-unused-but-set-variable" LDFLAGS="-m64 -g"
|
||||
else
|
||||
cd release
|
||||
if [ $? -ne 0 ]; then echo "cd release failed"; exit 1 ; fi
|
||||
echo "configuring for 64 bit release"
|
||||
echo
|
||||
../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --with-readline=yes --enable-openmp --disable-debug CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
||||
../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --enable-klu --with-readline=yes --enable-openmp --disable-debug --prefix="/usr/local" --libdir="/usr/local/lib" CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
||||
fi
|
||||
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
# --enable-osdi will add the osdi interface which allows to dynamically load compiled Verilog-A
|
||||
# compact models. Compiling the VA code of the models is done by the OpenVAF compiler.
|
||||
# Please see the ngspice manual, chapt. 13, for more info on OSDI/OpenVAF.
|
||||
# CIDER, XSPICE, and OpenMP may be selected at will.
|
||||
# CIDER, XSPICE, KLU, and OpenMP may be selected at will.
|
||||
# --disable-debug will give O2 optimization (versus O0 for debug) and removes all debugging info.
|
||||
|
||||
# Add (optionally) --enable-relpath to avoid absolute paths when searching for code models.
|
||||
|
|
@ -44,7 +44,7 @@ if test "$1" = "d"; then
|
|||
echo
|
||||
# The --prefix (and perhaps --libdir) may be used to determine a different install location
|
||||
# (depending on the Linux distribution, and on the calling programs search path).
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --prefix=/usr CFLAGS="-g -m64 -O0 -Wall" LDFLAGS="-m64 -g"
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --enable-klu --prefix=/usr CFLAGS="-g -m64 -O0 -Wall" LDFLAGS="-m64 -g"
|
||||
else
|
||||
cd releasesh
|
||||
if [ $? -ne 0 ]; then echo "cd releasesh failed"; exit 1 ; fi
|
||||
|
|
@ -52,7 +52,7 @@ else
|
|||
echo
|
||||
# The --prefix (and perhaps --libdir) may be used to determine a different install location
|
||||
# (depending on the Linux distribution, and on the calling programs search path).
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --disable-debug --enable-osdi --prefix=/usr CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --enable-klu --disable-debug --prefix=/usr CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
||||
fi
|
||||
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@
|
|||
# for debug version of shared ngspice
|
||||
|
||||
# Options:
|
||||
# --adms and --enable-adms will install extra HICUM, EKV and MEXTRAM models via the
|
||||
# adms interface.
|
||||
# Please see http://ngspice.sourceforge.net/admshowto.html for more info on adms.
|
||||
# CIDER, XSPICE, and OpenMP may be selected at will.
|
||||
# CIDER, XSPICE, KLU, and OpenMP may be selected at will.
|
||||
# --disable-debug will give O2 optimization (versus O0 for debug) and removes all debugging info.
|
||||
# To obtain a 32 bit executable, replace -m64 by -m32 ./configure lines.
|
||||
|
||||
|
|
@ -38,27 +36,19 @@ fi
|
|||
./autogen.sh
|
||||
if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi
|
||||
|
||||
# Alternatively, if compiling sources from git, and want to add adms created devices,
|
||||
# you may need to uncomment the following two lines (and don't forget to add adms option
|
||||
# to the ../configure statement):
|
||||
#./autogen.sh --adms
|
||||
#if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi
|
||||
|
||||
echo
|
||||
if test "$1" = "d"; then
|
||||
cd debug-sh
|
||||
if [ $? -ne 0 ]; then echo "cd debug-sh failed"; exit 1 ; fi
|
||||
echo "configuring for 64 bit debug"
|
||||
echo
|
||||
# You may add --enable-adms to the following command for adding adms generated devices
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --enable-relpath --disable-debug prefix="C:/Spice64d" CFLAGS="-m64 -g -O0 -Wall" LDFLAGS="-m64"
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --enable-klu --enable-relpath prefix="C:/Spice64d" CFLAGS="-m64 -g -O0 -Wall" LDFLAGS="-m64"
|
||||
else
|
||||
cd release-sh
|
||||
if [ $? -ne 0 ]; then echo "cd release-sh failed"; exit 1 ; fi
|
||||
echo "configuring for 64 bit release"
|
||||
echo
|
||||
# You may add --enable-adms to the following command for adding adms generated devices
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --enable-relpath --disable-debug prefix="C:/Spice64" CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
||||
../configure --with-ngshared --enable-xspice --enable-cider --enable-openmp --enable-osdi --enable-klu --enable-relpath --disable-debug prefix="C:/Spice64" CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
||||
fi
|
||||
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
||||
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ q4 7 7 9 qnl
|
|||
rbias 7 8 20k
|
||||
.model qnl npn(bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf
|
||||
+ va=50)
|
||||
.print dc v(4) v(5)
|
||||
.plot dc v(5)
|
||||
.print ac vm(5) vp(5)
|
||||
.plot ac vm(5) vp(5)
|
||||
*.print dc v(4) v(5)
|
||||
*.plot dc v(5)
|
||||
*.print ac vm(5) vp(5)
|
||||
*.plot ac vm(5) vp(5)
|
||||
.print tran v(4) v(5)
|
||||
.plot tran v(5)
|
||||
.end
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ m11 8 4 0 0 mod w=250u l=5u
|
|||
m12 9 9 8 0 mod w=5u l=5u
|
||||
.model mod nmos(vto=0.5 phi=0.7 kp=1.0e-6 gamma=1.83 lambda=0.115
|
||||
+ level=1 cgso=1u cgdo=1u cbd=50p cbs=50p)
|
||||
.print dc v(5) v(6)
|
||||
.plot dc v(6)
|
||||
*.print dc v(5) v(6)
|
||||
*.plot dc v(6)
|
||||
.plot tran v(6) v(5) v(7) v(1) v(2)
|
||||
.end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
The circuit adc.cir in this directory illustrates the use of the d_cosim
|
||||
XSPICE code model as a container for a Verilog simulation. Before the
|
||||
simulation can be run, the Verilog code must be compiled by Verilator
|
||||
using the command:
|
||||
|
||||
ngspice vlnggen adc.v
|
||||
|
||||
That should create a shared library file, adc.so (or adc.DLL on Windows)
|
||||
that will be loaded by the d_cosim code model. The compiled Verilog code that
|
||||
it contains will be executed during simulation.
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
Simulation of a switched-capacitor SAR ADC with Verilator and d_cosim
|
||||
|
||||
.subckt sar_adc input vref start valid d5 d4 d3 d2 d1 d0 clk
|
||||
|
||||
* A transmission gate connects the input to the capacitor set.
|
||||
|
||||
xsample input iin sample vref tgate
|
||||
rin iin test_v 1k
|
||||
|
||||
* Capacitors and controlling inverters
|
||||
|
||||
xb5 test_v vref d5 ccap c=1p
|
||||
xb4 test_v vref d4 ccap c={1p / 2}
|
||||
xb3 test_v vref d3 ccap c={1p / 4}
|
||||
xb2 test_v vref d2 ccap c={1p / 8}
|
||||
xb1 test_v vref d1 ccap c={1p / 16}
|
||||
xb0 test_v vref d0 ccap c={1p / 32}
|
||||
clast test_v 0 {1p / 32}
|
||||
|
||||
* An XSPICE ADC bridge functions as a comparator.
|
||||
|
||||
acomp [%vd(test_v vref)] [comp] comparator
|
||||
.model comparator adc_bridge in_low=0 in_high=0
|
||||
|
||||
* The digital portion of the circuit is specified in compiled Verilog.
|
||||
* Outputs inverted to cancel the inverter in subcircuit ccap,
|
||||
* and produce the correct numerical output value.
|
||||
|
||||
adut [ Clk Comp Start] [Sample Valid ~d5 ~d4 ~d3 ~d2 ~d1 ~d0] null dut
|
||||
.model dut d_cosim simulation="./adc.so"
|
||||
.ends // SUBCKT sar_adc
|
||||
|
||||
* Some MOS transistors complete the circuit.
|
||||
* Models from https://homepages.rpi.edu/~sawyes/AIMSPICE_TutorialManual.pdf
|
||||
|
||||
.model p1 pmos
|
||||
+ level=2 vto=-0.5 kp=8.5e-6 gamma=0.4 phi=0.65 lambda=0.05 xj=0.5e-6
|
||||
.model n1 nmos
|
||||
+ level=2 vto=0.5 kp=24e-6 gamma=0.15 phi=0.65 lambda=0.015 xj=0.5e-6
|
||||
|
||||
* Use those for an inverter.
|
||||
|
||||
.subckt ainv in out vdd
|
||||
mn out in 0 0 n1
|
||||
mp out in vdd vdd p1
|
||||
.ends
|
||||
|
||||
* A transmission gate modelled by a switch.
|
||||
|
||||
.subckt mos_tgate a b ctl vdd
|
||||
mn a ctl b b n1
|
||||
xinv ctl ictl vdd ainv
|
||||
mp b ictl a a p1
|
||||
.ends
|
||||
|
||||
.subckt tgate a b ctl vdd
|
||||
switch a b ctl 0 tg
|
||||
.model tg sw vt=1.5 ron=2k
|
||||
.ends
|
||||
|
||||
* The per-bit subcircuit in the adc
|
||||
|
||||
.subckt ccap in vcc ctl c=10p
|
||||
xinv ctl tail vcc ainv
|
||||
cb in tail {c}
|
||||
.ends
|
||||
|
||||
**** End of the ADC and its subcircuits. Begin test circuit ****
|
||||
|
||||
.param vcc=3.3
|
||||
vcc vcc 0 {vcc}
|
||||
|
||||
* Digital clock signal
|
||||
|
||||
aclock 0 clk clock
|
||||
.model clock d_osc cntl_array=[-1 1] freq_array=[1Meg 1Meg]
|
||||
|
||||
* A simple DAC so that the result may be compared to the input.
|
||||
|
||||
r5 d5 sum 2
|
||||
r4 d4 sum 4
|
||||
r3 d3 sum 8
|
||||
r2 d2 sum 16
|
||||
r1 d1 sum 32
|
||||
r0 d0 sum 64
|
||||
|
||||
vamm sum 0 0
|
||||
|
||||
* Pulse the Start signal high for 1.3uS each 10uS
|
||||
|
||||
Vpulse Start 0 PULSE 0 {vcc} 0.2u 10n 10n 1.3u 10u
|
||||
Vtest input 0 PULSE 0 3 0 200u 200u 1u 401u
|
||||
|
||||
* The ADC for testing
|
||||
|
||||
xtest input vcc start valid d5 d4 d3 d2 d1 d0 clk sar_adc
|
||||
|
||||
|
||||
.control
|
||||
tran 100n 250u
|
||||
plot input xtest.test_v vamm#branch clk/2 start/3 xtest.sample/3 valid
|
||||
.endc
|
||||
.end
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Digital control for a successive approximation ADC with switched capacitors.
|
||||
|
||||
module adc(Clk, Comp, Start, Sample, Done, Result);
|
||||
input wire Clk, Comp, Start;
|
||||
output reg Sample, Done;
|
||||
output reg [Bits - 1 : 0] Result;
|
||||
|
||||
parameter Bits=6;
|
||||
|
||||
reg [Bits - 1 : 0] SR;
|
||||
reg Running;
|
||||
|
||||
initial begin
|
||||
$display("ADC simulation starting");
|
||||
Done = 0;
|
||||
Sample = 0;
|
||||
Result = 0;
|
||||
Running = 0;
|
||||
end
|
||||
|
||||
always @(posedge(Clk)) begin
|
||||
if (Running) begin
|
||||
if (Sample) begin
|
||||
Sample <= 0;
|
||||
SR[Bits - 1] = 1;
|
||||
Result[Bits - 1] = 1;
|
||||
end else if (SR != 0) begin
|
||||
if (Comp)
|
||||
Result &= ~SR;
|
||||
SR >>= 1;
|
||||
Result |= SR;
|
||||
if (SR == 0) begin
|
||||
Running <= 0;
|
||||
Done <= 1;
|
||||
end
|
||||
end
|
||||
end else if (Start) begin
|
||||
Running <= 1;
|
||||
Sample <= 1;
|
||||
Done <= 0;
|
||||
SR = 0;
|
||||
Result = 0;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -34,6 +34,8 @@ libfte_la_SOURCES = \
|
|||
com_dump.h \
|
||||
com_echo.c \
|
||||
com_echo.h \
|
||||
com_fileio.c \
|
||||
com_fileio.h \
|
||||
com_ghelp.c \
|
||||
com_ghelp.h \
|
||||
com_gnuplot.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,181 @@
|
|||
/* Commands for opening and reading arbitrary files. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#include "ngspice/bool.h"
|
||||
#include "ngspice/wordlist.h"
|
||||
|
||||
#include "com_strcmp.h"
|
||||
#include "variable.h"
|
||||
|
||||
/* Track open files with these structures, indexed by the underlying
|
||||
* descriptor. Not many should be needed.
|
||||
*/
|
||||
|
||||
#define MAX_OPEN_FILES 20
|
||||
#define MAX_TEXT_LINE 8192
|
||||
|
||||
static struct {
|
||||
FILE *fp;
|
||||
char *name;
|
||||
} Open_Files[MAX_OPEN_FILES];
|
||||
|
||||
/* Check whether error messages should be suppressed. That is useful when
|
||||
* opening a file to see if it exists.
|
||||
*/
|
||||
|
||||
static int verbose(void)
|
||||
{
|
||||
return !cp_getvar("silent_fileio", CP_BOOL, NULL, 0);
|
||||
}
|
||||
|
||||
/* fopen handle file_name [mode]
|
||||
*
|
||||
* For example: fopen handle result.txt r
|
||||
*
|
||||
* The underlying file descriptor (or -1) is returned in the variable "handle".
|
||||
*/
|
||||
|
||||
void com_fopen(wordlist *wl)
|
||||
{
|
||||
char *var, *file_name, *mode;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
|
||||
var = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
file_name = cp_unquote(wl->wl_word);
|
||||
wl = wl->wl_next;
|
||||
mode = wl ? cp_unquote(wl->wl_word) : "r";
|
||||
fp = fopen(file_name, mode);
|
||||
if (fp) {
|
||||
fd = fileno(fp);
|
||||
if (fd < MAX_OPEN_FILES) {
|
||||
if (Open_Files[fd].fp) // Not expected!
|
||||
fclose(Open_Files[fd].fp);
|
||||
if (Open_Files[fd].name)
|
||||
tfree(Open_Files[fd].name);
|
||||
Open_Files[fd].fp = fp;
|
||||
Open_Files[fd].name = copy(file_name);
|
||||
} else {
|
||||
fclose(fp);
|
||||
fprintf(stderr,
|
||||
"com_fopen() cannot open %s: too many open files\n",
|
||||
file_name);
|
||||
fd = -1;
|
||||
}
|
||||
} else {
|
||||
fd = -1;
|
||||
if (verbose()) {
|
||||
fprintf(stderr, "com_fopen() cannot open %s: %s\n",
|
||||
file_name, strerror(errno));
|
||||
}
|
||||
}
|
||||
tfree(file_name);
|
||||
if (wl)
|
||||
tfree(mode);
|
||||
cp_vset(var, CP_NUM, &fd);
|
||||
}
|
||||
|
||||
/* Command looks like:
|
||||
* fread result handle [length]
|
||||
* where handle is a small positive integer, result names a variable
|
||||
* and length is the name of a variable used to return the length of the line.
|
||||
* The returned length is -1 at EOF, -2 on failure.
|
||||
*/
|
||||
|
||||
void com_fread(wordlist *wl)
|
||||
{
|
||||
char *handle, *result, *lvar;
|
||||
int fd, length;
|
||||
char buf[MAX_TEXT_LINE];
|
||||
|
||||
result = cp_unquote(wl->wl_word);
|
||||
wl = wl->wl_next;
|
||||
handle = cp_unquote(wl->wl_word);
|
||||
fd = atoi(handle);
|
||||
tfree(handle);
|
||||
wl = wl->wl_next;
|
||||
if (wl)
|
||||
lvar = cp_unquote(wl->wl_word);
|
||||
else
|
||||
lvar = NULL;
|
||||
|
||||
if (fd >= 0 && fd < MAX_OPEN_FILES) {
|
||||
if (!Open_Files[fd].fp) {
|
||||
/* Allow stdin, for example. */
|
||||
|
||||
Open_Files[fd].fp = fdopen(fd, "r");
|
||||
if (!Open_Files[fd].fp && verbose()) {
|
||||
fprintf(stderr, "com_fread() cannot open handle %d\n", fd);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (fgets(buf, sizeof buf, Open_Files[fd].fp)) {
|
||||
length = strlen(buf);
|
||||
if (length > 0 && buf[length - 1] == '\n') {
|
||||
--length;
|
||||
if (length > 0 && buf[length - 1] == '\r') {
|
||||
/* Windows CRLF line termination. */
|
||||
|
||||
--length;
|
||||
}
|
||||
buf[length] = '\0';
|
||||
} else if (verbose()) {
|
||||
fprintf(stderr,
|
||||
"com_fread() found line in %s "
|
||||
"too long for buffer\n",
|
||||
Open_Files[fd].name);
|
||||
}
|
||||
} else {
|
||||
if (feof(Open_Files[fd].fp)) {
|
||||
length = -1;
|
||||
} else if (verbose()) {
|
||||
fprintf(stderr,
|
||||
"com_fread() error reading %s: %s\n",
|
||||
Open_Files[fd].name, strerror(errno));
|
||||
length = -2;
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
} else if (verbose()) {
|
||||
fprintf(stderr,
|
||||
"com_fread(): file handle %d is not in accepted range.\n",
|
||||
fd);
|
||||
err:
|
||||
length = -1;
|
||||
*buf = '\0';
|
||||
}
|
||||
cp_vset(result, CP_STRING, buf);
|
||||
tfree(result);
|
||||
if (lvar) {
|
||||
cp_vset(lvar, CP_NUM, &length);
|
||||
tfree(lvar);
|
||||
}
|
||||
}
|
||||
|
||||
void com_fclose(wordlist *wl)
|
||||
{
|
||||
char *handle;
|
||||
int fd;
|
||||
|
||||
handle = cp_unquote(wl->wl_word);
|
||||
fd = atoi(handle);
|
||||
tfree(handle);
|
||||
if (fd <= 2 || fd >= MAX_OPEN_FILES)
|
||||
return;
|
||||
if (Open_Files[fd].fp) {
|
||||
fclose(Open_Files[fd].fp);
|
||||
Open_Files[fd].fp = NULL;
|
||||
}
|
||||
if (Open_Files[fd].name)
|
||||
tfree(Open_Files[fd].name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef ngspice_COM_FILEIO_H
|
||||
#define ngspice_COM_FILEIO_H
|
||||
|
||||
|
||||
extern void com_fopen(wordlist *wl);
|
||||
extern void com_fread(wordlist *wl);
|
||||
extern void com_fclose(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
|
@ -400,6 +400,11 @@ com_measure_when(
|
|||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (dScale->v_realdata ==NULL && dScale->v_compdata == NULL) {
|
||||
fprintf(cp_err, "Error: scale vector time, frequency or dc has no data.\n");
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
prevValue = 0.;
|
||||
prevValue2 = 0.;
|
||||
prevScaleValue = 0.;
|
||||
|
|
@ -658,6 +663,11 @@ measure_at(
|
|||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (dScale->v_realdata == NULL && dScale->v_compdata == NULL) {
|
||||
fprintf(cp_err, "Error: scale vector time, frequency or dc has no data.\n");
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* Take the string tests outside of the loop for speed.
|
||||
* ----------------------------------------------------------------- */
|
||||
|
|
@ -768,7 +778,12 @@ measure_minMaxAvg(
|
|||
}
|
||||
|
||||
if (dScale == NULL) {
|
||||
fprintf(cp_err, "Error: no such vector as time, frquency or v-sweep.\n");
|
||||
fprintf(cp_err, "Error: no such vector as time, frequency or v-sweep.\n");
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (dScale->v_realdata == NULL && dScale->v_compdata == NULL) {
|
||||
fprintf(cp_err, "Error: scale vector time, frequency or v-sweep has no data.\n");
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
|
|
@ -944,7 +959,12 @@ measure_rms_integral(
|
|||
}
|
||||
|
||||
if (xScale == NULL) {
|
||||
fprintf(cp_err, "Error: no such vector as time.\n");
|
||||
fprintf(cp_err, "Error: no such vector as time, frequency or v-sweep.\n");
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (xScale->v_realdata == NULL && xScale->v_compdata == NULL) {
|
||||
fprintf(cp_err, "Error: scale vector time, frequency or v-sweep has no data.\n");
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,3 +23,54 @@ com_strcmp(wordlist *wl)
|
|||
tfree(s2);
|
||||
cp_vset(var, CP_NUM, &i);
|
||||
}
|
||||
|
||||
/* These must be more evil still. */
|
||||
|
||||
void com_strstr(wordlist *wl)
|
||||
{
|
||||
char *var, *s1, *s2;
|
||||
int i;
|
||||
|
||||
s1 = cp_unquote(wl->wl_next->wl_word);
|
||||
s2 = cp_unquote(wl->wl_next->wl_next->wl_word);
|
||||
if (*s2) {
|
||||
var = strstr(s1, s2); // Search for s2 in s1
|
||||
if (var)
|
||||
i = var - s1; // Offset to match
|
||||
else
|
||||
i = -1;
|
||||
} else {
|
||||
i = strlen(s1); // Length
|
||||
}
|
||||
tfree(s1);
|
||||
tfree(s2);
|
||||
cp_vset(wl->wl_word, CP_NUM, &i);
|
||||
}
|
||||
|
||||
void com_strslice(wordlist *wl)
|
||||
{
|
||||
char *var, *s1, *tp, tmp;
|
||||
int offset, length, actual;
|
||||
|
||||
var = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
s1 = cp_unquote(wl->wl_word);
|
||||
wl = wl->wl_next;
|
||||
offset = atoi(wl->wl_word);
|
||||
length = atoi(wl->wl_next->wl_word);
|
||||
actual = strlen(s1);
|
||||
if (offset < 0)
|
||||
offset = actual + offset;
|
||||
if (length + offset > actual)
|
||||
length = actual - offset;
|
||||
if (length > 0 && offset >= 0) {
|
||||
tp = s1 + offset + length;
|
||||
tmp = *tp;
|
||||
*tp = '\0';
|
||||
cp_vset(var, CP_STRING, s1 + offset);
|
||||
*tp = tmp;
|
||||
} else {
|
||||
cp_vset(var, CP_STRING, "");
|
||||
}
|
||||
tfree(s1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef ngspice_COM_STRCMP_H
|
||||
#define ngspice_COM_STRCMP_H
|
||||
|
||||
|
||||
void com_strcmp(wordlist *wl);
|
||||
extern void com_strcmp(wordlist *wl);
|
||||
extern void com_strstr(wordlist *wl);
|
||||
extern void com_strslice(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
#include "resource.h"
|
||||
#include "diff.h"
|
||||
#include "com_strcmp.h"
|
||||
#include "com_fileio.h"
|
||||
#include "ngspice/randnumb.h"
|
||||
#include "../spicelib/analysis/com_optran.h"
|
||||
#include "com_wr_ic.h"
|
||||
|
|
@ -613,6 +614,30 @@ struct comm spcp_coms[] = {
|
|||
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
||||
NULL,
|
||||
"varname s1 s2 : Set $varname to strcmp(s1, s2)." } ,
|
||||
{ "strstr", com_strstr, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
||||
NULL,
|
||||
"varname s1 s2 : Set $varname to strstr(s1, s2)." } ,
|
||||
{ "strslice", com_strslice, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 4, 4,
|
||||
NULL,
|
||||
"varname s1 offset length : "
|
||||
"Set $varname to s1[offset ... offset+length]" } ,
|
||||
{ "fopen", com_fopen, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
|
||||
NULL,
|
||||
"handle file_name [mode] : "
|
||||
"Open file_name with mode, return handle in $handle" } ,
|
||||
{ "fread", com_fread, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
|
||||
NULL,
|
||||
"handle result [length] : "
|
||||
"Read a line from open file handle, "
|
||||
"data in $result, status in $length" } ,
|
||||
{ "fclose", com_fclose, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 1, 1,
|
||||
NULL,
|
||||
"handle : Close open file" } ,
|
||||
{ "linearize", com_linearize, FALSE, FALSE,
|
||||
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
|
|
@ -1033,6 +1058,30 @@ struct comm nutcp_coms[] = {
|
|||
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
||||
NULL,
|
||||
"varname s1 s2 : Set $varname to strcmp(s1, s2)." } ,
|
||||
{ "strstr", com_strstr, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
||||
NULL,
|
||||
"varname s1 s2 : Set $varname to strstr(s1, s2)." } ,
|
||||
{ "strslice", com_strslice, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 4, 4,
|
||||
NULL,
|
||||
"varname s1 offset length : "
|
||||
"Set $varname to s1[offset ... offset+length]" } ,
|
||||
{ "fopen", com_fopen, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
|
||||
NULL,
|
||||
"handle file_name [mode] : "
|
||||
"Open file_name with mode, return handle in $handle" } ,
|
||||
{ "fread", com_fread, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
|
||||
NULL,
|
||||
"handle result [length] : "
|
||||
"Read a line from open file handle, "
|
||||
"data in $result, status in $length" } ,
|
||||
{ "fclose", com_fclose, FALSE, FALSE,
|
||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 1, 1,
|
||||
NULL,
|
||||
"handle : Close open file" } ,
|
||||
{ "linearize", com_linearize, TRUE, FALSE,
|
||||
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,54 @@
|
|||
|
||||
|
||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/dvec.h"
|
||||
|
||||
#if defined SHARED_MODULE
|
||||
|
||||
/*Use Windows threads if on W32 without pthreads*/
|
||||
#ifndef HAVE_LIBPTHREAD
|
||||
|
||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||
//#if defined(_MSC_VER)
|
||||
#ifdef SRW
|
||||
#define mutex_lock(a) AcquireSRWLockExclusive(a)
|
||||
#define mutex_unlock(a) ReleaseSRWLockExclusive(a)
|
||||
typedef SRWLOCK mutexType;
|
||||
#else
|
||||
#define mutex_lock(a) EnterCriticalSection(a)
|
||||
#define mutex_unlock(a) LeaveCriticalSection(a)
|
||||
typedef CRITICAL_SECTION mutexType;
|
||||
#endif
|
||||
#define thread_self() GetCurrentThread()
|
||||
#define threadid_self() GetCurrentThreadId()
|
||||
typedef HANDLE threadId_t;
|
||||
#define WIN_THREADS
|
||||
#define THREADS
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
#define mutex_lock(a) pthread_mutex_lock(a)
|
||||
#define mutex_unlock(a) pthread_mutex_unlock(a)
|
||||
#define thread_self() pthread_self()
|
||||
#define threadid_self() 0 //FIXME t.b.d.
|
||||
typedef pthread_mutex_t mutexType;
|
||||
typedef pthread_t threadId_t;
|
||||
#define THREADS
|
||||
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
static bool cont_condition;
|
||||
|
||||
#endif
|
||||
|
||||
extern mutexType vecreallocMutex;
|
||||
|
||||
#endif
|
||||
|
||||
struct dvec *dvec_alloc(/* NOT const -- assigned to char */ char *name,
|
||||
int type, short flags, int length, void *storage)
|
||||
|
|
@ -58,7 +106,7 @@ struct dvec *dvec_alloc(/* NOT const -- assigned to char */ char *name,
|
|||
} /* end of function dvec_alloc */
|
||||
|
||||
|
||||
/* Resize dvec to length if storage is NULL orr replace
|
||||
/* Resize dvec to length if storage is NULL or replace
|
||||
* its existing allocation with storage if not
|
||||
*/
|
||||
void dvec_realloc(struct dvec *v, int length, void *storage)
|
||||
|
|
@ -86,17 +134,26 @@ void dvec_realloc(struct dvec *v, int length, void *storage)
|
|||
v->v_alloc_length = length;
|
||||
} /* end of function dvec_realloc */
|
||||
|
||||
|
||||
/* called from plotAddReal(Complex)Value, to increase
|
||||
storage for result vectors.
|
||||
In shared ngspice this may be locked, e.g. during plotting in the primary
|
||||
thread, while the simulation is running in the background thread. Locking and unlocking
|
||||
is done by API functions ngSpice_LockRealloc(), ngSpice_UnlockRealloc(). */
|
||||
void dvec_extend(struct dvec *v, int length)
|
||||
{
|
||||
#if defined SHARED_MODULE
|
||||
mutex_lock(&vecreallocMutex);
|
||||
#endif
|
||||
if (isreal(v)) {
|
||||
v->v_realdata = TREALLOC(double, v->v_realdata, length);
|
||||
}
|
||||
else {
|
||||
v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length);
|
||||
}
|
||||
|
||||
v->v_alloc_length = length;
|
||||
#if defined SHARED_MODULE
|
||||
mutex_unlock(&vecreallocMutex);
|
||||
#endif
|
||||
} /* end of function dvec_extend */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ Author: 1985 Wayne A. Christopher
|
|||
#include "subckt.h"
|
||||
#include "spiceif.h"
|
||||
#include "com_let.h"
|
||||
#include "com_set.h"
|
||||
#include "com_commands.h"
|
||||
|
||||
#ifdef XSPICE
|
||||
|
|
@ -57,8 +58,9 @@ static wordlist *inp_savecurrents(struct card *deck, struct card *options,
|
|||
wordlist *wl, wordlist *controls);
|
||||
static void recifeval(struct card *pdeck);
|
||||
static char *upper(register char *string);
|
||||
#ifdef REM_UNUSED
|
||||
static void rem_unused_mos_models(struct card* deck);
|
||||
|
||||
#endif
|
||||
extern void com_optran(wordlist * wl);
|
||||
extern void tprint(struct card *deck);
|
||||
|
||||
|
|
@ -88,6 +90,17 @@ extern void exec_controls(wordlist *controls);
|
|||
extern void SetSource(char *Name);
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
typedef struct timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
} timeval;
|
||||
#endif
|
||||
#if defined (_MSC_VER) || defined (__MINGW32__)
|
||||
extern int gettimeofday(struct timeval* tp, void* unused);
|
||||
#endif
|
||||
|
||||
|
||||
/* structure used to save expression parse trees for .model and
|
||||
* device instance lines
|
||||
*/
|
||||
|
|
@ -100,6 +113,7 @@ struct pt_temper {
|
|||
struct pt_temper *next;
|
||||
};
|
||||
|
||||
|
||||
static int inp_parse_temper(struct card *deck,
|
||||
struct pt_temper **motdlist_p,
|
||||
struct pt_temper **devtlist_p);
|
||||
|
|
@ -438,9 +452,10 @@ eval_opt(struct card* deck)
|
|||
char* token = gettok(&begtok);
|
||||
/* option seed=random [seed='random'] */
|
||||
if (eq(token, "random") || eq(token, "{random}")) {
|
||||
time_t acttime = time(NULL);
|
||||
/* get random value from time in seconds since 1.1.1970 */
|
||||
int rseed = (int)(acttime - 1600000000);
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
/* get random value from current timestamp microseconds */
|
||||
int rseed = (int)(tv.tv_usec);
|
||||
cp_vset("rndseed", CP_NUM, &rseed);
|
||||
com_sseed(NULL);
|
||||
has_seed = TRUE;
|
||||
|
|
@ -623,10 +638,71 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
* the cards .control and .endc, unless comfile is TRUE, in which
|
||||
* case every line must be a front-end command. There are too
|
||||
* many problems with matching the first word on the line. */
|
||||
|
||||
ld = deck;
|
||||
if (comfile) {
|
||||
bool with_params = FALSE;
|
||||
|
||||
#ifndef SHARED_MODULE
|
||||
if (ciprefix("*ng_script_with_params", deck->line)) {
|
||||
extern char **Copy_of_argv; // main.c
|
||||
extern int optind; // Library function getopt()
|
||||
static const char header[] = "argc = %u argv = ( ";
|
||||
wordlist *setarg;
|
||||
unsigned int argc, size;
|
||||
char *p_buf_active; /* buffer in use */
|
||||
char buf[BSIZE_SP];
|
||||
|
||||
/* Not just a command script, but one requesting arguments
|
||||
* from the program's command line.
|
||||
* This is similar to cp_oddcomm() (cpitf.c),
|
||||
* but arguments are taken from the original program command.
|
||||
*/
|
||||
|
||||
with_params = TRUE;
|
||||
size = sizeof header + 10; // Allow for %u and close.
|
||||
for (argc = 0; Copy_of_argv[optind + argc]; ++argc)
|
||||
size += strlen(Copy_of_argv[optind + argc]);
|
||||
size += 3 * argc; // Spaces and quotes.
|
||||
if (size <= sizeof buf)
|
||||
p_buf_active = buf;
|
||||
else
|
||||
p_buf_active = TMALLOC(char, size);
|
||||
|
||||
/* Fill the buffer. */
|
||||
|
||||
size = sprintf(p_buf_active, header, argc);
|
||||
while (Copy_of_argv[optind]) {
|
||||
char c, *fmt;
|
||||
|
||||
c = Copy_of_argv[optind][0];
|
||||
if ((c >= '0' && c <= '9') || c == '+' || c == '-' || !c) {
|
||||
/* Looks like a number or empty string - quote it. */
|
||||
|
||||
fmt = " \"%s\"";
|
||||
} else {
|
||||
fmt = " %s";
|
||||
}
|
||||
size += sprintf(p_buf_active + size, fmt,
|
||||
Copy_of_argv[optind++]);
|
||||
}
|
||||
strcpy(p_buf_active + size, " )");
|
||||
|
||||
/* Treat the buffer as a "set" command to create argv and argc. */
|
||||
|
||||
setarg = cp_lexer(p_buf_active);
|
||||
com_set(setarg);
|
||||
wl_free(setarg);
|
||||
|
||||
/* Free buffer allocation if made */
|
||||
|
||||
if (p_buf_active != buf)
|
||||
txfree(p_buf_active);
|
||||
}
|
||||
#endif
|
||||
/* Process each command, except 'option' which is assembled
|
||||
in a list and ingnored here */
|
||||
|
||||
for (dd = deck; dd; dd = ld) {
|
||||
ld = dd->nextcard;
|
||||
if ((dd->line[0] == '*') && (dd->line[1] != '#'))
|
||||
|
|
@ -641,6 +717,12 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
cp_evloop(dd->line);
|
||||
}
|
||||
}
|
||||
|
||||
if (with_params) {
|
||||
cp_remvar("argc");
|
||||
cp_remvar("argv");
|
||||
}
|
||||
|
||||
/* free the control deck */
|
||||
line_free(deck, TRUE);
|
||||
/* set to NULL to allow generation of a new dbs */
|
||||
|
|
@ -929,10 +1011,11 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
}
|
||||
|
||||
/* merge the two option line structs
|
||||
com_options (comfile == TRUE, filled in from spinit, .spiceinit, and *ng_sript), and
|
||||
options (comfile == FALSE, filled in from circuit with .OPTIONS)
|
||||
com_options (comfile == TRUE, filled in from spinit,
|
||||
.spiceinit, and *ng_script), and options
|
||||
(comfile == FALSE, filled in from circuit with .OPTIONS)
|
||||
into options, thus keeping com_options,
|
||||
options is loaded into circuit and freed when circuit is removed */
|
||||
options is loaded into circuit and freed when circuit is removed */
|
||||
options = line_reverse(line_nconc(options, inp_deckcopy(com_options)));
|
||||
|
||||
/* List of all expressions found in instance and .model lines */
|
||||
|
|
@ -955,14 +1038,14 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
/* If user wants all currents saved (.options savecurrents), add .save
|
||||
to wl_first with all terminal currents available on selected devices */
|
||||
wl_first = inp_savecurrents(deck, options, wl_first, controls);
|
||||
|
||||
#ifdef REM_UNUSED
|
||||
/* Circuit is flat, all numbers expanded.
|
||||
So again try to remove unused MOS models.
|
||||
All binning models are still here when w or l have been
|
||||
determined by an expression. */
|
||||
// if (newcompat.hs || newcompat.spe)
|
||||
// rem_unused_mos_models(deck->nextcard);
|
||||
|
||||
if (newcompat.hs || newcompat.spe)
|
||||
rem_unused_mos_models(deck->nextcard);
|
||||
#endif
|
||||
/* now load deck into ft_curckt -- the current circuit. */
|
||||
if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0)
|
||||
return 1;
|
||||
|
|
@ -2541,6 +2624,7 @@ struct mlist {
|
|||
bool checked;
|
||||
};
|
||||
|
||||
#ifdef REM_UNUSED
|
||||
/* Finally get rid of unused MOS models */
|
||||
static void rem_unused_mos_models(struct card* deck) {
|
||||
struct card *tmpc, *tmppc = NULL;
|
||||
|
|
@ -2744,3 +2828,4 @@ static void rem_unused_mos_models(struct card* deck) {
|
|||
modellist = tlist;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -584,6 +584,7 @@ static void delete_names(struct names *p)
|
|||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef CIDER
|
||||
/* concatenate 2 strings, with space if spa == TRUE,
|
||||
return malloced string (replacement for tprintf,
|
||||
which is not efficient enough when reading PDKs
|
||||
|
|
@ -613,6 +614,7 @@ static char *cat2strings(char *s1, char *s2, bool spa)
|
|||
return strsum;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* line1
|
||||
|
|
@ -1589,8 +1591,11 @@ struct inp_read_t inp_read( FILE *fp, int call_depth, const char *dir_name,
|
|||
|
||||
/* add Inp_Path to buffer while keeping the sourcepath variable contents */
|
||||
if (ciprefix("set", buffer)) {
|
||||
char *p = strstr(buffer, "sourcepath");
|
||||
if (p) {
|
||||
char *p;
|
||||
|
||||
p = skip_ws(buffer + 3); // Next word
|
||||
if (strncmp(p, "sourcepath", 10) == 0 &&
|
||||
skip_non_ws(p) == p + 10) {
|
||||
p = strchr(buffer, ')');
|
||||
if (p) {
|
||||
*p = 0; // clear ) and insert Inp_Path in between
|
||||
|
|
@ -3108,7 +3113,8 @@ void inp_casefix(char *string)
|
|||
/* Special treatment of code model file input. */
|
||||
|
||||
if (ciprefix(".model", string))
|
||||
tmpstr = strstr(string, "file=");
|
||||
tmpstr = strstr(string, "file=\"");
|
||||
|
||||
#endif
|
||||
keepquotes = ciprefix(".param", string); // Allow string params
|
||||
|
||||
|
|
@ -3184,8 +3190,6 @@ static void inp_stripcomments_deck(struct card *c, bool cf)
|
|||
If there is only white space before the end-of-line comment the
|
||||
the whole line is converted to a normal comment line (i.e. one that
|
||||
begins with a '*').
|
||||
BUG: comment characters in side of string literals are not ignored
|
||||
('$' outside of .control section is o.k. however).
|
||||
|
||||
If the comaptibility mode is PS, LTPS or LTPSA, '$' is treated as a valid
|
||||
character, not as end-of-line comment delimiter, except for that it is
|
||||
|
|
@ -3202,6 +3206,24 @@ static void inp_stripcomments_line(char *s, bool cs)
|
|||
/* look for comments */
|
||||
while ((c = *d) != '\0') {
|
||||
d++;
|
||||
|
||||
/* Skip over single or double-quoted strings. */
|
||||
|
||||
if (c == '"') {
|
||||
while ((c = *d) && (c != '"' || d[-1] == '\\'))
|
||||
++d;
|
||||
if (c)
|
||||
++d;
|
||||
continue;
|
||||
}
|
||||
if (c == '\'') {
|
||||
while ((c = *d) && (c != '\'' || d[-1] == '\\'))
|
||||
++d;
|
||||
if (c)
|
||||
++d;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*d == ';') {
|
||||
break;
|
||||
}
|
||||
|
|
@ -3310,7 +3332,8 @@ static char *inp_fix_subckt(struct names *subckt_w_params, char *s)
|
|||
char *equal, *beg, *buffer, *ptr1, *ptr2, *new_str;
|
||||
|
||||
equal = strchr(s, '=');
|
||||
if (equal && !strstr(s, "params:")) {
|
||||
if (equal &&
|
||||
(!strstr(s, "params:") || !isspace_c(s[-1]))) {
|
||||
/* get subckt name (ptr1 will point to name) */
|
||||
ptr1 = skip_non_ws(s);
|
||||
ptr1 = skip_ws(ptr1);
|
||||
|
|
@ -3481,7 +3504,7 @@ static void inp_fix_for_numparam(
|
|||
if (ciprefix(".subckt", c->line) || ciprefix("x", c->line)) {
|
||||
/* remove params: */
|
||||
char *str_ptr = strstr(c->line, "params:");
|
||||
if (str_ptr)
|
||||
if (str_ptr && isspace_c(str_ptr[-1]))
|
||||
memcpy(str_ptr, " ", 7);
|
||||
}
|
||||
|
||||
|
|
@ -3782,13 +3805,14 @@ static int inp_fix_subckt_multiplier(struct names *subckt_w_params,
|
|||
char *subckt_param_names[], char *subckt_param_values[])
|
||||
{
|
||||
struct card *card;
|
||||
char *new_str;
|
||||
char *new_str, *s;
|
||||
|
||||
subckt_param_names[num_subckt_params] = copy("m");
|
||||
subckt_param_values[num_subckt_params] = copy("1");
|
||||
num_subckt_params++;
|
||||
|
||||
if (!strstr(subckt_card->line, "params:")) {
|
||||
s = strstr(subckt_card->line, "params:");
|
||||
if (!s || !isspace_c(s[-1])) {
|
||||
new_str = tprintf("%s params: m=1", subckt_card->line);
|
||||
add_name(subckt_w_params, get_subckt_model_name(subckt_card->line));
|
||||
}
|
||||
|
|
@ -7842,6 +7866,9 @@ static void inp_quote_params(struct card *c, struct card *end_c,
|
|||
{
|
||||
bool in_control = FALSE;
|
||||
|
||||
if (ft_skywaterpdk)
|
||||
return;
|
||||
|
||||
for (; c && c != end_c; c = c->nextcard) {
|
||||
|
||||
int i, j, num_terminals;
|
||||
|
|
@ -8333,6 +8360,7 @@ static void inp_check_syntax(struct card *deck)
|
|||
bool mwarn = FALSE;
|
||||
char* subs[10]; /* store subckt lines */
|
||||
int ends = 0; /* store .ends line numbers */
|
||||
static bool nesting_once = TRUE;
|
||||
|
||||
/* prevent crash in inp.c, fcn inp_spsource: */
|
||||
if (ciprefix(".param", deck->line) || ciprefix(".meas", deck->line)) {
|
||||
|
|
@ -8405,10 +8433,12 @@ static void inp_check_syntax(struct card *deck)
|
|||
}
|
||||
}
|
||||
// nesting may be critical if params are involved
|
||||
if (check_subs > 0 && strchr(cut_line, '='))
|
||||
if (nesting_once && check_subs > 0 && strchr(cut_line, '=')) {
|
||||
fprintf(cp_err,
|
||||
"\nWarning: Nesting of subcircuits with parameters "
|
||||
"is only marginally supported!\n\n");
|
||||
"\nWarning: Nesting of subcircuits with parameters "
|
||||
"is only marginally supported!\n\n");
|
||||
nesting_once = FALSE;
|
||||
}
|
||||
if (check_subs < 10)
|
||||
subs[check_subs] = cut_line;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
|
||||
bool ft_acctprint = FALSE, ft_noacctprint = FALSE, ft_listprint = FALSE;
|
||||
bool ft_nodesprint = FALSE, ft_optsprint = FALSE, ft_noinitprint = FALSE;
|
||||
bool ft_norefprint = FALSE;
|
||||
bool ft_norefprint = FALSE, ft_skywaterpdk = FALSE;
|
||||
bool ft_ngdebug = FALSE, ft_nginfo = FALSE, ft_stricterror = FALSE;
|
||||
|
||||
static void setdb(char *str);
|
||||
|
|
@ -307,6 +307,8 @@ cp_usrset(struct variable *var, bool isset)
|
|||
ft_ngdebug = isset;
|
||||
} else if (eq(var->va_name, "nginfo")) {
|
||||
ft_nginfo = isset;
|
||||
} else if (eq(var->va_name, "skywaterpdk")) {
|
||||
ft_skywaterpdk = isset;
|
||||
} else if (eq(var->va_name, "noinit")) {
|
||||
ft_noinitprint = isset;
|
||||
} else if (eq(var->va_name, "norefvalue")) {
|
||||
|
|
|
|||
|
|
@ -1542,6 +1542,7 @@ InterpFileAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
|
|||
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||
fileAddRealValue(run->fp, run->binary, newval);
|
||||
valueold[i] = valuenew[i];
|
||||
timeold = refValue->rValue;
|
||||
}
|
||||
else if (nodata)
|
||||
/* Just keep the transient output value corresponding to timeold,
|
||||
|
|
@ -1573,6 +1574,7 @@ InterpFileAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
|
|||
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||
fileAddRealValue(run->fp, run->binary, newval);
|
||||
valueold[i] = valuenew[i];
|
||||
timeold = refValue->rValue;
|
||||
}
|
||||
else if (nodata)
|
||||
/* Just keep the transient output value corresponding to timeold,
|
||||
|
|
@ -1705,6 +1707,7 @@ InterpPlotAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
|
|||
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||
plotAddRealValue(&run->data[i], newval);
|
||||
valueold[i] = valuenew[i];
|
||||
timeold = refValue->rValue;
|
||||
}
|
||||
else if (nodata)
|
||||
/* Just keep the transient output value corresponding to timeold,
|
||||
|
|
@ -1727,6 +1730,7 @@ InterpPlotAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
|
|||
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||
plotAddRealValue(&run->data[i], newval);
|
||||
valueold[i] = valuenew[i];
|
||||
timeold = refValue->rValue;
|
||||
}
|
||||
else if (nodata)
|
||||
/* Just keep the transient output value corresponding to timeold,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ Modified: 2000 AlansFixes
|
|||
#include "ngspice/fteinp.h"
|
||||
#include "ngspice/stringskip.h"
|
||||
#include "ngspice/compatmode.h"
|
||||
#include "ngspice/hash.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
|
@ -95,14 +96,17 @@ static int translate(struct card *deck, char *formal, int flen, char *actual,
|
|||
struct bxx_buffer;
|
||||
static void finishLine(struct bxx_buffer *dst, char *src, char *scname);
|
||||
static int settrans(char *formal, int flen, char *actual, const char *subname);
|
||||
static char *gettrans(const char *name, const char *name_end);
|
||||
static char *gettrans(const char *name, const char *name_end, bool *isglobal);
|
||||
static int numnodes(const char *line, struct subs *subs, wordlist const *modnames);
|
||||
static int numdevs(char *s);
|
||||
static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames);
|
||||
static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames);
|
||||
static int inp_numnodes(char c);
|
||||
|
||||
#define N_GLOBAL_NODES 1005
|
||||
/* hash table to store the global nodes
|
||||
* For now its use is limited to avoid double entries in global_nodes[] */
|
||||
static NGHASHPTR glonodes = NULL;
|
||||
#define DUMMYDATA ((void *)42)
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* table is used in settrans and gettrans -- it holds the netnames used
|
||||
|
|
@ -137,19 +141,16 @@ static bool use_numparams = FALSE;
|
|||
|
||||
static char start[32], sbend[32], invoke[32], model[32];
|
||||
|
||||
static char *global_nodes[N_GLOBAL_NODES];
|
||||
static int num_global_nodes;
|
||||
|
||||
|
||||
static void
|
||||
collect_global_nodes(struct card *c)
|
||||
{
|
||||
num_global_nodes = 0;
|
||||
|
||||
global_nodes[num_global_nodes++] = copy("0");
|
||||
/* hash table for global nodes */
|
||||
glonodes = nghash_init(NGHASH_MIN_SIZE);
|
||||
|
||||
/* add 0 and null as global nodes */
|
||||
nghash_insert(glonodes, "0", DUMMYDATA);
|
||||
#ifdef XSPICE
|
||||
global_nodes[num_global_nodes++] = copy("null");
|
||||
nghash_insert(glonodes, "null", DUMMYDATA);
|
||||
#endif
|
||||
|
||||
for (; c; c = c->nextcard)
|
||||
|
|
@ -157,17 +158,20 @@ collect_global_nodes(struct card *c)
|
|||
char *s = c->line;
|
||||
s = nexttok(s);
|
||||
while (*s) {
|
||||
if (num_global_nodes == N_GLOBAL_NODES) {
|
||||
fprintf(stderr, "ERROR, N_GLOBAL_NODES overflow\n");
|
||||
controlled_exit(EXIT_FAILURE);
|
||||
}
|
||||
char *t = skip_non_ws(s);
|
||||
global_nodes[num_global_nodes++] = copy_substring(s, t);
|
||||
/* global node name */
|
||||
char *gnode = copy_substring(s, t);
|
||||
/* insert only if not yet found in table */
|
||||
if (gnode && *gnode != '\0' && nghash_find(glonodes, gnode) == NULL) {
|
||||
nghash_insert(glonodes, gnode, DUMMYDATA);
|
||||
}
|
||||
tfree(gnode);
|
||||
s = skip_ws(t);
|
||||
}
|
||||
c->line[0] = '*'; /* comment it out */
|
||||
}
|
||||
|
||||
|
||||
#ifdef TRACE
|
||||
{
|
||||
int i;
|
||||
|
|
@ -184,10 +188,7 @@ collect_global_nodes(struct card *c)
|
|||
static void
|
||||
free_global_nodes(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_global_nodes; i++)
|
||||
tfree(global_nodes[i]);
|
||||
num_global_nodes = 0;
|
||||
nghash_free(glonodes, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1107,14 +1108,19 @@ bxx_buffer(struct bxx_buffer *t)
|
|||
static void
|
||||
translate_node_name(struct bxx_buffer *buffer, const char *scname, const char *name, const char *name_e)
|
||||
{
|
||||
|
||||
const char *t;
|
||||
bool isglobal;
|
||||
|
||||
if (!name_e)
|
||||
name_e = strchr(name, '\0');
|
||||
|
||||
t = gettrans(name, name_e);
|
||||
t = gettrans(name, name_e, &isglobal);
|
||||
|
||||
if (t) {
|
||||
bxx_put_cstring(buffer, t);
|
||||
/* free only if t is global node, nodes from table[].t_new are freed elsewhere */
|
||||
if(isglobal)
|
||||
tfree(t);
|
||||
} else {
|
||||
bxx_put_cstring(buffer, scname);
|
||||
bxx_putc(buffer, '.');
|
||||
|
|
@ -1624,21 +1630,28 @@ eq_substr(const char *str, const char *end, const char *cstring)
|
|||
* otherwise it returns NULL.
|
||||
*------------------------------------------------------------------------------*/
|
||||
static char *
|
||||
gettrans(const char *name, const char *name_end)
|
||||
gettrans(const char *name, const char *name_end, bool *isglobal)
|
||||
{
|
||||
int i;
|
||||
*isglobal = FALSE;
|
||||
|
||||
if (!name_end)
|
||||
name_end = strchr(name, '\0');
|
||||
|
||||
/* Added by H.Tanaka to translate global nodes */
|
||||
for (i = 0; i<num_global_nodes; i++)
|
||||
if (eq_substr(name, name_end, global_nodes[i]))
|
||||
return (global_nodes[i]);
|
||||
char* newgl = copy_substring(name, name_end);
|
||||
if (nghash_find(glonodes, newgl)) {
|
||||
*isglobal = TRUE;
|
||||
return newgl;
|
||||
}
|
||||
else
|
||||
tfree(newgl);
|
||||
|
||||
for (i = 0; table[i].t_old; i++)
|
||||
if (eq_substr(name, name_end, table[i].t_old))
|
||||
return (table[i].t_new);
|
||||
if (eq_substr(name, name_end, table[i].t_old)) {
|
||||
*isglobal = FALSE;
|
||||
return table[i].t_new;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
|
@ -1682,6 +1695,9 @@ numnodes(const char *line, struct subs *subs, wordlist const *modnames)
|
|||
return (nodes);
|
||||
}
|
||||
}
|
||||
/* if we use option skywaterpdk, MOS has four nodes. Required if number of devices is large */
|
||||
if (ft_skywaterpdk && c == 'm')
|
||||
return 4;
|
||||
|
||||
n = inp_numnodes(c);
|
||||
|
||||
|
|
|
|||
|
|
@ -791,8 +791,6 @@ cp_getvar(char *name, enum cp_types type, void *retval, size_t rsize)
|
|||
* variable *, which allows the host program to provide values for
|
||||
* non-cshpar variables. */
|
||||
|
||||
char cp_dol = '$';
|
||||
|
||||
/* Non-alphanumeric characters that may appear in variable names. < is very
|
||||
* special...
|
||||
*/
|
||||
|
|
@ -808,10 +806,11 @@ char cp_dol = '$';
|
|||
* Return value
|
||||
* Address of the first character after the variable name.
|
||||
*/
|
||||
char *span_var_expr(char *t)
|
||||
char *span_var_expr(char *s)
|
||||
{
|
||||
int parenthesis = 0;
|
||||
int brackets = 0;
|
||||
char *t = s;
|
||||
int parenthesis = 0;
|
||||
int brackets = 0;
|
||||
|
||||
while (*t && (isalnum_c(*t) || strchr(VALIDCHARS, *t)))
|
||||
switch (*t++)
|
||||
|
|
@ -834,6 +833,14 @@ char *span_var_expr(char *t)
|
|||
if (--parenthesis <= 0)
|
||||
return t;
|
||||
break;
|
||||
case '$':
|
||||
if (brackets <= 0 && parenthesis <= 0) {
|
||||
if (t == s + 1) // Special case: "$$".
|
||||
return t;
|
||||
else
|
||||
return t-1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -852,7 +859,7 @@ wordlist *cp_variablesubst(wordlist *wlist)
|
|||
char *s_dollar;
|
||||
int i = 0;
|
||||
|
||||
while ((s_dollar = strchr(wl->wl_word + i, cp_dol)) != NULL) {
|
||||
while ((s_dollar = strchr(wl->wl_word + i, '$')) != NULL) {
|
||||
|
||||
int prefix_len = (int) (s_dollar - wl->wl_word);
|
||||
|
||||
|
|
@ -1002,6 +1009,8 @@ wordlist *vareval(/* NOT const */ char *string)
|
|||
if (eq(v->va_name, string))
|
||||
break;
|
||||
if (!v && isdigit_c(*string)) {
|
||||
/* Treat $i for some integer i as argv[i] - positional parameters. */
|
||||
|
||||
for (v = variables; v; v = v->va_next) {
|
||||
if (eq(v->va_name, "argv")) {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ NON-STANDARD FEATURES
|
|||
|
||||
#define ANALOG MIF_ANALOG
|
||||
#define EVENT MIF_EVENT_DRIVEN
|
||||
#define STEP_PENDING MIF_STEP_PENDING
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ int cm_message_printf(const char *fmt, ...);
|
|||
double cm_netlist_get_c(void);
|
||||
double cm_netlist_get_l(void);
|
||||
|
||||
void cm_irreversible(unsigned int);
|
||||
const char *cm_get_node_name(const char *, unsigned int);
|
||||
bool cm_probe_node(unsigned int, unsigned int, void *);
|
||||
bool cm_schedule_output(unsigned int, unsigned int, double, void *);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
/* Header file for the shim code between d_cosim and a co-simulator. */
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* A value of this type controls how the step() function is called.
|
||||
* The normal method is to call step() to advance to the time of a
|
||||
* queued input, then supply the input, then call step again to
|
||||
* advance to the next input time or the end of the current SPICE
|
||||
* timestep. But Verilator does nothing without an input change,
|
||||
* so step() must be called after input.
|
||||
*/
|
||||
|
||||
typedef enum {Normal, After_input} Cosim_method;
|
||||
|
||||
/* Structure used by Cosim_setup() to pass and return
|
||||
* co-simulation interface information.
|
||||
*/
|
||||
|
||||
struct co_info {
|
||||
/* The co-simulator must set the number of ports in Cosim_setup(). */
|
||||
|
||||
unsigned int in_count;
|
||||
unsigned int out_count;
|
||||
unsigned int inout_count;
|
||||
|
||||
/* The co-simulator may specify a function to be called just before
|
||||
* it is unloaded at the end of a simulation run.
|
||||
*/
|
||||
|
||||
void (*cleanup)(struct co_info *);
|
||||
|
||||
/* Function called by SPICE to advance the co-simulation.
|
||||
* A pointer to this structure is passed, so it has access to its handle
|
||||
* and the target simulation time, vtime. The co-simulator should
|
||||
* pause the step when output is produced and update vtime.
|
||||
*/
|
||||
|
||||
void (*step)(struct co_info *pinfo); // Advance simulation.
|
||||
|
||||
/* Function called by SPICE to pass input to input and inout ports.
|
||||
* (Inouts after inputs.)
|
||||
* Called as:
|
||||
* struct co_info info;
|
||||
* (*in_fn)(&info, bit_number, &value);
|
||||
* Function provided by co-simulator.
|
||||
*/
|
||||
|
||||
void (*in_fn)(struct co_info *, unsigned int, Digital_t *);
|
||||
|
||||
/* Function called by co-simulator to report output on
|
||||
* output and inout ports. (Inouts after outputs.)
|
||||
* Called as:
|
||||
* struct co_info *p_info;
|
||||
* (*out_fn)(p_info, bit_number, &value);
|
||||
* It will usually be called inside a call to step().
|
||||
*/
|
||||
|
||||
void (*out_fn)(struct co_info *, unsigned int, Digital_t *);
|
||||
void *handle; // Co-simulator's private handle
|
||||
double vtime; // Time in the co-simulation.
|
||||
Cosim_method method; // May be set in Cosim_setup;
|
||||
};
|
||||
|
||||
extern void Cosim_setup(struct co_info *pinfo); // This must exist.
|
||||
extern void Cosim_step(struct co_info *pinfo); // Exists for Verilator.
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -156,7 +156,6 @@ extern bool cp_ignoreeof;
|
|||
extern bool cp_noclobber;
|
||||
extern bool cp_noglob;
|
||||
extern bool cp_nonomatch;
|
||||
extern char cp_dol;
|
||||
extern void cp_remvar(char *varname);
|
||||
void cp_vset(const char *varname, enum cp_types type, const void *value);
|
||||
extern struct variable *cp_setparse(wordlist *wl);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ struct coreInfo_t {
|
|||
int ((*dllitf_cm_message_send)(char *));
|
||||
double ((*dllitf_cm_netlist_get_c)(void));
|
||||
double ((*dllitf_cm_netlist_get_l)(void));
|
||||
void ((*dllitf_cm_irreversible)(unsigned int));
|
||||
const char * ((*dllitf_cm_get_node_name)(const char *, unsigned int));
|
||||
bool ((*dllitf_cm_probe_node)(unsigned int, unsigned int,
|
||||
void *));
|
||||
|
|
|
|||
|
|
@ -91,35 +91,27 @@ struct Evt_Node_Info {
|
|||
};
|
||||
|
||||
struct Evt_Inst_Info {
|
||||
Evt_Inst_Info_t *next; /* the next in the linked list of node info */
|
||||
Evt_Inst_Info_t *next; /* the next in the linked list */
|
||||
MIFinstance *inst_ptr; /* Pointer to MIFinstance struct for this instance */
|
||||
};
|
||||
|
||||
struct Evt_Info {
|
||||
Evt_Inst_Info_t *inst_list; /* static info about event/hybrid instances */
|
||||
Evt_Node_Info_t *node_list; /* static info about event nodes */
|
||||
Evt_Port_Info_t *port_list; /* static info about event ports */
|
||||
Evt_Output_Info_t *output_list; /* static info about event outputs */
|
||||
int *hybrid_index; /* vector of inst indexs for hybrids */
|
||||
Evt_Inst_Info_t **inst_table; /* vector of pointers to elements in inst_list */
|
||||
Evt_Node_Info_t **node_table; /* vector of pointers to elements in node_list */
|
||||
Evt_Port_Info_t **port_table; /* vector of pointers to elements in port_list */
|
||||
Evt_Output_Info_t **output_table; /* vector of pointers to elements in output_list */
|
||||
Evt_Inst_Info_t *inst_list; /* static info about event instances */
|
||||
Evt_Node_Info_t *node_list; /* static info about event nodes */
|
||||
Evt_Port_Info_t *port_list; /* static info about event ports */
|
||||
Evt_Output_Info_t *output_list; /* static info about event outputs */
|
||||
MIFinstance **hybrids; /* vector of inst pointers for hybrids */
|
||||
Evt_Inst_Info_t **inst_table; /* vector of pointers to elements in inst_list */
|
||||
Evt_Node_Info_t **node_table; /* vector of pointers to elements in node_list */
|
||||
Evt_Port_Info_t **port_table; /* vector of pointers to elements in port_list */
|
||||
Evt_Output_Info_t **output_table; /* vector of pointers to elements in output_list */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* *************** */
|
||||
/* Queue structure */
|
||||
/* *************** */
|
||||
|
||||
|
||||
|
||||
struct Evt_Inst_Event {
|
||||
Evt_Inst_Event_t *next; /* the next in the linked list */
|
||||
double event_time; /* Time for this event to happen */
|
||||
|
|
|
|||
|
|
@ -92,7 +92,9 @@ void EVTqueue_inst(
|
|||
|
||||
void EVTdequeue(CKTcircuit *ckt, double time);
|
||||
|
||||
int EVTload(CKTcircuit *ckt, int inst_index);
|
||||
int EVTload(CKTcircuit *ckt, MIFinstance *inst);
|
||||
|
||||
int EVTload_with_event(CKTcircuit *ckt, MIFinstance *inst, Mif_Call_Type_t type);
|
||||
|
||||
void EVTprint(wordlist *wl);
|
||||
void EVTprintvcd(wordlist *wl);
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@ extern struct card *inp_getoptsc(char *line, struct card *options);
|
|||
extern bool ft_ngdebug;
|
||||
extern bool ft_nginfo;
|
||||
extern bool ft_stricterror;
|
||||
extern bool ft_skywaterpdk;
|
||||
|
||||
/* parse.c */
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ struct MIFinstance {
|
|||
|
||||
Mif_Boolean_t analog; /* true if this inst is analog or hybrid type */
|
||||
Mif_Boolean_t event_driven; /* true if this inst is event-driven or hybrid type */
|
||||
unsigned int irreversible; /* non-zero for special treatment */
|
||||
|
||||
int inst_index; /* Index into inst_table in evt struct in ckt */
|
||||
Mif_Callback_t callback; /* instance callback function */
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ typedef enum {
|
|||
typedef enum {
|
||||
MIF_ANALOG, /* Analog call */
|
||||
MIF_EVENT_DRIVEN, /* Event-driven call */
|
||||
MIF_STEP_PENDING, /* Special event call for irreversible Code Models */
|
||||
} Mif_Call_Type_t;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ enum {
|
|||
|
||||
#ifdef KLU
|
||||
OPT_SPARSE,
|
||||
OPT_KLU,
|
||||
OPT_KLU_MEMGROW_FACTOR,
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ typedef struct linked_lists_of_Bpoint{
|
|||
} BPOINT, *BPOINTPTR;
|
||||
|
||||
typedef struct linked_lists_of_nodeName{
|
||||
char id[24];
|
||||
char id[256];
|
||||
struct linked_lists_of_nodeName *left, *right;
|
||||
NODE *nd;
|
||||
} NDname, *NDnamePt;
|
||||
|
|
|
|||
46
src/main.c
46
src/main.c
|
|
@ -164,6 +164,8 @@ double EpsNorm, VNorm, NNorm, LNorm, TNorm, JNorm, GNorm, ENorm;
|
|||
/* end cider globals */
|
||||
#endif /* CIDER */
|
||||
|
||||
char **Copy_of_argv; // Used to recover args for *ng_script_with_params files
|
||||
|
||||
struct variable *(*if_getparam)(CKTcircuit *ckt, char **name, char *param, int ind, int do_model);
|
||||
|
||||
/* static functions */
|
||||
|
|
@ -1382,13 +1384,16 @@ int main(int argc, char **argv)
|
|||
while (optind < argc) {
|
||||
char *arg = argv[optind++];
|
||||
FILE *tp;
|
||||
|
||||
/* Copy the the path of the first filename only */
|
||||
if (!Infile_Path) {
|
||||
Infile_Path = ngdirname(arg);
|
||||
}
|
||||
|
||||
/* unquote the input string, needed if it results from double clicking the filename */
|
||||
#if defined(HAS_WINGUI)
|
||||
/* Unquote the input string, needed if it results
|
||||
* from double clicking the filename.
|
||||
*/
|
||||
arg = cp_unquote(arg);
|
||||
#endif
|
||||
/* Copy all the arguments into the temporary file */
|
||||
|
|
@ -1401,15 +1406,22 @@ int main(int argc, char **argv)
|
|||
tp = fopen(p, "r");
|
||||
tfree(p);
|
||||
}
|
||||
|
||||
if (!tp) {
|
||||
perror(arg);
|
||||
err = 1;
|
||||
break;
|
||||
/* Try and find it in a directory in $sourcepath. */
|
||||
|
||||
tp = inp_pathopen(arg, "r");
|
||||
if (!tp) {
|
||||
perror(arg);
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the input file name which otherwise will be lost due to the
|
||||
temporary file */
|
||||
/* Copy the input file name which otherwise will be lost
|
||||
* due to the temporary file.
|
||||
*/
|
||||
dname = copy(arg);
|
||||
#if defined(HAS_WINGUI)
|
||||
/* write source file name into source window */
|
||||
|
|
@ -1418,11 +1430,32 @@ int main(int argc, char **argv)
|
|||
tfree(arg);
|
||||
#endif
|
||||
|
||||
if (!gotone) {
|
||||
char line[256];
|
||||
|
||||
/* Check for "*ng_script_with_params" as first line. */
|
||||
|
||||
if (fgets(line, sizeof line, tp) &&
|
||||
ciprefix("*ng_script_with_params", line)) {
|
||||
/* Special script file: remaining arguments are
|
||||
* script parameters.
|
||||
*/
|
||||
|
||||
fclose(tempfile);
|
||||
tempfile = tp;
|
||||
Copy_of_argv = argv;
|
||||
break;
|
||||
} else {
|
||||
fseek(tp, 0L, SEEK_SET);
|
||||
gotone = TRUE;
|
||||
}
|
||||
}
|
||||
append_to_stream(tempfile, tp);
|
||||
fclose(tp);
|
||||
}
|
||||
|
||||
fseek(tempfile, 0L, SEEK_SET);
|
||||
gotone = FALSE; // Re-use
|
||||
|
||||
if (tempfile && (!err || !ft_batchmode)) {
|
||||
/* Copy the input file name for becoming another file search path */
|
||||
|
|
@ -1450,7 +1483,6 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (ft_batchmode) {
|
||||
|
||||
int error3 = 1;
|
||||
|
||||
/* If we get back here in batch mode then something is wrong,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ void * cx_mean(void *data, short int type, int length, int *newlength, short int
|
|||
void * cx_stddev(void *data, short int type, int length, int *newlength, short int *newtype);
|
||||
void * cx_length(void *data, short int type, int length, int *newlength, short int *newtype);
|
||||
void * cx_vector(void *data, short int type, int length, int *newlength, short int *newtype);
|
||||
void * cx_cvector(void *data, short int type, int length, int *newlength, short int *newtype);
|
||||
void * cx_unitvec(void *data, short int type, int length, int *newlength, short int *newtype);
|
||||
void * cx_plus(void *data1, void *data2, short int datatype1, short int datatype2, int length);
|
||||
void * cx_minus(void *data1, void *data2, short int datatype1, short int datatype2, int length);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ NIconvTest(CKTcircuit *ckt)
|
|||
double old;
|
||||
double new;
|
||||
double tol;
|
||||
static int nancount = 0;
|
||||
|
||||
node = ckt->CKTnodes;
|
||||
size = SMPmatSize(ckt->CKTmatrix);
|
||||
|
|
@ -41,8 +42,14 @@ NIconvTest(CKTcircuit *ckt)
|
|||
new = ckt->CKTrhs [i] ;
|
||||
old = ckt->CKTrhsOld [i] ;
|
||||
if (isnan(new)) {
|
||||
if (ft_ngdebug)
|
||||
if (ft_ngdebug && nancount < 10) {
|
||||
fprintf(stderr, "Warning: non-convergence, node %s is nan\n", CKTnodName(ckt, i));
|
||||
nancount++;
|
||||
}
|
||||
else if (ft_ngdebug && nancount == 10) {
|
||||
fprintf(stderr, " non-convergence warnings (nan) limited to 10\n", CKTnodName(ckt, i));
|
||||
nancount++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if(node->type == SP_VOLTAGE) {
|
||||
|
|
|
|||
|
|
@ -174,7 +174,14 @@ NIiter(CKTcircuit *ckt, int maxIter)
|
|||
ckt->CKTstat->STATreorderTime += SPfrontEnd->IFseconds() - startTime;
|
||||
if (error) {
|
||||
SMPgetError(ckt->CKTmatrix, &i, &j);
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING, "singular matrix: check nodes %s and %s\n", NODENAME(ckt, i), NODENAME(ckt, j));
|
||||
if (ft_ngdebug || msgcount < 6) {
|
||||
SMPgetError(ckt->CKTmatrix, &i, &j);
|
||||
if (eq(NODENAME(ckt, i), NODENAME(ckt, j)))
|
||||
SPfrontEnd->IFerrorf(ERR_WARNING, "singular matrix: check node %s\n", NODENAME(ckt, i));
|
||||
else
|
||||
SPfrontEnd->IFerrorf(ERR_WARNING, "singular matrix: check nodes %s and %s\n", NODENAME(ckt, i), NODENAME(ckt, j));
|
||||
msgcount += 1;
|
||||
}
|
||||
|
||||
/* CKTload(ckt); */
|
||||
/* SMPprint(ckt->CKTmatrix, stdout); */
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "polyeval.h"
|
||||
#include "polyfit.h"
|
||||
|
||||
/* Returns thestrchr of the last element that was calculated. oval is
|
||||
/* Returns the strchr of the last element that was calculated. oval is
|
||||
* the value of the old scale at the end of the interval that is being
|
||||
* interpolated from, and sign is 1 if the old scale was increasing,
|
||||
* and -1 if it was decreasing. */
|
||||
|
|
@ -30,14 +30,17 @@ putinterval(double *poly, int degree, double *nvec,
|
|||
/* Interpolate data from oscale to nscale. data is assumed to be olen long,
|
||||
* ndata will be nlen long. Returns FALSE if the scales are too strange
|
||||
* to deal with. Note that we are guaranteed that either both scales are
|
||||
* strictly increasing or both are strictly decreasing.
|
||||
* increasing or both are decreasing.
|
||||
*/
|
||||
|
||||
#define EDGE_FACTOR 1e-3
|
||||
|
||||
bool
|
||||
ft_interpolate(double *data, double *ndata, double *oscale, int olen,
|
||||
double *nscale, int nlen, int degree)
|
||||
{
|
||||
double *result, *scratch, *xdata, *ydata;
|
||||
int sign, lastone, i, l;
|
||||
double *result, *scratch, *xdata, *ydata, diff;
|
||||
int sign, lastone, i, l, middle, tdegree;
|
||||
|
||||
if ((olen < 2) || (nlen < 2)) {
|
||||
fprintf(cp_err, "Error: lengths too small to interpolate.\n");
|
||||
|
|
@ -49,30 +52,72 @@ ft_interpolate(double *data, double *ndata, double *oscale, int olen,
|
|||
return (FALSE);
|
||||
}
|
||||
|
||||
if (oscale[1] < oscale[0])
|
||||
sign = -1;
|
||||
else
|
||||
sign = 1;
|
||||
for (i = 0; i < olen - 1; ++i) {
|
||||
if (oscale[i + 1] < oscale[i]) {
|
||||
sign = -1;
|
||||
break;
|
||||
} else if (oscale[i + 1] > oscale[i]) {
|
||||
sign = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= olen) {
|
||||
fprintf(cp_err, "Error: bad scale, can't interpolate.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
scratch = TMALLOC(double, (degree + 1) * (degree + 2));
|
||||
result = TMALLOC(double, degree + 1);
|
||||
xdata = TMALLOC(double, degree + 1);
|
||||
ydata = TMALLOC(double, degree + 1);
|
||||
|
||||
/* Deal with the first degree pieces. */
|
||||
memcpy(ydata, data, (size_t) (degree + 1) * sizeof (double));
|
||||
memcpy(xdata, oscale, (size_t) (degree + 1) * sizeof (double));
|
||||
/* Initial load of the values to be analysed by ft_polyfit(),
|
||||
* skipping irrelevant points and checking for and fudging vertical edges.
|
||||
*/
|
||||
|
||||
while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {
|
||||
i = l = 0;
|
||||
middle = (degree + 1) / 2;
|
||||
if (sign > 0) {
|
||||
while (l < olen - degree && oscale[l + middle] < nscale[0])
|
||||
++l;
|
||||
} else {
|
||||
while (l < olen - degree && oscale[l + middle] > nscale[0])
|
||||
++l;
|
||||
}
|
||||
ydata[0] = data[l];
|
||||
xdata[0] = oscale[l];
|
||||
do {
|
||||
if (oscale[l + 1] == oscale[l]) {
|
||||
if (i == 0) {
|
||||
ydata[0] = data[++l]; // Ignore first point.
|
||||
} else {
|
||||
/* Push the previous x value back, making edge a slope. */
|
||||
|
||||
diff = xdata[i] - xdata[i - 1];
|
||||
xdata[i] -= sign * diff * EDGE_FACTOR;
|
||||
}
|
||||
}
|
||||
xdata[++i] = oscale[++l];
|
||||
ydata[i] = data[l];
|
||||
} while (i < degree && l < olen - 1);
|
||||
|
||||
if (i < degree) {
|
||||
fprintf(cp_err, "Error: too few points to calculate polynomial\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
tdegree = degree;
|
||||
while (!ft_polyfit(xdata + i, ydata + i, result, tdegree, scratch)) {
|
||||
/* If it doesn't work this time, bump the interpolation
|
||||
* degree down by one.
|
||||
*/
|
||||
|
||||
if (--degree == 0) {
|
||||
if (--tdegree == 0) {
|
||||
fprintf(cp_err, "ft_interpolate: Internal Error.\n");
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
if (tdegree % 2)
|
||||
++i; // Drop left point.
|
||||
}
|
||||
|
||||
/* Add this part of the curve. What we do is evaluate the polynomial
|
||||
|
|
@ -81,18 +126,19 @@ ft_interpolate(double *data, double *ndata, double *oscale, int olen,
|
|||
* if the scale is decreasing at the end of the interval we are looking
|
||||
* at.
|
||||
*/
|
||||
lastone = -1;
|
||||
for (i = 0; i < degree; i++) {
|
||||
lastone = putinterval(result, degree, ndata, lastone,
|
||||
nscale, nlen, xdata[i], sign);
|
||||
}
|
||||
|
||||
lastone = putinterval(result, tdegree, ndata, -1,
|
||||
nscale, nlen, xdata[middle], sign);
|
||||
|
||||
/* Now plot the rest, piece by piece. l is the
|
||||
* last element under consideration.
|
||||
*/
|
||||
for (l = degree + 1; l < olen; l++) {
|
||||
for (++l; l < olen; l++) {
|
||||
double out;
|
||||
|
||||
/* Shift the old stuff by one and get another value. */
|
||||
|
||||
out = xdata[0];
|
||||
for (i = 0; i < degree; i++) {
|
||||
xdata[i] = xdata[i + 1];
|
||||
ydata[i] = ydata[i + 1];
|
||||
|
|
@ -100,16 +146,44 @@ ft_interpolate(double *data, double *ndata, double *oscale, int olen,
|
|||
ydata[i] = data[l];
|
||||
xdata[i] = oscale[l];
|
||||
|
||||
while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {
|
||||
if (--degree == 0) {
|
||||
fprintf(cp_err,
|
||||
"interpolate: Internal Error.\n");
|
||||
/* Check for vertical edge. */
|
||||
|
||||
if (oscale[l] == xdata[i - 1]) {
|
||||
if (degree == 1)
|
||||
diff = xdata[0] - out;
|
||||
else
|
||||
diff = xdata[i - 1] - xdata[i - 2];
|
||||
xdata[i - 1] -= sign * diff * EDGE_FACTOR;
|
||||
}
|
||||
|
||||
/* Skip input points until the next output point is framed. */
|
||||
|
||||
if (l < olen - degree) {
|
||||
if (sign > 0 && xdata[middle] < nscale[lastone + 1])
|
||||
continue;
|
||||
else if (sign < 0 && xdata[middle] > nscale[lastone + 1])
|
||||
continue;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
tdegree = degree;
|
||||
while (!ft_polyfit(xdata + i, ydata + i, result, tdegree, scratch)) {
|
||||
/* If it doesn't work this time, bump the interpolation
|
||||
* degree down by one.
|
||||
*/
|
||||
|
||||
if (--tdegree == 0) {
|
||||
fprintf(cp_err, "ft_interpolate: Internal Error.\n");
|
||||
return (FALSE);
|
||||
}
|
||||
if (!((degree - tdegree) & 1))
|
||||
++i; // Drop left point after right.
|
||||
}
|
||||
lastone = putinterval(result, degree, ndata, lastone,
|
||||
nscale, nlen, xdata[i], sign);
|
||||
lastone = putinterval(result, tdegree, ndata, lastone,
|
||||
nscale, nlen, xdata[middle], sign);
|
||||
}
|
||||
lastone = putinterval(result, degree, ndata, lastone,
|
||||
nscale, nlen, oscale[olen - 1], sign);
|
||||
if (lastone < nlen - 1) /* ??? */
|
||||
ndata[nlen - 1] = data[olen - 1];
|
||||
tfree(scratch);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
//#include "ngspice/ngspice.h"
|
||||
#include <Windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <stdint.h> // portable: uint64_t MSVC: __int64
|
||||
|
||||
/*/ MSVC defines this in winsock2.h!?
|
||||
typedef struct timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
} timeval;
|
||||
*/
|
||||
int gettimeofday(struct timeval * tp, void * unused)
|
||||
{
|
||||
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
|
||||
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
|
||||
// until 00:00:00 January 1, 1970
|
||||
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
FILETIME file_time;
|
||||
uint64_t time;
|
||||
|
||||
GetSystemTime( &system_time );
|
||||
SystemTimeToFileTime( &system_time, &file_time );
|
||||
time = ((uint64_t)file_time.dwLowDateTime ) ;
|
||||
time += ((uint64_t)file_time.dwHighDateTime) << 32;
|
||||
|
||||
tp->tv_sec = (long) ((time - EPOCH) / 10000000L);
|
||||
tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -335,7 +335,7 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
|||
* multiple times. We use the handle as a key because the same SO will always
|
||||
* return the SAME pointer as long as dlclose is not called.
|
||||
* nghash_insert returns NULL if the key (handle) was not already in the table
|
||||
* and the data (DUMMYDATA) that was previously insered (!= NULL) otherwise*/
|
||||
* and the data (DUMMYDATA) that was previously inserted (!= NULL) otherwise*/
|
||||
if (nghash_insert(known_object_files, handle, DUMMYDATA)) {
|
||||
txfree(path);
|
||||
return EMPTY_OBJECT;
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ unsigned int main_id, ng_id, command_id;
|
|||
mutexType triggerMutex;
|
||||
mutexType allocMutex;
|
||||
mutexType fputsMutex;
|
||||
mutexType vecreallocMutex;
|
||||
#endif
|
||||
|
||||
/* initialization status */
|
||||
|
|
@ -774,6 +775,8 @@ read_initialisation_file(const char *dir, const char *name)
|
|||
/* The functions exported explicitely from shared ngspice */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
|
||||
#ifdef THREADS
|
||||
|
||||
/* Checks if ngspice is running in the background */
|
||||
|
|
@ -857,16 +860,19 @@ ngSpice_Init(SendChar* printfcn, SendStat* statusfcn, ControlledExit* ngspiceexi
|
|||
pthread_mutex_init(&triggerMutex, NULL);
|
||||
pthread_mutex_init(&allocMutex, NULL);
|
||||
pthread_mutex_init(&fputsMutex, NULL);
|
||||
pthread_mutex_init(&vecreallocMutex, NULL);
|
||||
cont_condition = FALSE;
|
||||
#else
|
||||
#ifdef SRW
|
||||
InitializeSRWLock(&triggerMutex);
|
||||
InitializeSRWLock(&allocMutex);
|
||||
InitializeSRWLock(&fputsMutex);
|
||||
InitializeSRWLock(&vecreallocMutex);
|
||||
#else
|
||||
InitializeCriticalSection(&triggerMutex);
|
||||
InitializeCriticalSection(&allocMutex);
|
||||
InitializeCriticalSection(&fputsMutex);
|
||||
InitializeCriticalSection(&vecreallocMutex);
|
||||
#endif
|
||||
#endif
|
||||
// Id of primary thread
|
||||
|
|
@ -1336,6 +1342,20 @@ char** ngSpice_AllEvtNodes(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Lock/unlock realloc of result vectors during plotting */
|
||||
IMPEXP
|
||||
int ngSpice_LockRealloc(void)
|
||||
{
|
||||
mutex_lock(&vecreallocMutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
IMPEXP
|
||||
int ngSpice_UnlockRealloc(void)
|
||||
{
|
||||
mutex_unlock(&vecreallocMutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* add the preliminary breakpoints to the list.
|
||||
called from dctran.c */
|
||||
|
|
|
|||
|
|
@ -57,11 +57,18 @@ CKTacct(CKTcircuit *ckt, JOB *anal, int which, IFvalue *val)
|
|||
case OPT_FILLNZ:
|
||||
if ( ckt->CKTmatrix != NULL ) {
|
||||
#ifdef KLU
|
||||
if (ckt->CKTmatrix->CKTkluMODE)
|
||||
val->iValue = ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz + ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz
|
||||
- (int)ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNZ ;
|
||||
else
|
||||
if (ckt->CKTmatrix->CKTkluMODE) {
|
||||
if (!ckt->CKTmatrix->SMPkluMatrix ||
|
||||
!ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric) {
|
||||
return -1;
|
||||
}
|
||||
val->iValue =
|
||||
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz +
|
||||
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz -
|
||||
(int)ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNZ ;
|
||||
} else {
|
||||
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
|
||||
}
|
||||
#else
|
||||
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
|
||||
#endif
|
||||
|
|
@ -72,10 +79,14 @@ CKTacct(CKTcircuit *ckt, JOB *anal, int which, IFvalue *val)
|
|||
case OPT_TOTALNZ:
|
||||
if ( ckt->CKTmatrix != NULL ) {
|
||||
#ifdef KLU
|
||||
if (ckt->CKTmatrix->CKTkluMODE)
|
||||
val->iValue = ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz + ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz ;
|
||||
else
|
||||
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
|
||||
if (ckt->CKTmatrix->CKTkluMODE && ckt->CKTmatrix->SMPkluMatrix &&
|
||||
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric) {
|
||||
val->iValue =
|
||||
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz +
|
||||
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz ;
|
||||
} else {
|
||||
val->iValue = 0;
|
||||
}
|
||||
#else
|
||||
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ CKTnewTask(CKTcircuit *ckt, TSKtask **taskPtr, IFuid taskName, TSKtask **defPtr)
|
|||
tsk->TSKepsmin = 1e-28;
|
||||
|
||||
#ifdef KLU
|
||||
tsk->TSKkluMODE = CKTkluON;
|
||||
tsk->TSKkluMODE = CKTkluOFF;
|
||||
tsk->TSKkluMemGrowFactor = 1.2 ;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,9 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val)
|
|||
case OPT_SPARSE:
|
||||
task->TSKkluMODE = (val->iValue == 0);
|
||||
break;
|
||||
|
||||
case OPT_KLU:
|
||||
task->TSKkluMODE = (val->iValue != 0);
|
||||
break;
|
||||
case OPT_KLU_MEMGROW_FACTOR:
|
||||
task->TSKkluMemGrowFactor = (val->rValue == 1.2);
|
||||
break;
|
||||
|
|
@ -348,6 +350,8 @@ static IFparm OPTtbl[] = {
|
|||
#ifdef KLU
|
||||
{ "sparse", OPT_SPARSE, IF_SET|IF_FLAG,
|
||||
"Set SPARSE 1.3 as Direct Linear Solver" },
|
||||
{ "klu", OPT_KLU, IF_SET|IF_FLAG,
|
||||
"Set KLU as Direct Linear Solver" },
|
||||
{ "klu_memgrow_factor", OPT_KLU_MEMGROW_FACTOR, IF_SET|IF_REAL,
|
||||
"KLU Memory Grow Factor (default is 1.2)" }
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -787,14 +787,6 @@ resume:
|
|||
|
||||
converged = NIiter(ckt,ckt->CKTtranMaxIter);
|
||||
|
||||
#ifdef XSPICE
|
||||
if(ckt->evt->counts.num_insts > 0) {
|
||||
g_mif_info.circuit.evt_step = ckt->CKTtime;
|
||||
EVTcall_hybrids(ckt);
|
||||
}
|
||||
/* gtri - end - wbk - Call all hybrids */
|
||||
|
||||
#endif
|
||||
ckt->CKTstat->STATtimePts ++;
|
||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITPRED;
|
||||
if(firsttime) {
|
||||
|
|
@ -830,8 +822,10 @@ resume:
|
|||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* Force backup if temporary breakpoint is < current time */
|
||||
} else if(g_mif_info.breakpoint.current < ckt->CKTtime) {
|
||||
/* Force backup if temporary breakpoint is < current time */
|
||||
|
||||
past_breakpoint:
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
ckt->CKTtime -= ckt->CKTdelta;
|
||||
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
||||
|
|
@ -879,6 +873,27 @@ resume:
|
|||
return(error);
|
||||
}
|
||||
if (newdelta > .9 * ckt->CKTdelta) {
|
||||
#if defined(XSPICE)
|
||||
/* The timestep has succeeded. XSPICE instances with
|
||||
* both analog and event ports ("hybrids") and others
|
||||
* that have called cm_irreversible() receive an EVENT
|
||||
* call here that allows them to capture their final
|
||||
* port values and advance co-simulations. As this is an EVENT
|
||||
* call, they are not expected to do any integrations,
|
||||
* so there is no need for a further convergence test.
|
||||
*/
|
||||
|
||||
if (ckt->evt->counts.num_hybrids > 0) {
|
||||
g_mif_info.circuit.evt_step = ckt->CKTtime;
|
||||
EVTcall_hybrids(ckt);
|
||||
if (g_mif_info.breakpoint.current < ckt->CKTtime) {
|
||||
/* A hybrid requested a breakpoint in the past. */
|
||||
|
||||
goto past_breakpoint;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */
|
||||
newdelta = ckt->CKTdelta;
|
||||
ckt->CKTorder = 2;
|
||||
|
|
@ -893,6 +908,7 @@ resume:
|
|||
}
|
||||
/* time point OK - 630 */
|
||||
ckt->CKTdelta = newdelta;
|
||||
|
||||
#ifdef NDEV
|
||||
if (!ft_norefprint) {
|
||||
/* show a time process indicator, by Gong Ding, gdiso@ustc.edu */
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ void my_key_free(void * key)
|
|||
void mem_delete(void) {
|
||||
#ifdef DB
|
||||
char buf[128];
|
||||
if (!memory_table)
|
||||
return;
|
||||
printf("CPL GC memory allocated %d times, freed %d times\n", mem_in, mem_out);
|
||||
printf("CPL GC size of hash table to be freed: %d entries.\n", nghash_get_size(memory_table));
|
||||
#ifdef DB_FULL
|
||||
|
|
@ -142,6 +144,7 @@ void mem_delete(void) {
|
|||
#endif
|
||||
gc_is_on = 0;
|
||||
nghash_free(memory_table, NULL, my_key_free);
|
||||
memory_table = NULL;
|
||||
#ifdef DB
|
||||
/* printf via sh_printf will need some info from variables that have
|
||||
been deleted already, therefore we use fputs */
|
||||
|
|
|
|||
|
|
@ -1934,7 +1934,8 @@ insert_ND(char* name, NDnamePt* ndn)
|
|||
memsaved(p);
|
||||
p->nd = NULL;
|
||||
p->right = p->left = NULL;
|
||||
strcpy(p->id, name);
|
||||
strncpy(p->id, name, 255);
|
||||
p->id[255] = '\0';
|
||||
return(p);
|
||||
}
|
||||
cmp = strcmp((*ndn)->id, name);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
|||
#include "ngspice/sperror.h"
|
||||
#include "ngspice/suffix.h"
|
||||
#include "ngspice/fteext.h"
|
||||
#include "ngspice/compatmode.h"
|
||||
|
||||
int
|
||||
DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
||||
|
|
@ -195,7 +196,13 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
}
|
||||
|
||||
if((!model->DIOresistGiven) || (model->DIOresist==0)) {
|
||||
model->DIOconductance = 0.0;
|
||||
if (newcompat.ps || newcompat.lt) {
|
||||
model->DIOconductance = 1e4; /* improved convergence */
|
||||
if (ft_ngdebug)
|
||||
fprintf(stderr, "Diode series resistance in model %s set to 100 microOhm\n", model->gen.GENmodName);
|
||||
}
|
||||
else
|
||||
model->DIOconductance = 0.0;
|
||||
} else {
|
||||
model->DIOconductance = 1/model->DIOresist;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1035,7 +1035,8 @@ insert_ND(char *name, NDnamePt *ndn)
|
|||
p = *ndn = TMALLOC(NDname, 1);
|
||||
p->nd = NULL;
|
||||
p->right = p->left = NULL;
|
||||
strcpy(p->id, name);
|
||||
strncpy(p->id, name, 255);
|
||||
p->id[255] = '\0';
|
||||
return(p);
|
||||
}
|
||||
cmp = strcmp((*ndn)->id, name);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
else
|
||||
Check_th = 0;
|
||||
|
||||
/* FIXME:
|
||||
this is not a fix, but a hack:
|
||||
with selfheat, op and op for ac don't work, NaN in self heating evaluation of
|
||||
first iteration in CKTop(). Calling CKTop() from acan uses flag MODEDCOP,
|
||||
changing this to MODETRANOP, as used by CKTop() called from dctran, then op is o.k.
|
||||
*/
|
||||
if (selfheat)
|
||||
if(ckt->CKTmode == 528) /* includes MODEDCOP */
|
||||
ckt->CKTmode = 544; /* includes MODETRANOP */
|
||||
|
||||
/* first, we compute a few useful values - these could be
|
||||
* pre-computed, but for historical reasons are still done
|
||||
* here. They may be moved at the expense of instance size
|
||||
|
|
|
|||
|
|
@ -850,7 +850,6 @@ ElementWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
static int
|
||||
MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
||||
{
|
||||
char *pC1; /* a temporary character pointer */
|
||||
char *pWorkString = NULL; /* a working copy of cmdline */
|
||||
int i; /* a loop counter */
|
||||
int quoteflag = 0; /* for the finite state machine parsing cmdline */
|
||||
|
|
@ -899,13 +898,13 @@ MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
|||
#endif
|
||||
/* If we still have a string left, parse it for all
|
||||
the arguments. */
|
||||
if (strlen(pWorkString))
|
||||
if (pWorkString[0])
|
||||
{
|
||||
/* This could probably be done with strtok as well
|
||||
but strtok is destructive if I wanted to look for " \""
|
||||
and I couldn't tell what delimiter that I had bumped
|
||||
against */
|
||||
for (i = 0; i < (signed)strlen(pWorkString); i++)
|
||||
for (i = 0; pWorkString[i]; i++)
|
||||
switch (pWorkString[i])
|
||||
{
|
||||
case SPACE:
|
||||
|
|
@ -935,7 +934,7 @@ MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
|||
}
|
||||
}
|
||||
/* malloc an argv */
|
||||
tmpargv = (char**) malloc((unsigned)numargs * sizeof(char *));
|
||||
tmpargv = (char**) malloc((unsigned)(numargs + 1) * sizeof(char *));
|
||||
if (NULL == tmpargv)
|
||||
{
|
||||
status = -1;
|
||||
|
|
@ -949,18 +948,15 @@ MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
|||
deli[0] = DELIMITER;
|
||||
deli[1] = '\0'; /* delimiter for strtok */
|
||||
|
||||
pC1 = NULL;
|
||||
/* Now actually strdup all the arguments out of the string
|
||||
and store them in the argv */
|
||||
for (i = 1; i < numargs; i++) {
|
||||
if (NULL == pC1)
|
||||
pC1 = pWorkString;
|
||||
|
||||
if (i == 1)
|
||||
tmpargv[i] = copy(strtok(pC1, deli));
|
||||
tmpargv[i] = copy(strtok(pWorkString, deli));
|
||||
else
|
||||
tmpargv[i] = copy(strtok(NULL, deli));
|
||||
}
|
||||
tmpargv[i] = NULL;
|
||||
|
||||
/* copy the working values over to the arguments */
|
||||
*argc = numargs;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# Process this file with automake
|
||||
|
||||
EXTRA_DIST = README examples icm xspice.c .gitignore
|
||||
EXTRA_DIST = README examples icm xspice.c .gitignore \
|
||||
verilog/vlnggen \
|
||||
verilog/verilator_shim.cpp verilog/verilator_main.cpp
|
||||
|
||||
## This is removed because icm relies upon the existance of all other
|
||||
## libs. It is currently compiled manually, last.
|
||||
|
|
@ -8,7 +10,15 @@ EXTRA_DIST = README examples icm xspice.c .gitignore
|
|||
|
||||
SUBDIRS = mif cm enh evt ipc idn cmpp icm
|
||||
|
||||
initdatadir = $(pkgdatadir)/scripts
|
||||
initdata_DATA = verilog/vlnggen
|
||||
|
||||
initdata1dir = $(pkgdatadir)/scripts/src
|
||||
initdata1_DATA = verilog/verilator_shim.cpp verilog/verilator_main.cpp
|
||||
|
||||
initdata2dir = $(pkgdatadir)/scripts/src/ngspice
|
||||
initdata2_DATA = ../include/ngspice/cosim.h ../include/ngspice/miftypes.h \
|
||||
../include/ngspice/cmtypes.h
|
||||
dist-hook:
|
||||
rm -f "$(distdir)/icm/makedefs"
|
||||
rm -f "$(distdir)/icm/GNUmakefile"
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ INTERFACES
|
|||
cm_get_path()
|
||||
cm_get_circuit()
|
||||
|
||||
cm_irreversible()
|
||||
cm_get_node_name()
|
||||
cm_probe_node()
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/enh.h"
|
||||
#include "ngspice/mif.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/cpextern.h"
|
||||
//#include "util.h"
|
||||
|
||||
|
||||
|
|
@ -730,6 +732,100 @@ CKTcircuit *cm_get_circuit(void)
|
|||
return(g_mif_info.ckt);
|
||||
}
|
||||
|
||||
/* Set the "irreversible" flag on the current instance and shuffle it to the
|
||||
* requested position among any other irreversibles in the hybrid_index array.
|
||||
* Array entries are sorted so that non-zero values of instance->irreversible
|
||||
* are decreasing: an instance with instance->irreversible == 1 is fully
|
||||
* protected.
|
||||
*/
|
||||
|
||||
static void duplicate(MIFinstance *instance)
|
||||
{
|
||||
fprintf(cp_err,
|
||||
"Warning: Duplicate value %d in cm_irreversible() "
|
||||
"for instance %s.\n",
|
||||
instance->irreversible, instance->gen.GENname);
|
||||
}
|
||||
|
||||
void cm_irreversible(unsigned int place)
|
||||
{
|
||||
MIFinstance *instance;
|
||||
Evt_Ckt_Data_t *evt;
|
||||
int num_hybrids;
|
||||
MIFinstance **hybrids;
|
||||
int old_index, i;
|
||||
unsigned int value;
|
||||
|
||||
instance = g_mif_info.instance;
|
||||
if (!g_mif_info.circuit.init) {
|
||||
fprintf(cp_err,
|
||||
"%s: Ignoring call to cm_irreversible(): not in INIT\n",
|
||||
instance->gen.GENname);
|
||||
return;
|
||||
}
|
||||
if (instance->irreversible || place == 0) {
|
||||
if (instance->irreversible != place) {
|
||||
fprintf(cp_err, "%s: Ignoring new value %d in cm_irreversible()\n",
|
||||
instance->gen.GENname, place);
|
||||
}
|
||||
return;
|
||||
}
|
||||
instance->irreversible = place;
|
||||
|
||||
evt = g_mif_info.ckt->evt;
|
||||
num_hybrids = evt->counts.num_hybrids;
|
||||
hybrids = evt->info.hybrids;
|
||||
|
||||
/* Already a hybrid? */
|
||||
|
||||
for (old_index = 0; old_index < num_hybrids; ++old_index) {
|
||||
if (hybrids[old_index] == instance)
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_index < num_hybrids) {
|
||||
/* Existing hybrid, move down, shuffling other entries up. */
|
||||
|
||||
for (i = old_index + 1; i < num_hybrids; ++i) {
|
||||
value = hybrids[i]->irreversible;
|
||||
if (value == 0 || value > place) {
|
||||
hybrids[i - 1] = hybrids[i];
|
||||
} else if (value == place) {
|
||||
duplicate(instance);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
hybrids[i - 1] = instance;
|
||||
} else {
|
||||
/* Instance is not hybrid, add an entry. */
|
||||
|
||||
num_hybrids++;
|
||||
hybrids = TREALLOC(MIFinstance *, hybrids, num_hybrids);
|
||||
evt->counts.num_hybrids = num_hybrids;
|
||||
evt->info.hybrids = hybrids;
|
||||
if (hybrids == NULL) {
|
||||
fprintf(cp_err, "Allocation failed in cm_irreversible()\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Shuffle entries down. */
|
||||
|
||||
for (i = num_hybrids - 2; i >= 0; --i) {
|
||||
value = hybrids[i]->irreversible;
|
||||
if (value != 0 && value < place) {
|
||||
hybrids[i + 1] = hybrids[i];
|
||||
} else if (value == place) {
|
||||
duplicate(instance);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
hybrids[i + 1] = instance;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the name of a circuit node connected to a port. */
|
||||
|
||||
const char *cm_get_node_name(const char *port_name, unsigned int index)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
#include "ngspice/cm.h"
|
||||
#include "ngspice/dllitf.h"
|
||||
|
||||
extern bool cp_getvar(char *, enum cp_types, void *, size_t);
|
||||
|
||||
/*how annoying!, needed for structure below*/
|
||||
static void *tcalloc(size_t a, size_t b) {
|
||||
return tmalloc(a*b); /* FIXME, tcalloc must zero !?!? */
|
||||
|
|
@ -60,6 +58,7 @@ struct coreInfo_t coreInfo =
|
|||
cm_message_send,
|
||||
cm_netlist_get_c,
|
||||
cm_netlist_get_l,
|
||||
cm_irreversible,
|
||||
cm_get_node_name,
|
||||
cm_probe_node,
|
||||
cm_schedule_output,
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ NON-STANDARD FEATURES
|
|||
#include <math.h>
|
||||
#include "ngspice/cm.h"
|
||||
|
||||
extern void controlled_exit(const int);
|
||||
|
||||
/* Corner Smoothing Function ************************************
|
||||
* *
|
||||
* The following function smooths the transition between two *
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@ MODIFICATIONS
|
|||
SUMMARY
|
||||
|
||||
This file contains function EVTcall_hybrids which calls all models
|
||||
which have both analog and event-driven ports. It is called following
|
||||
which have both analog and event-driven ports or have declared
|
||||
themselves to be irreversible (no back-out). It is called following
|
||||
successful evaluation of an analog iteration attempt to allow
|
||||
events to be scheduled by the hybrid models. The 'CALL_TYPE' is set
|
||||
to 'EVENT_DRIVEN' when the model is called from this function.
|
||||
to 'EVENT_DRIVEN' or 'STEP_PENDING' when the model is called
|
||||
from this function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
|
|
@ -60,18 +62,18 @@ void EVTcall_hybrids(
|
|||
CKTcircuit *ckt) /* the main circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_hybrids;
|
||||
|
||||
int *hybrid_index;
|
||||
int i;
|
||||
int num_hybrids;
|
||||
MIFinstance **hybrids;
|
||||
|
||||
|
||||
/* Get needed data for fast access */
|
||||
|
||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||
hybrid_index = ckt->evt->info.hybrid_index;
|
||||
hybrids = ckt->evt->info.hybrids;
|
||||
|
||||
/* Call EVTload for all hybrids */
|
||||
for(i = 0; i < num_hybrids; i++)
|
||||
EVTload(ckt, hybrid_index[i]);
|
||||
|
||||
for(i = 0; i < num_hybrids; i++)
|
||||
EVTload_with_event(ckt, hybrids[i], MIF_STEP_PENDING);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,5 +330,5 @@ Evt_Info_destroy(Evt_Info_t *info)
|
|||
}
|
||||
tfree(info->output_table);
|
||||
|
||||
tfree(info->hybrid_index);
|
||||
tfree(info->hybrids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ static int EVTinit_info(
|
|||
Evt_Port_Info_t **port_table = NULL;
|
||||
Evt_Output_Info_t **output_table = NULL;
|
||||
|
||||
int *hybrid_index = NULL;
|
||||
MIFinstance **hybrids = NULL;
|
||||
|
||||
int num_hybrids;
|
||||
|
||||
|
|
@ -253,15 +253,14 @@ static int EVTinit_info(
|
|||
ckt->evt->info.output_table = output_table;
|
||||
|
||||
|
||||
/* Allocate and create table of indexes into inst_table for hybrids */
|
||||
/* Allocate and create table of hybrids */
|
||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||
CKALLOC(hybrid_index, num_hybrids, int)
|
||||
CKALLOC(hybrids, num_hybrids, MIFinstance *)
|
||||
for(i = 0, j = 0; i < num_insts; i++) {
|
||||
if(inst_table[i]->inst_ptr->analog)
|
||||
hybrid_index[j++] = i;
|
||||
hybrids[j++] = inst_table[i]->inst_ptr;
|
||||
}
|
||||
ckt->evt->info.hybrid_index = hybrid_index;
|
||||
|
||||
ckt->evt->info.hybrids = hybrids;
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ int EVTiter(
|
|||
for(i = 0; i < num_to_call; i++) {
|
||||
inst_index = inst_queue->to_call_index[i];
|
||||
inst_queue->to_call[inst_index] = MIF_FALSE;
|
||||
EVTload(ckt, inst_index);
|
||||
EVTload(ckt, ckt->evt->info.inst_table[inst_index]->inst_ptr);
|
||||
}
|
||||
inst_queue->num_to_call = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,18 @@ ignored.
|
|||
*/
|
||||
|
||||
int EVTload(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index) /* The instance to call code model for */
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *inst) /* The instance to call */
|
||||
{
|
||||
return EVTload_with_event(ckt, inst, MIF_EVENT_DRIVEN);
|
||||
}
|
||||
|
||||
/* "Internal" version, also used by EVTcall_hybrids(). */
|
||||
|
||||
int EVTload_with_event(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *inst, /* The instance to call */
|
||||
Mif_Call_Type_t type) /* Type of call (EVENT or STEP_PENDING). */
|
||||
{
|
||||
|
||||
int i;
|
||||
|
|
@ -96,18 +106,16 @@ int EVTload(
|
|||
Mif_Conn_Data_t *conn;
|
||||
Mif_Port_Data_t *port;
|
||||
Evt_Node_Data_t *node_data;
|
||||
MIFinstance *inst;
|
||||
|
||||
Mif_Private_t cm_data;
|
||||
|
||||
void *value_ptr;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prepare the code model inputs */
|
||||
/* ***************************** */
|
||||
|
||||
/* Get pointer to instance data structure and other data */
|
||||
/* needed for fast access */
|
||||
inst = ckt->evt->info.inst_table[inst_index]->inst_ptr;
|
||||
/* Get pointer to data structure needed for fast access */
|
||||
|
||||
node_data = ckt->evt->data.node;
|
||||
|
||||
/* Setup circuit data in struct to be passed to code model function */
|
||||
|
|
@ -125,7 +133,14 @@ int EVTload(
|
|||
else
|
||||
cm_data.circuit.time = 0.0;
|
||||
|
||||
cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
/* Instances that have declared themselves as irreversible
|
||||
* are expected to distinguish STEP_PENDING from ordinary events.
|
||||
*/
|
||||
|
||||
if (type == MIF_STEP_PENDING && inst->irreversible)
|
||||
cm_data.circuit.call_type = MIF_STEP_PENDING;
|
||||
else
|
||||
cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
cm_data.circuit.temperature = ckt->CKTtemp - 273.15;
|
||||
|
||||
/* Setup data needed by cm_... functions */
|
||||
|
|
@ -142,11 +157,12 @@ int EVTload(
|
|||
|
||||
|
||||
/* If after initialization and in transient analysis mode */
|
||||
/* create a new state for the instance */
|
||||
|
||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized)
|
||||
EVTcreate_state(ckt, inst_index);
|
||||
/* create a new state for the instance, */
|
||||
/* except analog-only irreversibles. */
|
||||
|
||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized &&
|
||||
inst->inst_index >= 0)
|
||||
EVTcreate_state(ckt, inst->inst_index);
|
||||
|
||||
/* Loop through all connections on the instance and setup */
|
||||
/* load, total_load, and msg on all ports, and changed flag */
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ cm-descr := \
|
|||
|
||||
# When recursively making clean, cm-objs and cm-gens do not contain
|
||||
# the files generated for individual code models, as cmpp has already gone
|
||||
# and modlist and udnlist are empty. Those files are explicitly removed.
|
||||
# and modlist and udnlist are empty. The files are explicitly removed.
|
||||
|
||||
cm-clean :
|
||||
-rm -f $(cm)/$(cm).cm
|
||||
-rm -f $(cm-descr) $(cm-objs) $(cm-gens)
|
||||
-rm -f $(cm)/*/*.o $(cm)/*/*.c $(cm)/*/.deps/*
|
||||
-rm -f $(cm)/*/ifspec.c $(cm)/*/cfunc.c $(cm)/*/*.o $(cm)/*/.deps/*
|
||||
-rm -f $(cm-deps)
|
||||
|
||||
cm-distclean :
|
||||
|
|
@ -135,10 +135,10 @@ $(cm-dirs) $(cm-dep-dirs) :
|
|||
%/cmextrn.h %/cminfo.h %/udnextrn.h %/udninfo.h %/objects.inc : $(srcdir)/%/modpath.lst $(srcdir)/%/udnpath.lst
|
||||
CMPP_IDIR=$(srcdir)/$(@D) CMPP_ODIR=$(@D) $(CMPP) -lst
|
||||
|
||||
%/ifspec.c : $(srcdir)/%/ifspec.ifs
|
||||
%/ifspec.c : $(srcdir)/%/ifspec.ifs $(cmpp)
|
||||
CMPP_IDIR=$(srcdir)/$(@D) CMPP_ODIR=$(@D) $(CMPP) -ifs
|
||||
|
||||
%/cfunc.c : $(srcdir)/%/cfunc.mod
|
||||
%/cfunc.c : $(srcdir)/%/cfunc.mod $(cmpp)
|
||||
CMPP_IDIR=$(srcdir)/$(@D) CMPP_ODIR=$(@D) $(CMPP) -mod
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,578 @@
|
|||
/* Code model d_cosim.
|
||||
*
|
||||
* XSPICE code model for running a co-simulation with no support
|
||||
* for abandoning the current timestep.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined (__MINGW32__) || defined (__CYGWIN__) || defined (_MSC_VER)
|
||||
/* MS WINDOWS. */
|
||||
#undef BOOLEAN
|
||||
#include <windows.h>
|
||||
|
||||
#define dlopen(name, type) LoadLibrary(name)
|
||||
#define dlsym(handle, name) (void *)GetProcAddress(handle, name)
|
||||
#define dlclose(handle) FreeLibrary(handle)
|
||||
|
||||
char *dlerror(void) // Lifted from dev.c.
|
||||
{
|
||||
static const char errstr_fmt[] =
|
||||
"Unable to find message in dlerr(). System code = %lu";
|
||||
static char errstr[256];
|
||||
LPVOID lpMsgBuf;
|
||||
|
||||
DWORD rc = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (rc == 0) { /* FormatMessage failed */
|
||||
(void) sprintf(errstr, errstr_fmt, (unsigned long) GetLastError());
|
||||
} else {
|
||||
snprintf(errstr, sizeof errstr, lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
return errstr;
|
||||
} /* end of function dlerror */
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "ngspice/cosim.h"
|
||||
|
||||
/* The argument passed to code model functions. */
|
||||
|
||||
#define XSPICE_ARG mif_private
|
||||
|
||||
#define DBG(...)
|
||||
//#define DBG(...) cm_message_printf(__VA_ARGS__)
|
||||
|
||||
/* Structure used to hold queued inputs. */
|
||||
|
||||
struct pend_in {
|
||||
double when; // Due time.
|
||||
unsigned int which; // Index of input.
|
||||
Digital_t what; // The value.
|
||||
};
|
||||
|
||||
/* Structure to maintain context, pointed to by STATIC VAR cosim_instance. */
|
||||
|
||||
struct instance {
|
||||
struct co_info info; // Co-simulation interface - MUST BE FIRST.
|
||||
int q_index; // Queue index (last active entry).
|
||||
unsigned int q_length; // Size of input queue.
|
||||
struct pend_in *q; // The input queue.
|
||||
unsigned int in_ports; // Number of XSPICE inputs.
|
||||
unsigned int out_ports; // Number of XSPICE outputs.
|
||||
unsigned int inout_ports; // Number of XSPICE inout ports.
|
||||
unsigned int op_pending; // Output is pending.
|
||||
Digital_t *out_vals; // The new output values.
|
||||
double extra; // Margin to extend timestep.
|
||||
void *so_handle; // dlopen() handle to the simulation binary.
|
||||
};
|
||||
|
||||
/* Called at end of simulation run to free memory. */
|
||||
|
||||
static void callback(ARGS, Mif_Callback_Reason_t reason)
|
||||
{
|
||||
struct instance *ip;
|
||||
|
||||
ip = (struct instance *)STATIC_VAR(cosim_instance);
|
||||
if (reason == MIF_CB_DESTROY) {
|
||||
if (!ip)
|
||||
return;
|
||||
if (ip->info.cleanup)
|
||||
(*ip->info.cleanup)(&ip->info);
|
||||
if (ip->so_handle)
|
||||
dlclose(ip->so_handle);
|
||||
if (ip->q)
|
||||
free(ip->q);
|
||||
if (ip->out_vals)
|
||||
free(ip->out_vals);
|
||||
free(ip);
|
||||
STATIC_VAR(cosim_instance) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function called when a co-simulator output changes.
|
||||
* Out-of-range values for bit_num must be ignored.
|
||||
*/
|
||||
|
||||
void accept_output(struct co_info *pinfo, unsigned int bit_num, Digital_t *val)
|
||||
{
|
||||
struct instance *ip = (struct instance *)pinfo; // First member.
|
||||
Digital_t *out_vals; // XSPICE rotating memory.
|
||||
|
||||
if (bit_num >= ip->out_ports + ip->inout_ports)
|
||||
return;
|
||||
out_vals = (Digital_t *)cm_event_get_ptr(1, 0);
|
||||
DBG("Change %s %d/%d->%d/%d vtime %g",
|
||||
cm_get_node_name("d_out", bit_num),
|
||||
out_vals[bit_num].state, out_vals[bit_num].strength,
|
||||
val->state, val->strength,
|
||||
ip->info.vtime);
|
||||
if (ip->op_pending == 0) {
|
||||
/* Prepare pending output. */
|
||||
|
||||
memcpy(ip->out_vals, out_vals, ip->out_ports * sizeof *ip->out_vals);
|
||||
ip->op_pending = 1;
|
||||
}
|
||||
ip->out_vals[bit_num] = *val;
|
||||
}
|
||||
|
||||
/* Push pending outputs, usually sent back from the future.
|
||||
* It is safe to use OUTPUT() here, although it mays seem that this
|
||||
* function may be called twice in a single call to cm_d_cosim().
|
||||
* There will never be any input changes when cm_d_cosim() is called
|
||||
* with pending output, as all input for the shortened time-step has
|
||||
* already been processed.
|
||||
*/
|
||||
|
||||
static void output(struct instance *ip, ARGS)
|
||||
{
|
||||
double delay;
|
||||
Digital_t *out_vals; // XSPICE rotating memory
|
||||
int i, j;
|
||||
|
||||
delay = PARAM(delay) - (TIME - ip->info.vtime);
|
||||
if (delay <= 0) {
|
||||
cm_message_printf("WARNING: output scheduled with impossible "
|
||||
"delay (%g) at %g.", delay, TIME);
|
||||
delay = 1e-12;
|
||||
}
|
||||
out_vals = (Digital_t *)cm_event_get_ptr(1, 0);
|
||||
|
||||
/* Output to d_out. */
|
||||
|
||||
for (i = 0; i < ip->out_ports; ++i) {
|
||||
if (ip->out_vals[i].state != out_vals[i].state ||
|
||||
ip->out_vals[i].strength != out_vals[i].strength) {
|
||||
DBG("%g: OUT %s %d/%d->%d/%d vtime %g with delay %g",
|
||||
TIME, cm_get_node_name("d_out", i),
|
||||
out_vals[i].state, out_vals[i].strength,
|
||||
ip->out_vals[i].state, ip->out_vals[i].strength,
|
||||
ip->info.vtime, delay);
|
||||
*(Digital_t *)OUTPUT(d_out[i]) = out_vals[i] = ip->out_vals[i];
|
||||
OUTPUT_DELAY(d_out[i]) = delay;
|
||||
OUTPUT_CHANGED(d_out[i]) = TRUE;
|
||||
} else {
|
||||
OUTPUT_CHANGED(d_out[i]) = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output to d_inout. */
|
||||
|
||||
for (i = 0, j = ip->out_ports; i < ip->inout_ports; ++i, ++j) {
|
||||
if (ip->out_vals[j].state != out_vals[j].state ||
|
||||
ip->out_vals[j].strength != out_vals[j].strength) {
|
||||
DBG("%g: inOUT %s %d/%d->%d/%d vtime %g with delay %g",
|
||||
TIME, cm_get_node_name("d_inout", i),
|
||||
out_vals[j].state, out_vals[j].strength,
|
||||
ip->out_vals[j].state, ip->out_vals[j].strength,
|
||||
ip->info.vtime, delay);
|
||||
*(Digital_t *)OUTPUT(d_inout[i]) = out_vals[j] = ip->out_vals[j];
|
||||
OUTPUT_DELAY(d_inout[i]) = delay;
|
||||
OUTPUT_CHANGED(d_inout[i]) = TRUE;
|
||||
} else {
|
||||
OUTPUT_CHANGED(d_inout[i]) = FALSE;
|
||||
}
|
||||
}
|
||||
ip->op_pending = 0;
|
||||
}
|
||||
|
||||
/* Run the co-simulation. Return 1 if the timestep was truncated. */
|
||||
|
||||
static int advance(struct instance *ip, ARGS)
|
||||
{
|
||||
/* The co-simulator should advance to the time in ip->info.vtime,
|
||||
* but should pause when output is generated and update vtime.
|
||||
*/
|
||||
|
||||
(*ip->info.step)(&ip->info);
|
||||
|
||||
if (ip->op_pending) {
|
||||
|
||||
/* The co-simulator produced some output. */
|
||||
|
||||
if (TIME - ip->info.vtime <= PARAM(delay)) {
|
||||
#if 1
|
||||
DBG("Direct output with SPICE %.16g CS %.16g",
|
||||
TIME, ip->info.vtime);
|
||||
output(ip, XSPICE_ARG); // Normal output, unlikely.
|
||||
#else
|
||||
cm_event_queue((TIME + ip->info.vtime + PARAM(delay)) / 2.0);
|
||||
#endif
|
||||
} else {
|
||||
|
||||
/* Something changed that may alter the future of the
|
||||
* SPICE simulation. Truncate the current timestep so that
|
||||
* SPICE will see the pending output, which currently occurred
|
||||
* in the past.
|
||||
*/
|
||||
|
||||
DBG("Truncating timestep to %.16g", ip->info.vtime + ip->extra);
|
||||
cm_analog_set_temp_bkpt(ip->info.vtime + ip->extra);
|
||||
|
||||
/* Any remaining input events are in an alternate future. */
|
||||
|
||||
ip->q_index = -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called from the main function to run the co-simulation. */
|
||||
|
||||
static void run(struct instance *ip, ARGS)
|
||||
{
|
||||
struct pend_in *rp;
|
||||
double sim_started;
|
||||
int i;
|
||||
|
||||
if (ip->q_index < 0) {
|
||||
/* No queued input, advance to current TIME. */
|
||||
|
||||
DBG("Advancing vtime without input %.16g -> %.16g",
|
||||
ip->info.vtime , TIME);
|
||||
ip->info.vtime = TIME;
|
||||
advance(ip, XSPICE_ARG);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scan the queue. */
|
||||
|
||||
DBG("%.16g: Running Q with %d entries", TIME, ip->q_index + 1);
|
||||
sim_started = ip->info.vtime;
|
||||
|
||||
for (i = 0; i <= ip->q_index; ++i) {
|
||||
rp = ip->q + i;
|
||||
if (rp->when <= sim_started) {
|
||||
/* Not expected. */
|
||||
|
||||
cm_message_printf("Warning simulated event is in the past:\n"
|
||||
"XSPICE %.16g\n"
|
||||
"Event %.16g\n"
|
||||
"Cosim %.16g",
|
||||
TIME, rp->when, ip->info.vtime);
|
||||
cm_message_printf("i=%d index=%d", i, ip->q_index);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Step the simulation forward to the input event time. */
|
||||
|
||||
ip->info.vtime = rp->when;
|
||||
if (ip->info.method == Normal && advance(ip, XSPICE_ARG)) {
|
||||
ip->q_index = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pass input change to simulation. */
|
||||
|
||||
(*ip->info.in_fn)(&ip->info, rp->which, &rp->what);
|
||||
while (i < ip->q_index && ip->q[i + 1].when == rp->when) {
|
||||
/* Another change at the same time. */
|
||||
|
||||
++i;
|
||||
rp = ip->q + i;
|
||||
(*ip->info.in_fn)(&ip->info, rp->which, &rp->what);
|
||||
}
|
||||
|
||||
/* Simulator requested to run after input change. */
|
||||
|
||||
if (ip->info.method == After_input && advance(ip, XSPICE_ARG)) {
|
||||
ip->q_index = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* All input was processed. Advance to end of the timestep. */
|
||||
|
||||
ip->q_index = -1;
|
||||
if (ip->info.method == Normal && TIME > ip->info.vtime) {
|
||||
ip->info.vtime = TIME;
|
||||
advance(ip, XSPICE_ARG);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether an input value has changed.
|
||||
* To reduce the number of arguments, a struture pointer is passed.
|
||||
*/
|
||||
|
||||
static bool check_input(struct instance *ip, Digital_t *ovp,
|
||||
struct pend_in *rp)
|
||||
{
|
||||
if (ovp->state != rp->what.state ||
|
||||
ovp->strength != rp->what.strength) {
|
||||
if (++ip->q_index < ip->q_length) {
|
||||
/* Record this event. */
|
||||
|
||||
ip->q[ip->q_index] = *rp;
|
||||
} else {
|
||||
/* Queue is full. Handle that by forcing a shorter timestep. */
|
||||
|
||||
--ip->q_index;
|
||||
while (ip->q_index >= 0 && ip->q[ip->q_index].when >= rp->when)
|
||||
--ip->q_index;
|
||||
if (ip->q_index >= 0) {
|
||||
cm_analog_set_temp_bkpt(
|
||||
(rp->when + ip->q[ip->q_index].when) / 2);
|
||||
} else {
|
||||
/* This should never happen. */
|
||||
|
||||
cm_message_printf("Error: Event queue overflow at %e.",
|
||||
rp->when);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The code model's main function. */
|
||||
|
||||
void ucm_d_cosim(ARGS)
|
||||
{
|
||||
struct instance *ip;
|
||||
Digital_t *in_vals; // XSPICE rotating memory
|
||||
int i, index;
|
||||
|
||||
if (INIT) {
|
||||
int ins, outs, inouts;
|
||||
unsigned int alloc_size;
|
||||
void *handle;
|
||||
void (*ifp)(struct co_info *);
|
||||
char *fn;
|
||||
|
||||
/* Initialise outputs. Done early in case of failure. */
|
||||
|
||||
outs = PORT_NULL(d_out) ? 0 : PORT_SIZE(d_out);
|
||||
for (i = 0; i < outs; ++i) {
|
||||
OUTPUT_STATE(d_out[i]) = ZERO;
|
||||
OUTPUT_STRENGTH(d_out[i]) = STRONG;
|
||||
OUTPUT_DELAY(d_out[i]) = PARAM(delay);
|
||||
}
|
||||
|
||||
inouts = PORT_NULL(d_inout) ? 0 : PORT_SIZE(d_inout);
|
||||
for (i = 0; i < inouts; ++i) {
|
||||
OUTPUT_STATE(d_inout[i]) = ZERO;
|
||||
OUTPUT_STRENGTH(d_inout[i]) = STRONG;
|
||||
OUTPUT_DELAY(d_inout[i]) = PARAM(delay);
|
||||
}
|
||||
|
||||
/* Load the shared library containing the co-simulator. */
|
||||
|
||||
fn = PARAM(simulation);
|
||||
handle = dlopen(fn, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
cm_message_send("Failed to load simulation binary. "
|
||||
"Try setting LD_LIBRARY_PATH.");
|
||||
cm_message_send(dlerror());
|
||||
return;
|
||||
}
|
||||
ifp = dlsym(handle, "Cosim_setup");
|
||||
if (*ifp == NULL) {
|
||||
cm_message_printf("ERROR: no entry function in %s", fn);
|
||||
cm_message_send(dlerror());
|
||||
dlclose(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the instance data and initialise it. */
|
||||
|
||||
ip = (struct instance *)calloc(1, sizeof *ip);
|
||||
if (!ip)
|
||||
goto no_ip;
|
||||
ip->so_handle = handle;
|
||||
ip->info.vtime = 0.0;
|
||||
ip->info.out_fn = accept_output;
|
||||
CALLBACK = callback;
|
||||
|
||||
/* Store the simulation interface information. */
|
||||
|
||||
(*ifp)(&ip->info);
|
||||
|
||||
/* Check lengths. */
|
||||
|
||||
ins = PORT_NULL(d_in) ? 0 : PORT_SIZE(d_in);
|
||||
if (ins != ip->info.in_count) {
|
||||
cm_message_printf("Warning: mismatched XSPICE/co-simulator "
|
||||
"input counts: %d/%d.",
|
||||
ins, ip->info.in_count);
|
||||
}
|
||||
if (outs != ip->info.out_count) {
|
||||
cm_message_printf("Warning: mismatched XSPICE/co-simulator "
|
||||
"output counts: %d/%d.",
|
||||
outs, ip->info.out_count);
|
||||
}
|
||||
|
||||
if (inouts != ip->info.inout_count) {
|
||||
cm_message_printf("Warning: mismatched XSPICE/co-simulator "
|
||||
"inout counts: %d/%d.",
|
||||
inouts, ip->info.inout_count);
|
||||
}
|
||||
|
||||
/* Create input queue and output buffer. */
|
||||
|
||||
ip->q_index = -1;
|
||||
ip->q_length = PARAM(queue_size);
|
||||
ip->in_ports = ins;
|
||||
ip->out_ports = outs;
|
||||
ip->inout_ports = inouts;
|
||||
if (ins + inouts > ip->q_length) {
|
||||
cm_message_send("WARNING: Input queue size should be greater than "
|
||||
"number of input ports. Size increased.");
|
||||
ip->q_length = ins + inouts + 16;
|
||||
}
|
||||
alloc_size = ip->q_length * sizeof (struct pend_in);
|
||||
ip->q = (struct pend_in *)malloc(alloc_size);
|
||||
if (!ip->q)
|
||||
goto no_q;
|
||||
ip->op_pending = 0;
|
||||
ip->out_vals = (Digital_t *)calloc(outs + inouts, sizeof (Digital_t));
|
||||
if (!ip->out_vals)
|
||||
goto no_out_vals;
|
||||
ip->extra = PARAM(delay) / 3; // FIXME?
|
||||
STATIC_VAR(cosim_instance) = ip;
|
||||
|
||||
/* Allocate XSPICE rotating storage to track changes. */
|
||||
|
||||
cm_event_alloc(0, (ins + inouts) * sizeof (Digital_t));
|
||||
cm_event_alloc(1, (outs + inouts) * sizeof (Digital_t));
|
||||
|
||||
/* Declare irreversible. */
|
||||
|
||||
if (PARAM(irreversible) > 0)
|
||||
cm_irreversible(PARAM(irreversible));
|
||||
return;
|
||||
|
||||
/* Handle malloc failures. */
|
||||
no_out_vals:
|
||||
free(ip->q);
|
||||
no_q:
|
||||
free(ip);
|
||||
no_ip:
|
||||
cm_message_send("No memory!");
|
||||
return;
|
||||
}
|
||||
|
||||
ip = STATIC_VAR(cosim_instance);
|
||||
if (!ip) {
|
||||
int ports;
|
||||
|
||||
/* Error state. Do nothing at all. */
|
||||
|
||||
ports = PORT_NULL(d_out) ? 0 : PORT_SIZE(d_out);
|
||||
for (i = 0; i < ports; ++i)
|
||||
OUTPUT_CHANGED(d_out[i]) = FALSE;
|
||||
ports = PORT_NULL(d_inout) ? 0 : PORT_SIZE(d_inout);
|
||||
for (i = 0; i < ports; ++i)
|
||||
OUTPUT_CHANGED(d_inout[i]) = FALSE;
|
||||
return;
|
||||
}
|
||||
in_vals = (Digital_t *)cm_event_get_ptr(0, 0);
|
||||
|
||||
if (TIME == 0.0) {
|
||||
/* Starting, so inputs may be settling. */
|
||||
|
||||
for (i = 0; i < ip->in_ports; ++i) {
|
||||
Digital_t ival;
|
||||
|
||||
ival = *(Digital_t *)INPUT(d_in[i]);
|
||||
(*ip->info.in_fn)(&ip->info, i, &ival);
|
||||
in_vals[i] = ival;
|
||||
}
|
||||
|
||||
for (i = 0; i < ip->out_ports; ++i)
|
||||
OUTPUT_CHANGED(d_out[i]) = FALSE;
|
||||
|
||||
for (i = 0; i < ip->inout_ports; ++i) {
|
||||
Digital_t ival;
|
||||
|
||||
ival = *(Digital_t *)INPUT(d_inout[i]);
|
||||
(*ip->info.in_fn)(&ip->info, i + ip->in_ports, &ival);
|
||||
in_vals[i + ip->in_ports] = ival;
|
||||
OUTPUT_CHANGED(d_inout[i]) = FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (CALL_TYPE == ANALOG) // Belt and braces
|
||||
return;
|
||||
|
||||
/* Check for pending output. */
|
||||
|
||||
if (ip->op_pending) {
|
||||
output(ip, XSPICE_ARG);
|
||||
} else {
|
||||
for (i = 0; i < ip->out_ports; ++i)
|
||||
OUTPUT_CHANGED(d_out[i]) = FALSE;
|
||||
for (i = 0; i < ip->inout_ports; ++i)
|
||||
OUTPUT_CHANGED(d_inout[i]) = FALSE;
|
||||
}
|
||||
|
||||
/* Check TIME as it may have gone backwards after a failed time-step. */
|
||||
|
||||
index = ip->q_index;
|
||||
while (index >= 0 && TIME < ip->q[index].when)
|
||||
--index;
|
||||
ip->q_index = index;
|
||||
|
||||
if (CALL_TYPE == EVENT) {
|
||||
struct pend_in input;
|
||||
unsigned int limit, max;
|
||||
|
||||
/* New input is expected here. */
|
||||
|
||||
input.when = TIME;
|
||||
|
||||
limit = ip->info.in_count + ip->info.inout_count;
|
||||
max = limit < ip->in_ports ? limit : ip->in_ports;
|
||||
limit -= max;
|
||||
|
||||
for (input.which = 0; input.which < max; ++input.which) {
|
||||
input.what = *(Digital_t *)INPUT(d_in[input.which]);
|
||||
if (check_input(ip, in_vals + input.which, &input)) {
|
||||
DBG("%.16g: IN %s %d/%d->%d/%d",
|
||||
TIME, cm_get_node_name("d_in", input.which),
|
||||
in_vals[input.which].state, in_vals[input.which].strength,
|
||||
input.what.state, input.what.strength);
|
||||
in_vals[input.which] = input.what;
|
||||
}
|
||||
}
|
||||
|
||||
if (limit > ip->inout_ports)
|
||||
limit = ip->inout_ports;
|
||||
for (i = 0; i < limit; ++i, ++input.which) {
|
||||
input.what = *(Digital_t *)INPUT(d_inout[i]);
|
||||
if (check_input(ip, in_vals + input.which, &input)) {
|
||||
DBG("%.16g: INout %s %d/%d->%d/%d",
|
||||
TIME, cm_get_node_name("d_inout", i),
|
||||
in_vals[input.which].state, in_vals[input.which].strength,
|
||||
input.what.state, input.what.strength);
|
||||
in_vals[ip->in_ports + i] = input.what;
|
||||
}
|
||||
}
|
||||
} else if (CALL_TYPE == STEP_PENDING) {
|
||||
/* The current timestep succeeded. Run the co-simulator code
|
||||
* forward, replaying any saved input events.
|
||||
*/
|
||||
|
||||
if (TIME <= ip->info.vtime)
|
||||
cm_message_printf("XSPICE time is behind vtime:\n"
|
||||
"XSPICE %.16g\n"
|
||||
"Cosim %.16g",
|
||||
TIME, ip->info.vtime);
|
||||
run(ip, XSPICE_ARG);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/* Copyright 2023 Giles Atkinson
|
||||
SUMMARY
|
||||
|
||||
This file contains the interface specification file for the
|
||||
d_cosim code model for general digital co-simulation.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
NAME_TABLE:
|
||||
|
||||
Spice_Model_Name: d_cosim
|
||||
C_Function_Name: ucm_d_cosim
|
||||
Description: "Bridge to an irreversible digital model"
|
||||
|
||||
PORT_TABLE:
|
||||
|
||||
Port_Name: d_in
|
||||
Description: "digital input"
|
||||
Direction: in
|
||||
Default_Type: d
|
||||
Allowed_Types: [d]
|
||||
Vector: yes
|
||||
Vector_Bounds: [0 -]
|
||||
Null_Allowed: yes
|
||||
|
||||
PORT_TABLE:
|
||||
|
||||
Port_Name: d_out
|
||||
Description: "digital output"
|
||||
Direction: out
|
||||
Default_Type: d
|
||||
Allowed_Types: [d]
|
||||
Vector: yes
|
||||
Vector_Bounds: [0 -]
|
||||
Null_Allowed: yes
|
||||
|
||||
PORT_TABLE:
|
||||
|
||||
Port_Name: d_inout
|
||||
Description: "digital bidirectional port"
|
||||
Direction: inout
|
||||
Default_Type: d
|
||||
Allowed_Types: [d]
|
||||
Vector: yes
|
||||
Vector_Bounds: [0 -]
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: delay
|
||||
Description: "output delay time"
|
||||
Data_Type: real
|
||||
Default_Value: 1.0e-9
|
||||
Limits: [1e-12 -]
|
||||
Vector: no
|
||||
Vector_bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: simulation
|
||||
Description: "A shared library containing a digital model"
|
||||
Data_Type: string
|
||||
Default_Value: -
|
||||
Limits: -
|
||||
Vector: no
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: no
|
||||
|
||||
/* Instances maintain an internal input event queue that should be at least
|
||||
* as large as the number of inputs. Performance with clocked logic may
|
||||
* be improved by making it larger than (2 * F) / MTS, where F is
|
||||
* the clock frequency and MTS is the maximum timestep for .tran.
|
||||
*/
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: queue_size
|
||||
Description: "input queue size"
|
||||
Data_Type: int
|
||||
Default_Value: 128
|
||||
Limits: [1 -]
|
||||
Vector: no
|
||||
Vector_bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: irreversible
|
||||
Description: "Parameter passed to library function cm_irreversible()"
|
||||
Data_Type: int
|
||||
Default_Value: 1
|
||||
Limits: -
|
||||
Vector: no
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
STATIC_VAR_TABLE:
|
||||
|
||||
Static_Var_Name: cosim_instance
|
||||
Data_Type: pointer
|
||||
Description: "Per-instance structure"
|
||||
|
|
@ -29,3 +29,4 @@ d_tff
|
|||
d_tristate
|
||||
d_xnor
|
||||
d_xor
|
||||
d_cosim
|
||||
|
|
|
|||
|
|
@ -340,6 +340,11 @@ double cm_netlist_get_l(void) {
|
|||
return (coreitf->dllitf_cm_netlist_get_l)();
|
||||
}
|
||||
|
||||
void cm_irreversible(unsigned int place)
|
||||
{
|
||||
(coreitf->dllitf_cm_irreversible)(place);
|
||||
}
|
||||
|
||||
const char *cm_get_node_name(const char *port, unsigned int index) {
|
||||
return coreitf->dllitf_cm_get_node_name(port, index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
CL /O2 /LD /EHsc /Fe..\adc.DLL /I. /IC:\mingw64\share\verilator\include\vltstd /IC:\mingw64\share\verilator\include Vlng__ALL.cpp verilator_shim.cpp C:\mingw64\share\verilator\include\verilated.cpp C:\mingw64\share\verilator\include\verilated_threads.cpp /link /DLL /EXPORT:Cosim_setup
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
This directory contains Ngspice scripts and other files used to prepare
|
||||
Verilog (and possibly VHDL) code to be included in an Ngspice simulation.
|
||||
An example circuit can be found in examples/xspice/verilator.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/* Dummy main() for Verilator. */
|
||||
|
||||
#include "ngspice/cmtypes.h" // For Digital_t
|
||||
#include "ngspice/cosim.h" // For struct co_info and prototypes
|
||||
|
||||
int main(int argc, char** argv, char**) {
|
||||
struct co_info info;
|
||||
|
||||
Cosim_setup(&info);
|
||||
for (;;)
|
||||
(*info.step)(&info);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
/* This is a very mangled version of Vadc__main.cpp as generated by Verilator. */
|
||||
|
||||
// Verilated -*- C++ -*-
|
||||
// DESCRIPTION: main() calling loop, created with Verilator --main
|
||||
|
||||
#include "verilated.h"
|
||||
#include "Vlng.h"
|
||||
|
||||
#include "ngspice/cmtypes.h" // For Digital_t
|
||||
#include "ngspice/cosim.h" // For struct co_info and prototypes
|
||||
|
||||
//======================
|
||||
|
||||
/* Structure for the input table. */
|
||||
|
||||
struct input {
|
||||
const char *name;
|
||||
unsigned int offset;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/* This VL_DATA macro is used in header files inputs.h, outputs.h and inouts.h
|
||||
* to write functions accept_input() and step().
|
||||
* The macro is used several times with different definitions.
|
||||
*/
|
||||
|
||||
/* Generate the previous values table used by step(). */
|
||||
|
||||
#define VL_DATA(size, name, msb, lsb) + msb - lsb + 1
|
||||
static const unsigned int outs = 0
|
||||
#include "outputs.h"
|
||||
;
|
||||
static const unsigned int inouts = 0
|
||||
#include "inouts.h"
|
||||
;
|
||||
|
||||
static unsigned char previous_output[outs + inouts];
|
||||
|
||||
#undef VL_DATA
|
||||
|
||||
/* The input function: it should ignore out-of-range values of index. */
|
||||
|
||||
#define VL_DATA(size, name, msb, lsb) \
|
||||
if (index >= msb - lsb + 1) { \
|
||||
index -= msb - lsb + 1; \
|
||||
} else if (msb == 0 && lsb == 0) { \
|
||||
topp->name = val ? 1 : 0; \
|
||||
return; \
|
||||
} else { \
|
||||
if (val) \
|
||||
topp->name |= (1 << (msb - index)); \
|
||||
else \
|
||||
topp->name &= (1 << (msb - index)); \
|
||||
return; \
|
||||
}
|
||||
|
||||
static void accept_input(struct co_info *pinfo,
|
||||
unsigned int index, Digital_t *vp)
|
||||
{
|
||||
Vlng *topp = (Vlng *)pinfo->handle;
|
||||
unsigned int val, offset;
|
||||
|
||||
val = vp->state;
|
||||
if (val == UNKNOWN)
|
||||
return; // Verilator simulations are two-state.
|
||||
|
||||
#include "inputs.h"
|
||||
|
||||
/* For inout ports the new value must be stored to detect changes. */
|
||||
|
||||
offset = outs;
|
||||
#undef VL_DATA
|
||||
#define VL_DATA(size, name, msb, lsb) \
|
||||
if (index >= msb - lsb + 1) { \
|
||||
index -= msb - lsb + 1; \
|
||||
offset += msb - lsb + 1; \
|
||||
} else if (msb == 0 && lsb == 0) { \
|
||||
topp->name = val ? 1 : 0; \
|
||||
previous_output[index + offset] = val; \
|
||||
return; \
|
||||
} else { \
|
||||
if (val) \
|
||||
topp->name | (1 << (msb - index)); \
|
||||
else \
|
||||
topp->name &= (1 << (msb - index)); \
|
||||
previous_output[index + offset] = val; \
|
||||
return; \
|
||||
}
|
||||
|
||||
#include "inouts.h"
|
||||
}
|
||||
#undef VL_DATA
|
||||
|
||||
/* The step function that calls the Verilator code. */
|
||||
|
||||
#define VL_DATA(size, name, msb, lsb) \
|
||||
for (i = msb; i >= lsb; --i) { \
|
||||
if (topp->name & (1 << i)) \
|
||||
bit = 1; \
|
||||
else \
|
||||
bit = 0; \
|
||||
if (bit ^ previous_output[index]) { \
|
||||
previous_output[index] = bit; \
|
||||
oval.state = (Digital_State_t)bit; \
|
||||
(*pinfo->out_fn)(pinfo, index, &oval); \
|
||||
} \
|
||||
++index; \
|
||||
}
|
||||
|
||||
static void step(struct co_info *pinfo)
|
||||
{
|
||||
static Digital_t oval = {ZERO, STRONG};
|
||||
Vlng *topp;
|
||||
int index, i;
|
||||
unsigned char bit;
|
||||
|
||||
topp = (Vlng *)pinfo->handle;
|
||||
topp->eval();
|
||||
|
||||
/* Now scan the outputs for changes. */
|
||||
|
||||
index = 0;
|
||||
#include "outputs.h"
|
||||
#include "inouts.h"
|
||||
}
|
||||
#undef VL_DATA
|
||||
|
||||
extern "C" void Cosim_setup(struct co_info *pinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Setup context, and defaults
|
||||
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating
|
||||
|
||||
Vlng *topp{new Vlng{contextp.get()}};
|
||||
|
||||
/* Return information to caller. */
|
||||
|
||||
pinfo->handle = topp;
|
||||
pinfo->step = step;
|
||||
|
||||
#define VL_DATA(size, name, msb, lsb) i += msb - lsb + 1; // Count ports
|
||||
|
||||
i = 0;
|
||||
#include "inputs.h"
|
||||
pinfo->in_count = i;
|
||||
|
||||
pinfo->out_count = outs;
|
||||
pinfo->inout_count = inouts;
|
||||
pinfo->in_fn = accept_input;
|
||||
pinfo->method = After_input; // Verilator requires input to advance.
|
||||
}
|
||||
#undef VL_DATA
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
*ng_script_with_params
|
||||
// This Ngspice interpreter script accepts arbitrary argiments to
|
||||
// the Verilator compiler (Verilog to C++) and builds a shared library
|
||||
// or DLL that can be loaded by the d_cosim XSPICE code model.
|
||||
// Instances of the model are then digital circuit elements whose
|
||||
// behaviour is controlled by the Verilog source.
|
||||
|
||||
set bad=0
|
||||
if $?argc = 0
|
||||
set bad=1
|
||||
end
|
||||
|
||||
if $argc <= 0
|
||||
set bad=1
|
||||
end
|
||||
|
||||
if $bad
|
||||
echo Arguments acceptable to Verilator are required.
|
||||
quit
|
||||
end
|
||||
|
||||
// Disable special processing of '{'.
|
||||
|
||||
set noglob
|
||||
|
||||
// Set parameters for Windows or Unix-like OS.
|
||||
// For setting CFLAGS (passed to Verilator) it is somewhat arbitrarily
|
||||
// assumed that if Ngspice was compiled with VisualC++, then that is
|
||||
// the compiler to be used with Verilator. Edit to change.
|
||||
|
||||
// Compilation option for C/C++: -fpic is required by GCC for a shared library
|
||||
|
||||
if $oscompiled = 8 // VisualC++ - Verilator is a Perl script
|
||||
setcs cflags="--CFLAGS -fpic --compiler msvc"
|
||||
else
|
||||
setcs cflags="--CFLAGS -fpic" // For g++
|
||||
end
|
||||
|
||||
if $oscompiled = 2 | $oscompiled = 3 | $oscompiled = 8 // Windows
|
||||
set windows=1
|
||||
set dirsep1="\\"
|
||||
set dirsep2="/"
|
||||
set vloc="C:/mingw64/bin/verilator" // Expected location on Windows
|
||||
set run_verilator="perl $vloc"
|
||||
else
|
||||
set windows=0
|
||||
set dirsep1="/"
|
||||
set run_verilator=verilator
|
||||
end
|
||||
|
||||
if $oscompiled = 7 // MacOS
|
||||
set macos=1
|
||||
setcs cflags="$cflags --compiler clang"
|
||||
else
|
||||
set macos=0
|
||||
end
|
||||
|
||||
// Loop through the arguments to find Verilog source: some_path/xxxx.v
|
||||
// The output file will have the same base name.
|
||||
|
||||
let index=1
|
||||
set off=1 // Avoid error in dowhile
|
||||
repeat $argc
|
||||
set base="$argv[$&index]"
|
||||
let index = index + 1
|
||||
strstr l "$base" ""
|
||||
if $l > 2 // Look for xxxx.v
|
||||
strslice tail "$base" -2 2
|
||||
strcmp bad "$tail" ".v"
|
||||
if $bad <> 0
|
||||
set base=""
|
||||
continue
|
||||
end
|
||||
let l = $l - 2
|
||||
strslice base "$base" 0 $&l
|
||||
else
|
||||
set base=""
|
||||
continue
|
||||
end
|
||||
|
||||
dowhile $off >= 0 // Strip leading directories
|
||||
strstr off "$base" "$dirsep1"
|
||||
if $windows
|
||||
if $off < 0
|
||||
strstr off "$base" "$dirsep2"
|
||||
end
|
||||
end
|
||||
if $off >= 0
|
||||
let off=$off+1
|
||||
strslice base "$base" $&off $l
|
||||
end
|
||||
end
|
||||
|
||||
strstr l "$base" "" // Check for zero-length string
|
||||
if $l > 0
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if index - 1 > $argc
|
||||
set base=verilated // Default name
|
||||
end
|
||||
|
||||
// Define working directory for Verilator
|
||||
|
||||
set tail="_obj_dir"
|
||||
setcs objdir="$base$tail"
|
||||
|
||||
// Default base name of output file.
|
||||
|
||||
if $windows
|
||||
setcs tail=".DLL"
|
||||
else
|
||||
setcs tail=".so"
|
||||
end
|
||||
setcs soname="$base$tail"
|
||||
|
||||
// First convert to C++, PREFIX determines the file names.
|
||||
|
||||
setcs prefix="Vlng"
|
||||
|
||||
// Run Verilator on the given input files.
|
||||
|
||||
shell $run_verilator --Mdir $objdir --prefix $prefix $cflags --cc $argv
|
||||
|
||||
// Parse the primary interface Class definition for members representing
|
||||
// the ports of the top-level Verilog module.
|
||||
// Example conversion: VL_IN8(&Clk,0,0); ==> VL_DATA(8,Clk,0,0)
|
||||
|
||||
cd $objdir
|
||||
echo "/* Generated code: do not edit. */" > inouts.h
|
||||
echo "/* Generated code: do not edit. */" > inputs.h
|
||||
echo "/* Generated code: do not edit. */" > outputs.h
|
||||
|
||||
// This loop is intended to have the same effect as:
|
||||
// sed --quiet -e 's/VL_IN\([0-9]*\)(&\(.*\);/VL_DATA(\1,\2/p' \
|
||||
// obj_dir/${PREFIX}.h >> inputs.h
|
||||
|
||||
set htail=".h"
|
||||
setcs inout="VL_INOUT"
|
||||
setcs in="VL_IN"
|
||||
setcs out="VL_OUT"
|
||||
|
||||
set fn="$prefix$htail" // Like foo-obj_dir/Vlng.h
|
||||
fopen fh $fn
|
||||
if $fh < 0
|
||||
quit
|
||||
end
|
||||
|
||||
while 1
|
||||
fread line $fh l
|
||||
if $l < 0
|
||||
break
|
||||
end
|
||||
|
||||
// Does it contain a closing parenthesis?
|
||||
|
||||
strstr off "$line" ")"
|
||||
if $off < 0
|
||||
continue // No ")", ignore.
|
||||
end
|
||||
let off = $off + 1
|
||||
strslice line "$line" 0 $&off // Slice off tail.
|
||||
|
||||
// Is it an inout port definition?
|
||||
|
||||
strstr off "$line" $inout
|
||||
if $off >= 0 // Match found
|
||||
let off = $off + 8 // strlen("VL_INOUT") == 8
|
||||
strslice line "$line" $&off $l
|
||||
strstr off "$line" "("
|
||||
strslice size "$line" 0 $off
|
||||
let off = $off + 2 // strlen("(&") == 2
|
||||
strslice line "$line" $&off $l
|
||||
echo VL_DATA($size,$line >> inouts.h // New macro invocation
|
||||
continue
|
||||
end
|
||||
|
||||
// Input port?
|
||||
|
||||
strstr off "$line" $in
|
||||
if $off >= 0 // Match found
|
||||
let off = $off + 5 // strlen("VL_IN") == 5
|
||||
strslice line "$line" $&off $l
|
||||
strstr off "$line" "("
|
||||
strslice size "$line" 0 $off
|
||||
let off = $off + 2 // strlen("(&") == 2
|
||||
strslice line "$line" $&off $l
|
||||
echo VL_DATA($size,$line >> inputs.h // New macro invocation
|
||||
continue
|
||||
end
|
||||
|
||||
// Output port?
|
||||
|
||||
strstr off "$line" $out
|
||||
if $off >= 0 // Match found
|
||||
let off = $off + 6 // strlen("VL_OUT") == 6
|
||||
strslice line "$line" $&off $l
|
||||
strstr off "$line" "("
|
||||
strslice size "$line" 0 $off
|
||||
let off = $off + 2 // strlen("(&") == 2
|
||||
strslice line "$line" $&off $l
|
||||
echo VL_DATA($size,$line >> outputs.h // New macro invocation
|
||||
continue
|
||||
end
|
||||
end
|
||||
fclose $fh
|
||||
cd ..
|
||||
|
||||
// The shared library/DLL contains some ngspice source code as
|
||||
// well as that created by Verilator. Find it by scanning $sourcepath.
|
||||
|
||||
set shimfile=verilator_shim.cpp
|
||||
set shimobj=verilator_shim.o
|
||||
set mainfile=verilator_main.cpp
|
||||
set srcdir=src
|
||||
set silent_fileio // Silences fopen complaints
|
||||
|
||||
let i=1
|
||||
repeat $#sourcepath
|
||||
set stem="$sourcepath[$&i]"
|
||||
let i = i + 1
|
||||
set fn="$stem$dirsep1$shimfile"
|
||||
fopen fh $fn
|
||||
if $fh > 0
|
||||
break
|
||||
end
|
||||
set stem="$stem$dirsep1$srcdir"
|
||||
set fn="$stem$dirsep1$shimfile"
|
||||
fopen fh $fn
|
||||
if $fh > 0
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if $fh > 0
|
||||
fclose $fh
|
||||
set fn_main="$stem$dirsep1$mainfile"
|
||||
else
|
||||
echo Can not find C++ source file $shimfile
|
||||
quit
|
||||
end
|
||||
|
||||
if $windows
|
||||
// Verilator makes a mess of absolute include paths passed by --CFLAGS.
|
||||
// Copy the files instead.
|
||||
|
||||
set incdir=ngspice
|
||||
shell xcopy /i "$stem$dirsep1$incdir" "$objdir$dirsep1$incdir"
|
||||
setcs include="--CFLAGS -I."
|
||||
|
||||
// Copy verilator_shim.cpp for MSVC.CMD.
|
||||
|
||||
shell copy "$fn" "$objdir"
|
||||
else
|
||||
// Some header files are with the source.
|
||||
|
||||
strstr off "$stem" "."
|
||||
if $off <> 0
|
||||
setcs include="--CFLAGS -I$stem"
|
||||
else
|
||||
setcs include="--CFLAGS -I..$dirsep1$stem" // Relative path
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// Compile the code. Verilator only does that when building an executable,
|
||||
// so include verilator_main.cpp.
|
||||
|
||||
shell $run_verilator --Mdir $objdir --prefix $prefix $include $cflags
|
||||
+ --cc --build --exe
|
||||
+ $fn_main $fn $argv
|
||||
|
||||
strcmp bad "$shellstatus" "0"
|
||||
|
||||
if $bad = 0
|
||||
// g++ must be available: make a shared library/DLL.
|
||||
|
||||
set v_objs="$objdir$dirsep1$shimobj $objdir/verilated.o $objdir/verilated_threads.o"
|
||||
setcs tail="__ALL.a"
|
||||
setcs v_lib="$objdir/$prefix$tail" // Like Vlng__ALL.a
|
||||
|
||||
shell g++ --shared $v_objs $v_lib -pthread -lpthread -o $soname
|
||||
else
|
||||
// Assume we have CL.EXE and use that. A script avoids multiple \escapes.
|
||||
|
||||
if $windows = 0
|
||||
quit
|
||||
end
|
||||
|
||||
// Look for MSVC.CMD
|
||||
|
||||
set msvcfile=MSVC.CMD
|
||||
let i=1
|
||||
repeat $#sourcepath
|
||||
set stem="$sourcepath[$&i]"
|
||||
let i = i + 1
|
||||
set fn="$stem$dirsep1$msvcfile"
|
||||
fopen fh $fn
|
||||
if $fh > 0
|
||||
break
|
||||
end
|
||||
end
|
||||
if $fh > 0
|
||||
fclose $fh
|
||||
else
|
||||
echo Can not find bulid file $msvcfile
|
||||
quit
|
||||
end
|
||||
|
||||
echo Building with MSVC compiler, CL.EXE.
|
||||
cd $objdir
|
||||
shell $fn
|
||||
cd ..
|
||||
end
|
||||
quit
|
||||
|
|
@ -12,7 +12,6 @@ set cmsrc=.\codemodels\Win32\Release
|
|||
|
||||
mkdir %dst%\bin
|
||||
mkdir %dst%\lib\ngspice
|
||||
mkdir %dst%\share\ngspice\scripts
|
||||
|
||||
copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\
|
||||
copy %cmsrc%\analog.cm %dst%\lib\ngspice\analog.cm
|
||||
|
|
@ -21,8 +20,6 @@ copy %cmsrc%\table.cm %dst%\lib\ngspice\table.cm
|
|||
copy %cmsrc%\xtraevt.cm %dst%\lib\ngspice\xtraevt.cm
|
||||
copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm
|
||||
copy %cmsrc%\spice2poly.cm %dst%\lib\ngspice\spice2poly.cm
|
||||
copy .\spinit_all %dst%\share\ngspice\scripts\spinit
|
||||
copy .\spinitr .\spinit
|
||||
|
||||
if "%2" == "fftw" goto copy2
|
||||
if "%3" == "fftw" goto copy2
|
||||
|
|
@ -42,7 +39,6 @@ set cmsrc=.\codemodels\x64\Release
|
|||
|
||||
mkdir %dst%\bin
|
||||
mkdir %dst%\lib\ngspice
|
||||
mkdir %dst%\share\ngspice\scripts
|
||||
|
||||
copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\
|
||||
copy %cmsrc%\analog64.cm %dst%\lib\ngspice\analog.cm
|
||||
|
|
@ -51,8 +47,6 @@ copy %cmsrc%\table64.cm %dst%\lib\ngspice\table.cm
|
|||
copy %cmsrc%\xtraevt64.cm %dst%\lib\ngspice\xtraevt.cm
|
||||
copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm
|
||||
copy %cmsrc%\spice2poly64.cm %dst%\lib\ngspice\spice2poly.cm
|
||||
copy .\spinit_all %dst%\share\ngspice\scripts\spinit
|
||||
copy .\spinitr64 .\spinit
|
||||
|
||||
if "%2" == "fftw" goto copy2-64
|
||||
if "%3" == "fftw" goto copy2-64
|
||||
|
|
@ -65,3 +59,18 @@ copy %1\ngspice.exe %dst%\bin\
|
|||
copy ..\..\fftw-3.3-dll64\libfftw3-3.dll %dst%\bin\
|
||||
|
||||
:end
|
||||
mkdir %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy .\spinit_all %dst%\share\ngspice\scripts\spinit
|
||||
copy .\spinitr .\spinit
|
||||
cd ..\src
|
||||
copy ciderinit %dst%\share\ngspice\scripts
|
||||
copy devaxis %dst%\share\ngspice\scripts
|
||||
copy devload %dst%\share\ngspice\scripts
|
||||
copy setplot %dst%\share\ngspice\scripts
|
||||
copy spectrum %dst%\share\ngspice\scripts
|
||||
copy xspice\verilog\vlnggen %dst%\share\ngspice\scripts
|
||||
copy xspice\verilog\MSVC.CMD %dst%\share\ngspice\scripts
|
||||
copy xspice\verilog\*.cpp %dst%\share\ngspice\scripts\src
|
||||
copy include\ngspice\cosim.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy include\ngspice\miftypes.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy include\ngspice\cmtypes.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ set cmsrc=.\codemodels\Win32\Debug
|
|||
|
||||
mkdir %dst%\bin
|
||||
mkdir %dst%\lib\ngspice
|
||||
mkdir %dst%\share\ngspice\scripts
|
||||
|
||||
copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\
|
||||
copy %cmsrc%\analog.cm %dst%\lib\ngspice\analog.cm
|
||||
|
|
@ -21,8 +20,6 @@ copy %cmsrc%\table.cm %dst%\lib\ngspice\table.cm
|
|||
copy %cmsrc%\xtraevt.cm %dst%\lib\ngspice\xtraevt.cm
|
||||
copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm
|
||||
copy %cmsrc%\spice2poly.cm %dst%\lib\ngspice\spice2poly.cm
|
||||
copy .\spinit_all %dst%\share\ngspice\scripts\spinit
|
||||
copy .\spinitd .\spinit
|
||||
|
||||
if "%2" == "fftw" goto copy2
|
||||
if "%3" == "fftw" goto copy2
|
||||
|
|
@ -42,7 +39,6 @@ set cmsrc=.\codemodels\x64\Debug
|
|||
|
||||
mkdir %dst%\bin
|
||||
mkdir %dst%\lib\ngspice
|
||||
mkdir %dst%\share\ngspice\scripts
|
||||
|
||||
copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\
|
||||
copy %cmsrc%\analog64.cm %dst%\lib\ngspice\analog.cm
|
||||
|
|
@ -51,8 +47,6 @@ copy %cmsrc%\table64.cm %dst%\lib\ngspice\table.cm
|
|||
copy %cmsrc%\xtraevt64.cm %dst%\lib\ngspice\xtraevt.cm
|
||||
copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm
|
||||
copy %cmsrc%\spice2poly64.cm %dst%\lib\ngspice\spice2poly.cm
|
||||
copy .\spinit_all %dst%\share\ngspice\scripts\spinit
|
||||
copy .\spinitd64 .\spinit
|
||||
|
||||
if "%2" == "fftw" goto copy2-64
|
||||
if "%3" == "fftw" goto copy2-64
|
||||
|
|
@ -65,3 +59,18 @@ copy %1\ngspice.exe %dst%\bin\
|
|||
copy ..\..\fftw-3.3-dll64\libfftw3-3.dll %dst%\bin\
|
||||
|
||||
:end
|
||||
mkdir %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy .\spinit_all %dst%\share\ngspice\scripts\spinit
|
||||
copy .\spinitr .\spinit
|
||||
cd ..\src
|
||||
copy ciderinit %dst%\share\ngspice\scripts
|
||||
copy devaxis %dst%\share\ngspice\scripts
|
||||
copy devload %dst%\share\ngspice\scripts
|
||||
copy setplot %dst%\share\ngspice\scripts
|
||||
copy spectrum %dst%\share\ngspice\scripts
|
||||
copy xspice\verilog\vlnggen %dst%\share\ngspice\scripts
|
||||
copy xspice\verilog\MSVC.CMD %dst%\share\ngspice\scripts
|
||||
copy xspice\verilog\*.cpp %dst%\share\ngspice\scripts\src
|
||||
copy include\ngspice\cosim.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy include\ngspice\miftypes.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy include\ngspice\cmtypes.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@
|
|||
<ClInclude Include="..\src\frontend\com_dump.h" />
|
||||
<ClInclude Include="..\src\frontend\com_echo.h" />
|
||||
<ClInclude Include="..\src\frontend\com_fft.h" />
|
||||
<ClInclude Include="..\src\frontend\com_fileio.h" />
|
||||
<ClInclude Include="..\src\frontend\com_ghelp.h" />
|
||||
<ClInclude Include="..\src\frontend\com_gnuplot.h" />
|
||||
<ClInclude Include="..\src\frontend\com_hardcopy.h" />
|
||||
|
|
@ -1007,6 +1008,7 @@
|
|||
<ClCompile Include="..\src\frontend\com_dump.c" />
|
||||
<ClCompile Include="..\src\frontend\com_echo.c" />
|
||||
<ClCompile Include="..\src\frontend\com_fft.c" />
|
||||
<ClCompile Include="..\src\frontend\com_fileio.c" />
|
||||
<ClCompile Include="..\src\frontend\com_ghelp.c" />
|
||||
<ClCompile Include="..\src\frontend\com_gnuplot.c" />
|
||||
<ClCompile Include="..\src\frontend\com_hardcopy.c" />
|
||||
|
|
@ -1220,6 +1222,7 @@
|
|||
<ClCompile Include="..\src\misc\string.c" />
|
||||
<ClCompile Include="..\src\misc\tilde.c" />
|
||||
<ClCompile Include="..\src\misc\util.c" />
|
||||
<ClCompile Include="..\src\misc\win_time.c" />
|
||||
<ClCompile Include="..\src\misc\wlist.c" />
|
||||
<ClCompile Include="..\src\ngspice.c" />
|
||||
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
||||
|
|
|
|||
|
|
@ -854,6 +854,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClInclude Include="..\src\frontend\com_dump.h" />
|
||||
<ClInclude Include="..\src\frontend\com_echo.h" />
|
||||
<ClInclude Include="..\src\frontend\com_fft.h" />
|
||||
<ClInclude Include="..\src\frontend\com_fileio.h" />
|
||||
<ClInclude Include="..\src\frontend\com_ghelp.h" />
|
||||
<ClInclude Include="..\src\frontend\com_gnuplot.h" />
|
||||
<ClInclude Include="..\src\frontend\com_hardcopy.h" />
|
||||
|
|
@ -1467,6 +1468,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\frontend\com_dump.c" />
|
||||
<ClCompile Include="..\src\frontend\com_echo.c" />
|
||||
<ClCompile Include="..\src\frontend\com_fft.c" />
|
||||
<ClCompile Include="..\src\frontend\com_fileio.c" />
|
||||
<ClCompile Include="..\src\frontend\com_ghelp.c" />
|
||||
<ClCompile Include="..\src\frontend\com_gnuplot.c" />
|
||||
<ClCompile Include="..\src\frontend\com_hardcopy.c" />
|
||||
|
|
@ -1686,6 +1688,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\misc\string.c" />
|
||||
<ClCompile Include="..\src\misc\tilde.c" />
|
||||
<ClCompile Include="..\src\misc\util.c" />
|
||||
<ClCompile Include="..\src\misc\win_time.c" />
|
||||
<ClCompile Include="..\src\misc\wlist.c" />
|
||||
<ClCompile Include="..\src\ngspice.c" />
|
||||
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
||||
|
|
|
|||
|
|
@ -885,6 +885,7 @@
|
|||
<ClInclude Include="..\src\frontend\com_shift.h" />
|
||||
<ClInclude Include="..\src\frontend\com_state.h" />
|
||||
<ClInclude Include="..\src\frontend\com_strcmp.h" />
|
||||
<ClInclude Include="..\src\frontend\com_fileio.h" />
|
||||
<ClInclude Include="..\src\frontend\com_unset.h" />
|
||||
<ClInclude Include="..\src\frontend\com_wr_ic.h" />
|
||||
<ClInclude Include="..\src\frontend\control.h" />
|
||||
|
|
@ -1498,6 +1499,7 @@
|
|||
<ClCompile Include="..\src\frontend\com_shift.c" />
|
||||
<ClCompile Include="..\src\frontend\com_state.c" />
|
||||
<ClCompile Include="..\src\frontend\com_strcmp.c" />
|
||||
<ClCompile Include="..\src\frontend\com_fileio.c" />
|
||||
<ClCompile Include="..\src\frontend\com_sysinfo.c" />
|
||||
<ClCompile Include="..\src\frontend\com_unset.c" />
|
||||
<ClCompile Include="..\src\frontend\com_wr_ic.c" />
|
||||
|
|
@ -1700,6 +1702,7 @@
|
|||
<ClCompile Include="..\src\misc\string.c" />
|
||||
<ClCompile Include="..\src\misc\tilde.c" />
|
||||
<ClCompile Include="..\src\misc\util.c" />
|
||||
<ClCompile Include="..\src\misc\win_time.c" />
|
||||
<ClCompile Include="..\src\misc\wlist.c" />
|
||||
<ClCompile Include="..\src\ngspice.c" />
|
||||
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
||||
|
|
@ -2893,4 +2896,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -322,6 +322,10 @@
|
|||
<AdditionalIncludeDirectories>..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile Include="icm\digital\d_xor\d_xor-ifspec.c" />
|
||||
<ClCompile Include="icm\digital\d_cosim\d_cosim-ifspec.c" />
|
||||
<ClCompile Include="icm\digital\d_cosim\d_cosim-cfunc.c">
|
||||
<AdditionalIncludeDirectories>..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\xspice\icm\dlmain.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
|||
Loading…
Reference in New Issue