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
|
# external OpenVAF Verilig-A compiler, will allow access to advanced compact
|
||||||
# device models writen in Verilog-A.
|
# device models writen in Verilog-A.
|
||||||
# Please see the ngspice manual, chapt. 13, for more info on using OSDI/OpenVAF.
|
# 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.
|
# --disable-debug will give O2 optimization (versus O0 for debug) and removes all debugging info.
|
||||||
|
|
||||||
# ngspice as shared library:
|
# ngspice as shared library:
|
||||||
|
|
@ -48,13 +49,13 @@ if test "$1" = "d"; then
|
||||||
if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi
|
||||||
echo "configuring for 64 bit debug"
|
echo "configuring for 64 bit debug"
|
||||||
echo
|
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
|
else
|
||||||
cd release
|
cd release
|
||||||
if [ $? -ne 0 ]; then echo "cd release failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "cd release failed"; exit 1 ; fi
|
||||||
echo "configuring for 64 bit release"
|
echo "configuring for 64 bit release"
|
||||||
echo
|
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
|
fi
|
||||||
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; 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
|
# --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.
|
# 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.
|
# 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.
|
# --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.
|
# Add (optionally) --enable-relpath to avoid absolute paths when searching for code models.
|
||||||
|
|
@ -44,7 +44,7 @@ if test "$1" = "d"; then
|
||||||
echo
|
echo
|
||||||
# The --prefix (and perhaps --libdir) may be used to determine a different install location
|
# 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).
|
# (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
|
else
|
||||||
cd releasesh
|
cd releasesh
|
||||||
if [ $? -ne 0 ]; then echo "cd releasesh failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "cd releasesh failed"; exit 1 ; fi
|
||||||
|
|
@ -52,7 +52,7 @@ else
|
||||||
echo
|
echo
|
||||||
# The --prefix (and perhaps --libdir) may be used to determine a different install location
|
# 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).
|
# (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
|
fi
|
||||||
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,8 @@
|
||||||
# for debug version of shared ngspice
|
# for debug version of shared ngspice
|
||||||
|
|
||||||
# Options:
|
# 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.
|
# 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.
|
# --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.
|
# To obtain a 32 bit executable, replace -m64 by -m32 ./configure lines.
|
||||||
|
|
||||||
|
|
@ -38,27 +36,19 @@ fi
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi
|
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
|
echo
|
||||||
if test "$1" = "d"; then
|
if test "$1" = "d"; then
|
||||||
cd debug-sh
|
cd debug-sh
|
||||||
if [ $? -ne 0 ]; then echo "cd debug-sh failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "cd debug-sh failed"; exit 1 ; fi
|
||||||
echo "configuring for 64 bit debug"
|
echo "configuring for 64 bit debug"
|
||||||
echo
|
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-klu --enable-relpath prefix="C:/Spice64d" CFLAGS="-m64 -g -O0 -Wall" LDFLAGS="-m64"
|
||||||
../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"
|
|
||||||
else
|
else
|
||||||
cd release-sh
|
cd release-sh
|
||||||
if [ $? -ne 0 ]; then echo "cd release-sh failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "cd release-sh failed"; exit 1 ; fi
|
||||||
echo "configuring for 64 bit release"
|
echo "configuring for 64 bit release"
|
||||||
echo
|
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-klu --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-relpath --disable-debug prefix="C:/Spice64" CFLAGS="-m64 -O2" LDFLAGS="-m64 -s"
|
|
||||||
fi
|
fi
|
||||||
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ q4 7 7 9 qnl
|
||||||
rbias 7 8 20k
|
rbias 7 8 20k
|
||||||
.model qnl npn(bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf
|
.model qnl npn(bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf
|
||||||
+ va=50)
|
+ va=50)
|
||||||
.print dc v(4) v(5)
|
*.print dc v(4) v(5)
|
||||||
.plot dc v(5)
|
*.plot dc v(5)
|
||||||
.print ac vm(5) vp(5)
|
*.print ac vm(5) vp(5)
|
||||||
.plot ac vm(5) vp(5)
|
*.plot ac vm(5) vp(5)
|
||||||
.print tran v(4) v(5)
|
.print tran v(4) v(5)
|
||||||
.plot tran v(5)
|
.plot tran v(5)
|
||||||
.end
|
.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
|
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
|
.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)
|
+ level=1 cgso=1u cgdo=1u cbd=50p cbs=50p)
|
||||||
.print dc v(5) v(6)
|
*.print dc v(5) v(6)
|
||||||
.plot dc v(6)
|
*.plot dc v(6)
|
||||||
.plot tran v(6) v(5) v(7) v(1) v(2)
|
.plot tran v(6) v(5) v(7) v(1) v(2)
|
||||||
.end
|
.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_dump.h \
|
||||||
com_echo.c \
|
com_echo.c \
|
||||||
com_echo.h \
|
com_echo.h \
|
||||||
|
com_fileio.c \
|
||||||
|
com_fileio.h \
|
||||||
com_ghelp.c \
|
com_ghelp.c \
|
||||||
com_ghelp.h \
|
com_ghelp.h \
|
||||||
com_gnuplot.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;
|
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.;
|
prevValue = 0.;
|
||||||
prevValue2 = 0.;
|
prevValue2 = 0.;
|
||||||
prevScaleValue = 0.;
|
prevScaleValue = 0.;
|
||||||
|
|
@ -658,6 +663,11 @@ measure_at(
|
||||||
return MEASUREMENT_FAILURE;
|
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.
|
* Take the string tests outside of the loop for speed.
|
||||||
* ----------------------------------------------------------------- */
|
* ----------------------------------------------------------------- */
|
||||||
|
|
@ -768,7 +778,12 @@ measure_minMaxAvg(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dScale == NULL) {
|
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;
|
return MEASUREMENT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -944,7 +959,12 @@ measure_rms_integral(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xScale == NULL) {
|
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;
|
return MEASUREMENT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,54 @@ com_strcmp(wordlist *wl)
|
||||||
tfree(s2);
|
tfree(s2);
|
||||||
cp_vset(var, CP_NUM, &i);
|
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
|
#ifndef ngspice_COM_STRCMP_H
|
||||||
#define ngspice_COM_STRCMP_H
|
#define ngspice_COM_STRCMP_H
|
||||||
|
|
||||||
|
extern void com_strcmp(wordlist *wl);
|
||||||
void com_strcmp(wordlist *wl);
|
extern void com_strstr(wordlist *wl);
|
||||||
|
extern void com_strslice(wordlist *wl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "diff.h"
|
#include "diff.h"
|
||||||
#include "com_strcmp.h"
|
#include "com_strcmp.h"
|
||||||
|
#include "com_fileio.h"
|
||||||
#include "ngspice/randnumb.h"
|
#include "ngspice/randnumb.h"
|
||||||
#include "../spicelib/analysis/com_optran.h"
|
#include "../spicelib/analysis/com_optran.h"
|
||||||
#include "com_wr_ic.h"
|
#include "com_wr_ic.h"
|
||||||
|
|
@ -613,6 +614,30 @@ struct comm spcp_coms[] = {
|
||||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
||||||
NULL,
|
NULL,
|
||||||
"varname s1 s2 : Set $varname to strcmp(s1, s2)." } ,
|
"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,
|
{ "linearize", com_linearize, FALSE, FALSE,
|
||||||
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
|
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
@ -1033,6 +1058,30 @@ struct comm nutcp_coms[] = {
|
||||||
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
|
||||||
NULL,
|
NULL,
|
||||||
"varname s1 s2 : Set $varname to strcmp(s1, s2)." } ,
|
"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,
|
{ "linearize", com_linearize, TRUE, FALSE,
|
||||||
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
|
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,54 @@
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ngspice/ngspice.h"
|
#include "ngspice/ngspice.h"
|
||||||
#include "ngspice/dvec.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,
|
struct dvec *dvec_alloc(/* NOT const -- assigned to char */ char *name,
|
||||||
int type, short flags, int length, void *storage)
|
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 */
|
} /* 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
|
* its existing allocation with storage if not
|
||||||
*/
|
*/
|
||||||
void dvec_realloc(struct dvec *v, int length, void *storage)
|
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;
|
v->v_alloc_length = length;
|
||||||
} /* end of function dvec_realloc */
|
} /* 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)
|
void dvec_extend(struct dvec *v, int length)
|
||||||
{
|
{
|
||||||
|
#if defined SHARED_MODULE
|
||||||
|
mutex_lock(&vecreallocMutex);
|
||||||
|
#endif
|
||||||
if (isreal(v)) {
|
if (isreal(v)) {
|
||||||
v->v_realdata = TREALLOC(double, v->v_realdata, length);
|
v->v_realdata = TREALLOC(double, v->v_realdata, length);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length);
|
v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
v->v_alloc_length = length;
|
v->v_alloc_length = length;
|
||||||
|
#if defined SHARED_MODULE
|
||||||
|
mutex_unlock(&vecreallocMutex);
|
||||||
|
#endif
|
||||||
} /* end of function dvec_extend */
|
} /* end of function dvec_extend */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ Author: 1985 Wayne A. Christopher
|
||||||
#include "subckt.h"
|
#include "subckt.h"
|
||||||
#include "spiceif.h"
|
#include "spiceif.h"
|
||||||
#include "com_let.h"
|
#include "com_let.h"
|
||||||
|
#include "com_set.h"
|
||||||
#include "com_commands.h"
|
#include "com_commands.h"
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
|
|
@ -57,8 +58,9 @@ static wordlist *inp_savecurrents(struct card *deck, struct card *options,
|
||||||
wordlist *wl, wordlist *controls);
|
wordlist *wl, wordlist *controls);
|
||||||
static void recifeval(struct card *pdeck);
|
static void recifeval(struct card *pdeck);
|
||||||
static char *upper(register char *string);
|
static char *upper(register char *string);
|
||||||
|
#ifdef REM_UNUSED
|
||||||
static void rem_unused_mos_models(struct card* deck);
|
static void rem_unused_mos_models(struct card* deck);
|
||||||
|
#endif
|
||||||
extern void com_optran(wordlist * wl);
|
extern void com_optran(wordlist * wl);
|
||||||
extern void tprint(struct card *deck);
|
extern void tprint(struct card *deck);
|
||||||
|
|
||||||
|
|
@ -88,6 +90,17 @@ extern void exec_controls(wordlist *controls);
|
||||||
extern void SetSource(char *Name);
|
extern void SetSource(char *Name);
|
||||||
#endif
|
#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
|
/* structure used to save expression parse trees for .model and
|
||||||
* device instance lines
|
* device instance lines
|
||||||
*/
|
*/
|
||||||
|
|
@ -100,6 +113,7 @@ struct pt_temper {
|
||||||
struct pt_temper *next;
|
struct pt_temper *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int inp_parse_temper(struct card *deck,
|
static int inp_parse_temper(struct card *deck,
|
||||||
struct pt_temper **motdlist_p,
|
struct pt_temper **motdlist_p,
|
||||||
struct pt_temper **devtlist_p);
|
struct pt_temper **devtlist_p);
|
||||||
|
|
@ -438,9 +452,10 @@ eval_opt(struct card* deck)
|
||||||
char* token = gettok(&begtok);
|
char* token = gettok(&begtok);
|
||||||
/* option seed=random [seed='random'] */
|
/* option seed=random [seed='random'] */
|
||||||
if (eq(token, "random") || eq(token, "{random}")) {
|
if (eq(token, "random") || eq(token, "{random}")) {
|
||||||
time_t acttime = time(NULL);
|
struct timeval tv;
|
||||||
/* get random value from time in seconds since 1.1.1970 */
|
gettimeofday(&tv, NULL);
|
||||||
int rseed = (int)(acttime - 1600000000);
|
/* get random value from current timestamp microseconds */
|
||||||
|
int rseed = (int)(tv.tv_usec);
|
||||||
cp_vset("rndseed", CP_NUM, &rseed);
|
cp_vset("rndseed", CP_NUM, &rseed);
|
||||||
com_sseed(NULL);
|
com_sseed(NULL);
|
||||||
has_seed = TRUE;
|
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
|
* the cards .control and .endc, unless comfile is TRUE, in which
|
||||||
* case every line must be a front-end command. There are too
|
* case every line must be a front-end command. There are too
|
||||||
* many problems with matching the first word on the line. */
|
* many problems with matching the first word on the line. */
|
||||||
|
|
||||||
ld = deck;
|
ld = deck;
|
||||||
if (comfile) {
|
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
|
/* Process each command, except 'option' which is assembled
|
||||||
in a list and ingnored here */
|
in a list and ingnored here */
|
||||||
|
|
||||||
for (dd = deck; dd; dd = ld) {
|
for (dd = deck; dd; dd = ld) {
|
||||||
ld = dd->nextcard;
|
ld = dd->nextcard;
|
||||||
if ((dd->line[0] == '*') && (dd->line[1] != '#'))
|
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);
|
cp_evloop(dd->line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (with_params) {
|
||||||
|
cp_remvar("argc");
|
||||||
|
cp_remvar("argv");
|
||||||
|
}
|
||||||
|
|
||||||
/* free the control deck */
|
/* free the control deck */
|
||||||
line_free(deck, TRUE);
|
line_free(deck, TRUE);
|
||||||
/* set to NULL to allow generation of a new dbs */
|
/* 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
|
/* merge the two option line structs
|
||||||
com_options (comfile == TRUE, filled in from spinit, .spiceinit, and *ng_sript), and
|
com_options (comfile == TRUE, filled in from spinit,
|
||||||
options (comfile == FALSE, filled in from circuit with .OPTIONS)
|
.spiceinit, and *ng_script), and options
|
||||||
|
(comfile == FALSE, filled in from circuit with .OPTIONS)
|
||||||
into options, thus keeping com_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)));
|
options = line_reverse(line_nconc(options, inp_deckcopy(com_options)));
|
||||||
|
|
||||||
/* List of all expressions found in instance and .model lines */
|
/* 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
|
/* If user wants all currents saved (.options savecurrents), add .save
|
||||||
to wl_first with all terminal currents available on selected devices */
|
to wl_first with all terminal currents available on selected devices */
|
||||||
wl_first = inp_savecurrents(deck, options, wl_first, controls);
|
wl_first = inp_savecurrents(deck, options, wl_first, controls);
|
||||||
|
#ifdef REM_UNUSED
|
||||||
/* Circuit is flat, all numbers expanded.
|
/* Circuit is flat, all numbers expanded.
|
||||||
So again try to remove unused MOS models.
|
So again try to remove unused MOS models.
|
||||||
All binning models are still here when w or l have been
|
All binning models are still here when w or l have been
|
||||||
determined by an expression. */
|
determined by an expression. */
|
||||||
// if (newcompat.hs || newcompat.spe)
|
if (newcompat.hs || newcompat.spe)
|
||||||
// rem_unused_mos_models(deck->nextcard);
|
rem_unused_mos_models(deck->nextcard);
|
||||||
|
#endif
|
||||||
/* now load deck into ft_curckt -- the current circuit. */
|
/* now load deck into ft_curckt -- the current circuit. */
|
||||||
if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0)
|
if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -2541,6 +2624,7 @@ struct mlist {
|
||||||
bool checked;
|
bool checked;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef REM_UNUSED
|
||||||
/* Finally get rid of unused MOS models */
|
/* Finally get rid of unused MOS models */
|
||||||
static void rem_unused_mos_models(struct card* deck) {
|
static void rem_unused_mos_models(struct card* deck) {
|
||||||
struct card *tmpc, *tmppc = NULL;
|
struct card *tmpc, *tmppc = NULL;
|
||||||
|
|
@ -2744,3 +2828,4 @@ static void rem_unused_mos_models(struct card* deck) {
|
||||||
modellist = tlist;
|
modellist = tlist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -584,6 +584,7 @@ static void delete_names(struct names *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
#ifdef CIDER
|
||||||
/* concatenate 2 strings, with space if spa == TRUE,
|
/* concatenate 2 strings, with space if spa == TRUE,
|
||||||
return malloced string (replacement for tprintf,
|
return malloced string (replacement for tprintf,
|
||||||
which is not efficient enough when reading PDKs
|
which is not efficient enough when reading PDKs
|
||||||
|
|
@ -613,6 +614,7 @@ static char *cat2strings(char *s1, char *s2, bool spa)
|
||||||
return strsum;
|
return strsum;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* line1
|
/* 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 */
|
/* add Inp_Path to buffer while keeping the sourcepath variable contents */
|
||||||
if (ciprefix("set", buffer)) {
|
if (ciprefix("set", buffer)) {
|
||||||
char *p = strstr(buffer, "sourcepath");
|
char *p;
|
||||||
if (p) {
|
|
||||||
|
p = skip_ws(buffer + 3); // Next word
|
||||||
|
if (strncmp(p, "sourcepath", 10) == 0 &&
|
||||||
|
skip_non_ws(p) == p + 10) {
|
||||||
p = strchr(buffer, ')');
|
p = strchr(buffer, ')');
|
||||||
if (p) {
|
if (p) {
|
||||||
*p = 0; // clear ) and insert Inp_Path in between
|
*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. */
|
/* Special treatment of code model file input. */
|
||||||
|
|
||||||
if (ciprefix(".model", string))
|
if (ciprefix(".model", string))
|
||||||
tmpstr = strstr(string, "file=");
|
tmpstr = strstr(string, "file=\"");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
keepquotes = ciprefix(".param", string); // Allow string params
|
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
|
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
|
the whole line is converted to a normal comment line (i.e. one that
|
||||||
begins with a '*').
|
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
|
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
|
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 */
|
/* look for comments */
|
||||||
while ((c = *d) != '\0') {
|
while ((c = *d) != '\0') {
|
||||||
d++;
|
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 == ';') {
|
if (*d == ';') {
|
||||||
break;
|
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;
|
char *equal, *beg, *buffer, *ptr1, *ptr2, *new_str;
|
||||||
|
|
||||||
equal = strchr(s, '=');
|
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) */
|
/* get subckt name (ptr1 will point to name) */
|
||||||
ptr1 = skip_non_ws(s);
|
ptr1 = skip_non_ws(s);
|
||||||
ptr1 = skip_ws(ptr1);
|
ptr1 = skip_ws(ptr1);
|
||||||
|
|
@ -3481,7 +3504,7 @@ static void inp_fix_for_numparam(
|
||||||
if (ciprefix(".subckt", c->line) || ciprefix("x", c->line)) {
|
if (ciprefix(".subckt", c->line) || ciprefix("x", c->line)) {
|
||||||
/* remove params: */
|
/* remove params: */
|
||||||
char *str_ptr = strstr(c->line, "params:");
|
char *str_ptr = strstr(c->line, "params:");
|
||||||
if (str_ptr)
|
if (str_ptr && isspace_c(str_ptr[-1]))
|
||||||
memcpy(str_ptr, " ", 7);
|
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[])
|
char *subckt_param_names[], char *subckt_param_values[])
|
||||||
{
|
{
|
||||||
struct card *card;
|
struct card *card;
|
||||||
char *new_str;
|
char *new_str, *s;
|
||||||
|
|
||||||
subckt_param_names[num_subckt_params] = copy("m");
|
subckt_param_names[num_subckt_params] = copy("m");
|
||||||
subckt_param_values[num_subckt_params] = copy("1");
|
subckt_param_values[num_subckt_params] = copy("1");
|
||||||
num_subckt_params++;
|
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);
|
new_str = tprintf("%s params: m=1", subckt_card->line);
|
||||||
add_name(subckt_w_params, get_subckt_model_name(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;
|
bool in_control = FALSE;
|
||||||
|
|
||||||
|
if (ft_skywaterpdk)
|
||||||
|
return;
|
||||||
|
|
||||||
for (; c && c != end_c; c = c->nextcard) {
|
for (; c && c != end_c; c = c->nextcard) {
|
||||||
|
|
||||||
int i, j, num_terminals;
|
int i, j, num_terminals;
|
||||||
|
|
@ -8333,6 +8360,7 @@ static void inp_check_syntax(struct card *deck)
|
||||||
bool mwarn = FALSE;
|
bool mwarn = FALSE;
|
||||||
char* subs[10]; /* store subckt lines */
|
char* subs[10]; /* store subckt lines */
|
||||||
int ends = 0; /* store .ends line numbers */
|
int ends = 0; /* store .ends line numbers */
|
||||||
|
static bool nesting_once = TRUE;
|
||||||
|
|
||||||
/* prevent crash in inp.c, fcn inp_spsource: */
|
/* prevent crash in inp.c, fcn inp_spsource: */
|
||||||
if (ciprefix(".param", deck->line) || ciprefix(".meas", deck->line)) {
|
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
|
// 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,
|
fprintf(cp_err,
|
||||||
"\nWarning: Nesting of subcircuits with parameters "
|
"\nWarning: Nesting of subcircuits with parameters "
|
||||||
"is only marginally supported!\n\n");
|
"is only marginally supported!\n\n");
|
||||||
|
nesting_once = FALSE;
|
||||||
|
}
|
||||||
if (check_subs < 10)
|
if (check_subs < 10)
|
||||||
subs[check_subs] = cut_line;
|
subs[check_subs] = cut_line;
|
||||||
else
|
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_acctprint = FALSE, ft_noacctprint = FALSE, ft_listprint = FALSE;
|
||||||
bool ft_nodesprint = FALSE, ft_optsprint = FALSE, ft_noinitprint = 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;
|
bool ft_ngdebug = FALSE, ft_nginfo = FALSE, ft_stricterror = FALSE;
|
||||||
|
|
||||||
static void setdb(char *str);
|
static void setdb(char *str);
|
||||||
|
|
@ -307,6 +307,8 @@ cp_usrset(struct variable *var, bool isset)
|
||||||
ft_ngdebug = isset;
|
ft_ngdebug = isset;
|
||||||
} else if (eq(var->va_name, "nginfo")) {
|
} else if (eq(var->va_name, "nginfo")) {
|
||||||
ft_nginfo = isset;
|
ft_nginfo = isset;
|
||||||
|
} else if (eq(var->va_name, "skywaterpdk")) {
|
||||||
|
ft_skywaterpdk = isset;
|
||||||
} else if (eq(var->va_name, "noinit")) {
|
} else if (eq(var->va_name, "noinit")) {
|
||||||
ft_noinitprint = isset;
|
ft_noinitprint = isset;
|
||||||
} else if (eq(var->va_name, "norefvalue")) {
|
} 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];
|
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||||
fileAddRealValue(run->fp, run->binary, newval);
|
fileAddRealValue(run->fp, run->binary, newval);
|
||||||
valueold[i] = valuenew[i];
|
valueold[i] = valuenew[i];
|
||||||
|
timeold = refValue->rValue;
|
||||||
}
|
}
|
||||||
else if (nodata)
|
else if (nodata)
|
||||||
/* Just keep the transient output value corresponding to timeold,
|
/* 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];
|
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||||
fileAddRealValue(run->fp, run->binary, newval);
|
fileAddRealValue(run->fp, run->binary, newval);
|
||||||
valueold[i] = valuenew[i];
|
valueold[i] = valuenew[i];
|
||||||
|
timeold = refValue->rValue;
|
||||||
}
|
}
|
||||||
else if (nodata)
|
else if (nodata)
|
||||||
/* Just keep the transient output value corresponding to timeold,
|
/* 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];
|
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||||
plotAddRealValue(&run->data[i], newval);
|
plotAddRealValue(&run->data[i], newval);
|
||||||
valueold[i] = valuenew[i];
|
valueold[i] = valuenew[i];
|
||||||
|
timeold = refValue->rValue;
|
||||||
}
|
}
|
||||||
else if (nodata)
|
else if (nodata)
|
||||||
/* Just keep the transient output value corresponding to timeold,
|
/* 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];
|
newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
|
||||||
plotAddRealValue(&run->data[i], newval);
|
plotAddRealValue(&run->data[i], newval);
|
||||||
valueold[i] = valuenew[i];
|
valueold[i] = valuenew[i];
|
||||||
|
timeold = refValue->rValue;
|
||||||
}
|
}
|
||||||
else if (nodata)
|
else if (nodata)
|
||||||
/* Just keep the transient output value corresponding to timeold,
|
/* Just keep the transient output value corresponding to timeold,
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ Modified: 2000 AlansFixes
|
||||||
#include "ngspice/fteinp.h"
|
#include "ngspice/fteinp.h"
|
||||||
#include "ngspice/stringskip.h"
|
#include "ngspice/stringskip.h"
|
||||||
#include "ngspice/compatmode.h"
|
#include "ngspice/compatmode.h"
|
||||||
|
#include "ngspice/hash.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
@ -95,14 +96,17 @@ static int translate(struct card *deck, char *formal, int flen, char *actual,
|
||||||
struct bxx_buffer;
|
struct bxx_buffer;
|
||||||
static void finishLine(struct bxx_buffer *dst, char *src, char *scname);
|
static void finishLine(struct bxx_buffer *dst, char *src, char *scname);
|
||||||
static int settrans(char *formal, int flen, char *actual, const char *subname);
|
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 numnodes(const char *line, struct subs *subs, wordlist const *modnames);
|
||||||
static int numdevs(char *s);
|
static int numdevs(char *s);
|
||||||
static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames);
|
static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames);
|
||||||
static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames);
|
static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames);
|
||||||
static int inp_numnodes(char c);
|
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
|
* 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 start[32], sbend[32], invoke[32], model[32];
|
||||||
|
|
||||||
static char *global_nodes[N_GLOBAL_NODES];
|
|
||||||
static int num_global_nodes;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
collect_global_nodes(struct card *c)
|
collect_global_nodes(struct card *c)
|
||||||
{
|
{
|
||||||
num_global_nodes = 0;
|
/* hash table for global nodes */
|
||||||
|
glonodes = nghash_init(NGHASH_MIN_SIZE);
|
||||||
global_nodes[num_global_nodes++] = copy("0");
|
|
||||||
|
|
||||||
|
/* add 0 and null as global nodes */
|
||||||
|
nghash_insert(glonodes, "0", DUMMYDATA);
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
global_nodes[num_global_nodes++] = copy("null");
|
nghash_insert(glonodes, "null", DUMMYDATA);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (; c; c = c->nextcard)
|
for (; c; c = c->nextcard)
|
||||||
|
|
@ -157,17 +158,20 @@ collect_global_nodes(struct card *c)
|
||||||
char *s = c->line;
|
char *s = c->line;
|
||||||
s = nexttok(s);
|
s = nexttok(s);
|
||||||
while (*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);
|
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);
|
s = skip_ws(t);
|
||||||
}
|
}
|
||||||
c->line[0] = '*'; /* comment it out */
|
c->line[0] = '*'; /* comment it out */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -184,10 +188,7 @@ collect_global_nodes(struct card *c)
|
||||||
static void
|
static void
|
||||||
free_global_nodes(void)
|
free_global_nodes(void)
|
||||||
{
|
{
|
||||||
int i;
|
nghash_free(glonodes, NULL, NULL);
|
||||||
for (i = 0; i < num_global_nodes; i++)
|
|
||||||
tfree(global_nodes[i]);
|
|
||||||
num_global_nodes = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1107,14 +1108,19 @@ bxx_buffer(struct bxx_buffer *t)
|
||||||
static void
|
static void
|
||||||
translate_node_name(struct bxx_buffer *buffer, const char *scname, const char *name, const char *name_e)
|
translate_node_name(struct bxx_buffer *buffer, const char *scname, const char *name, const char *name_e)
|
||||||
{
|
{
|
||||||
|
|
||||||
const char *t;
|
const char *t;
|
||||||
|
bool isglobal;
|
||||||
|
|
||||||
if (!name_e)
|
if (!name_e)
|
||||||
name_e = strchr(name, '\0');
|
name_e = strchr(name, '\0');
|
||||||
|
|
||||||
t = gettrans(name, name_e);
|
t = gettrans(name, name_e, &isglobal);
|
||||||
|
|
||||||
if (t) {
|
if (t) {
|
||||||
bxx_put_cstring(buffer, 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 {
|
} else {
|
||||||
bxx_put_cstring(buffer, scname);
|
bxx_put_cstring(buffer, scname);
|
||||||
bxx_putc(buffer, '.');
|
bxx_putc(buffer, '.');
|
||||||
|
|
@ -1624,21 +1630,28 @@ eq_substr(const char *str, const char *end, const char *cstring)
|
||||||
* otherwise it returns NULL.
|
* otherwise it returns NULL.
|
||||||
*------------------------------------------------------------------------------*/
|
*------------------------------------------------------------------------------*/
|
||||||
static char *
|
static char *
|
||||||
gettrans(const char *name, const char *name_end)
|
gettrans(const char *name, const char *name_end, bool *isglobal)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
*isglobal = FALSE;
|
||||||
|
|
||||||
if (!name_end)
|
if (!name_end)
|
||||||
name_end = strchr(name, '\0');
|
name_end = strchr(name, '\0');
|
||||||
|
|
||||||
/* Added by H.Tanaka to translate global nodes */
|
/* Added by H.Tanaka to translate global nodes */
|
||||||
for (i = 0; i<num_global_nodes; i++)
|
char* newgl = copy_substring(name, name_end);
|
||||||
if (eq_substr(name, name_end, global_nodes[i]))
|
if (nghash_find(glonodes, newgl)) {
|
||||||
return (global_nodes[i]);
|
*isglobal = TRUE;
|
||||||
|
return newgl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tfree(newgl);
|
||||||
|
|
||||||
for (i = 0; table[i].t_old; i++)
|
for (i = 0; table[i].t_old; i++)
|
||||||
if (eq_substr(name, name_end, table[i].t_old))
|
if (eq_substr(name, name_end, table[i].t_old)) {
|
||||||
return (table[i].t_new);
|
*isglobal = FALSE;
|
||||||
|
return table[i].t_new;
|
||||||
|
}
|
||||||
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
@ -1682,6 +1695,9 @@ numnodes(const char *line, struct subs *subs, wordlist const *modnames)
|
||||||
return (nodes);
|
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);
|
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
|
* variable *, which allows the host program to provide values for
|
||||||
* non-cshpar variables. */
|
* non-cshpar variables. */
|
||||||
|
|
||||||
char cp_dol = '$';
|
|
||||||
|
|
||||||
/* Non-alphanumeric characters that may appear in variable names. < is very
|
/* Non-alphanumeric characters that may appear in variable names. < is very
|
||||||
* special...
|
* special...
|
||||||
*/
|
*/
|
||||||
|
|
@ -808,10 +806,11 @@ char cp_dol = '$';
|
||||||
* Return value
|
* Return value
|
||||||
* Address of the first character after the variable name.
|
* Address of the first character after the variable name.
|
||||||
*/
|
*/
|
||||||
char *span_var_expr(char *t)
|
char *span_var_expr(char *s)
|
||||||
{
|
{
|
||||||
int parenthesis = 0;
|
char *t = s;
|
||||||
int brackets = 0;
|
int parenthesis = 0;
|
||||||
|
int brackets = 0;
|
||||||
|
|
||||||
while (*t && (isalnum_c(*t) || strchr(VALIDCHARS, *t)))
|
while (*t && (isalnum_c(*t) || strchr(VALIDCHARS, *t)))
|
||||||
switch (*t++)
|
switch (*t++)
|
||||||
|
|
@ -834,6 +833,14 @@ char *span_var_expr(char *t)
|
||||||
if (--parenthesis <= 0)
|
if (--parenthesis <= 0)
|
||||||
return t;
|
return t;
|
||||||
break;
|
break;
|
||||||
|
case '$':
|
||||||
|
if (brackets <= 0 && parenthesis <= 0) {
|
||||||
|
if (t == s + 1) // Special case: "$$".
|
||||||
|
return t;
|
||||||
|
else
|
||||||
|
return t-1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -852,7 +859,7 @@ wordlist *cp_variablesubst(wordlist *wlist)
|
||||||
char *s_dollar;
|
char *s_dollar;
|
||||||
int i = 0;
|
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);
|
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))
|
if (eq(v->va_name, string))
|
||||||
break;
|
break;
|
||||||
if (!v && isdigit_c(*string)) {
|
if (!v && isdigit_c(*string)) {
|
||||||
|
/* Treat $i for some integer i as argv[i] - positional parameters. */
|
||||||
|
|
||||||
for (v = variables; v; v = v->va_next) {
|
for (v = variables; v; v = v->va_next) {
|
||||||
if (eq(v->va_name, "argv")) {
|
if (eq(v->va_name, "argv")) {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ NON-STANDARD FEATURES
|
||||||
|
|
||||||
#define ANALOG MIF_ANALOG
|
#define ANALOG MIF_ANALOG
|
||||||
#define EVENT MIF_EVENT_DRIVEN
|
#define EVENT MIF_EVENT_DRIVEN
|
||||||
|
#define STEP_PENDING MIF_STEP_PENDING
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ int cm_message_printf(const char *fmt, ...);
|
||||||
double cm_netlist_get_c(void);
|
double cm_netlist_get_c(void);
|
||||||
double cm_netlist_get_l(void);
|
double cm_netlist_get_l(void);
|
||||||
|
|
||||||
|
void cm_irreversible(unsigned int);
|
||||||
const char *cm_get_node_name(const char *, unsigned int);
|
const char *cm_get_node_name(const char *, unsigned int);
|
||||||
bool cm_probe_node(unsigned int, unsigned int, void *);
|
bool cm_probe_node(unsigned int, unsigned int, void *);
|
||||||
bool cm_schedule_output(unsigned int, unsigned int, double, 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_noclobber;
|
||||||
extern bool cp_noglob;
|
extern bool cp_noglob;
|
||||||
extern bool cp_nonomatch;
|
extern bool cp_nonomatch;
|
||||||
extern char cp_dol;
|
|
||||||
extern void cp_remvar(char *varname);
|
extern void cp_remvar(char *varname);
|
||||||
void cp_vset(const char *varname, enum cp_types type, const void *value);
|
void cp_vset(const char *varname, enum cp_types type, const void *value);
|
||||||
extern struct variable *cp_setparse(wordlist *wl);
|
extern struct variable *cp_setparse(wordlist *wl);
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ struct coreInfo_t {
|
||||||
int ((*dllitf_cm_message_send)(char *));
|
int ((*dllitf_cm_message_send)(char *));
|
||||||
double ((*dllitf_cm_netlist_get_c)(void));
|
double ((*dllitf_cm_netlist_get_c)(void));
|
||||||
double ((*dllitf_cm_netlist_get_l)(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));
|
const char * ((*dllitf_cm_get_node_name)(const char *, unsigned int));
|
||||||
bool ((*dllitf_cm_probe_node)(unsigned int, unsigned int,
|
bool ((*dllitf_cm_probe_node)(unsigned int, unsigned int,
|
||||||
void *));
|
void *));
|
||||||
|
|
|
||||||
|
|
@ -91,35 +91,27 @@ struct Evt_Node_Info {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Evt_Inst_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 */
|
MIFinstance *inst_ptr; /* Pointer to MIFinstance struct for this instance */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Evt_Info {
|
struct Evt_Info {
|
||||||
Evt_Inst_Info_t *inst_list; /* static info about event/hybrid instances */
|
Evt_Inst_Info_t *inst_list; /* static info about event instances */
|
||||||
Evt_Node_Info_t *node_list; /* static info about event nodes */
|
Evt_Node_Info_t *node_list; /* static info about event nodes */
|
||||||
Evt_Port_Info_t *port_list; /* static info about event ports */
|
Evt_Port_Info_t *port_list; /* static info about event ports */
|
||||||
Evt_Output_Info_t *output_list; /* static info about event outputs */
|
Evt_Output_Info_t *output_list; /* static info about event outputs */
|
||||||
int *hybrid_index; /* vector of inst indexs for hybrids */
|
MIFinstance **hybrids; /* vector of inst pointers for hybrids */
|
||||||
Evt_Inst_Info_t **inst_table; /* vector of pointers to elements in inst_list */
|
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_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_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_Output_Info_t **output_table; /* vector of pointers to elements in output_list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *************** */
|
/* *************** */
|
||||||
/* Queue structure */
|
/* Queue structure */
|
||||||
/* *************** */
|
/* *************** */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct Evt_Inst_Event {
|
struct Evt_Inst_Event {
|
||||||
Evt_Inst_Event_t *next; /* the next in the linked list */
|
Evt_Inst_Event_t *next; /* the next in the linked list */
|
||||||
double event_time; /* Time for this event to happen */
|
double event_time; /* Time for this event to happen */
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,9 @@ void EVTqueue_inst(
|
||||||
|
|
||||||
void EVTdequeue(CKTcircuit *ckt, double time);
|
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 EVTprint(wordlist *wl);
|
||||||
void EVTprintvcd(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_ngdebug;
|
||||||
extern bool ft_nginfo;
|
extern bool ft_nginfo;
|
||||||
extern bool ft_stricterror;
|
extern bool ft_stricterror;
|
||||||
|
extern bool ft_skywaterpdk;
|
||||||
|
|
||||||
/* parse.c */
|
/* parse.c */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ struct MIFinstance {
|
||||||
|
|
||||||
Mif_Boolean_t analog; /* true if this inst is analog or hybrid type */
|
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 */
|
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 */
|
int inst_index; /* Index into inst_table in evt struct in ckt */
|
||||||
Mif_Callback_t callback; /* instance callback function */
|
Mif_Callback_t callback; /* instance callback function */
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ typedef enum {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MIF_ANALOG, /* Analog call */
|
MIF_ANALOG, /* Analog call */
|
||||||
MIF_EVENT_DRIVEN, /* Event-driven call */
|
MIF_EVENT_DRIVEN, /* Event-driven call */
|
||||||
|
MIF_STEP_PENDING, /* Special event call for irreversible Code Models */
|
||||||
} Mif_Call_Type_t;
|
} Mif_Call_Type_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ enum {
|
||||||
|
|
||||||
#ifdef KLU
|
#ifdef KLU
|
||||||
OPT_SPARSE,
|
OPT_SPARSE,
|
||||||
|
OPT_KLU,
|
||||||
OPT_KLU_MEMGROW_FACTOR,
|
OPT_KLU_MEMGROW_FACTOR,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ typedef struct linked_lists_of_Bpoint{
|
||||||
} BPOINT, *BPOINTPTR;
|
} BPOINT, *BPOINTPTR;
|
||||||
|
|
||||||
typedef struct linked_lists_of_nodeName{
|
typedef struct linked_lists_of_nodeName{
|
||||||
char id[24];
|
char id[256];
|
||||||
struct linked_lists_of_nodeName *left, *right;
|
struct linked_lists_of_nodeName *left, *right;
|
||||||
NODE *nd;
|
NODE *nd;
|
||||||
} NDname, *NDnamePt;
|
} 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 */
|
/* end cider globals */
|
||||||
#endif /* CIDER */
|
#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);
|
struct variable *(*if_getparam)(CKTcircuit *ckt, char **name, char *param, int ind, int do_model);
|
||||||
|
|
||||||
/* static functions */
|
/* static functions */
|
||||||
|
|
@ -1382,13 +1384,16 @@ int main(int argc, char **argv)
|
||||||
while (optind < argc) {
|
while (optind < argc) {
|
||||||
char *arg = argv[optind++];
|
char *arg = argv[optind++];
|
||||||
FILE *tp;
|
FILE *tp;
|
||||||
|
|
||||||
/* Copy the the path of the first filename only */
|
/* Copy the the path of the first filename only */
|
||||||
if (!Infile_Path) {
|
if (!Infile_Path) {
|
||||||
Infile_Path = ngdirname(arg);
|
Infile_Path = ngdirname(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unquote the input string, needed if it results from double clicking the filename */
|
|
||||||
#if defined(HAS_WINGUI)
|
#if defined(HAS_WINGUI)
|
||||||
|
/* Unquote the input string, needed if it results
|
||||||
|
* from double clicking the filename.
|
||||||
|
*/
|
||||||
arg = cp_unquote(arg);
|
arg = cp_unquote(arg);
|
||||||
#endif
|
#endif
|
||||||
/* Copy all the arguments into the temporary file */
|
/* Copy all the arguments into the temporary file */
|
||||||
|
|
@ -1401,15 +1406,22 @@ int main(int argc, char **argv)
|
||||||
tp = fopen(p, "r");
|
tp = fopen(p, "r");
|
||||||
tfree(p);
|
tfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tp) {
|
if (!tp) {
|
||||||
perror(arg);
|
/* Try and find it in a directory in $sourcepath. */
|
||||||
err = 1;
|
|
||||||
break;
|
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
|
/* Copy the input file name which otherwise will be lost
|
||||||
temporary file */
|
* due to the temporary file.
|
||||||
|
*/
|
||||||
dname = copy(arg);
|
dname = copy(arg);
|
||||||
#if defined(HAS_WINGUI)
|
#if defined(HAS_WINGUI)
|
||||||
/* write source file name into source window */
|
/* write source file name into source window */
|
||||||
|
|
@ -1418,11 +1430,32 @@ int main(int argc, char **argv)
|
||||||
tfree(arg);
|
tfree(arg);
|
||||||
#endif
|
#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);
|
append_to_stream(tempfile, tp);
|
||||||
fclose(tp);
|
fclose(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(tempfile, 0L, SEEK_SET);
|
fseek(tempfile, 0L, SEEK_SET);
|
||||||
|
gotone = FALSE; // Re-use
|
||||||
|
|
||||||
if (tempfile && (!err || !ft_batchmode)) {
|
if (tempfile && (!err || !ft_batchmode)) {
|
||||||
/* Copy the input file name for becoming another file search path */
|
/* Copy the input file name for becoming another file search path */
|
||||||
|
|
@ -1450,7 +1483,6 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ft_batchmode) {
|
if (ft_batchmode) {
|
||||||
|
|
||||||
int error3 = 1;
|
int error3 = 1;
|
||||||
|
|
||||||
/* If we get back here in batch mode then something is wrong,
|
/* 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_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_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_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_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_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);
|
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 old;
|
||||||
double new;
|
double new;
|
||||||
double tol;
|
double tol;
|
||||||
|
static int nancount = 0;
|
||||||
|
|
||||||
node = ckt->CKTnodes;
|
node = ckt->CKTnodes;
|
||||||
size = SMPmatSize(ckt->CKTmatrix);
|
size = SMPmatSize(ckt->CKTmatrix);
|
||||||
|
|
@ -41,8 +42,14 @@ NIconvTest(CKTcircuit *ckt)
|
||||||
new = ckt->CKTrhs [i] ;
|
new = ckt->CKTrhs [i] ;
|
||||||
old = ckt->CKTrhsOld [i] ;
|
old = ckt->CKTrhsOld [i] ;
|
||||||
if (isnan(new)) {
|
if (isnan(new)) {
|
||||||
if (ft_ngdebug)
|
if (ft_ngdebug && nancount < 10) {
|
||||||
fprintf(stderr, "Warning: non-convergence, node %s is nan\n", CKTnodName(ckt, i));
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
if(node->type == SP_VOLTAGE) {
|
if(node->type == SP_VOLTAGE) {
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,14 @@ NIiter(CKTcircuit *ckt, int maxIter)
|
||||||
ckt->CKTstat->STATreorderTime += SPfrontEnd->IFseconds() - startTime;
|
ckt->CKTstat->STATreorderTime += SPfrontEnd->IFseconds() - startTime;
|
||||||
if (error) {
|
if (error) {
|
||||||
SMPgetError(ckt->CKTmatrix, &i, &j);
|
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); */
|
/* CKTload(ckt); */
|
||||||
/* SMPprint(ckt->CKTmatrix, stdout); */
|
/* SMPprint(ckt->CKTmatrix, stdout); */
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include "polyeval.h"
|
#include "polyeval.h"
|
||||||
#include "polyfit.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
|
* 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,
|
* interpolated from, and sign is 1 if the old scale was increasing,
|
||||||
* and -1 if it was decreasing. */
|
* 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,
|
/* 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
|
* 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
|
* 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
|
bool
|
||||||
ft_interpolate(double *data, double *ndata, double *oscale, int olen,
|
ft_interpolate(double *data, double *ndata, double *oscale, int olen,
|
||||||
double *nscale, int nlen, int degree)
|
double *nscale, int nlen, int degree)
|
||||||
{
|
{
|
||||||
double *result, *scratch, *xdata, *ydata;
|
double *result, *scratch, *xdata, *ydata, diff;
|
||||||
int sign, lastone, i, l;
|
int sign, lastone, i, l, middle, tdegree;
|
||||||
|
|
||||||
if ((olen < 2) || (nlen < 2)) {
|
if ((olen < 2) || (nlen < 2)) {
|
||||||
fprintf(cp_err, "Error: lengths too small to interpolate.\n");
|
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);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oscale[1] < oscale[0])
|
for (i = 0; i < olen - 1; ++i) {
|
||||||
sign = -1;
|
if (oscale[i + 1] < oscale[i]) {
|
||||||
else
|
sign = -1;
|
||||||
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));
|
scratch = TMALLOC(double, (degree + 1) * (degree + 2));
|
||||||
result = TMALLOC(double, degree + 1);
|
result = TMALLOC(double, degree + 1);
|
||||||
xdata = TMALLOC(double, degree + 1);
|
xdata = TMALLOC(double, degree + 1);
|
||||||
ydata = TMALLOC(double, degree + 1);
|
ydata = TMALLOC(double, degree + 1);
|
||||||
|
|
||||||
/* Deal with the first degree pieces. */
|
/* Initial load of the values to be analysed by ft_polyfit(),
|
||||||
memcpy(ydata, data, (size_t) (degree + 1) * sizeof (double));
|
* skipping irrelevant points and checking for and fudging vertical edges.
|
||||||
memcpy(xdata, oscale, (size_t) (degree + 1) * sizeof (double));
|
*/
|
||||||
|
|
||||||
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
|
/* If it doesn't work this time, bump the interpolation
|
||||||
* degree down by one.
|
* degree down by one.
|
||||||
*/
|
*/
|
||||||
|
if (--tdegree == 0) {
|
||||||
if (--degree == 0) {
|
|
||||||
fprintf(cp_err, "ft_interpolate: Internal Error.\n");
|
fprintf(cp_err, "ft_interpolate: Internal Error.\n");
|
||||||
return (FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
|
if (tdegree % 2)
|
||||||
|
++i; // Drop left point.
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add this part of the curve. What we do is evaluate the polynomial
|
/* 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
|
* if the scale is decreasing at the end of the interval we are looking
|
||||||
* at.
|
* at.
|
||||||
*/
|
*/
|
||||||
lastone = -1;
|
|
||||||
for (i = 0; i < degree; i++) {
|
lastone = putinterval(result, tdegree, ndata, -1,
|
||||||
lastone = putinterval(result, degree, ndata, lastone,
|
nscale, nlen, xdata[middle], sign);
|
||||||
nscale, nlen, xdata[i], sign);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now plot the rest, piece by piece. l is the
|
/* Now plot the rest, piece by piece. l is the
|
||||||
* last element under consideration.
|
* 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. */
|
/* Shift the old stuff by one and get another value. */
|
||||||
|
|
||||||
|
out = xdata[0];
|
||||||
for (i = 0; i < degree; i++) {
|
for (i = 0; i < degree; i++) {
|
||||||
xdata[i] = xdata[i + 1];
|
xdata[i] = xdata[i + 1];
|
||||||
ydata[i] = ydata[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];
|
ydata[i] = data[l];
|
||||||
xdata[i] = oscale[l];
|
xdata[i] = oscale[l];
|
||||||
|
|
||||||
while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {
|
/* Check for vertical edge. */
|
||||||
if (--degree == 0) {
|
|
||||||
fprintf(cp_err,
|
if (oscale[l] == xdata[i - 1]) {
|
||||||
"interpolate: Internal Error.\n");
|
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);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
|
if (!((degree - tdegree) & 1))
|
||||||
|
++i; // Drop left point after right.
|
||||||
}
|
}
|
||||||
lastone = putinterval(result, degree, ndata, lastone,
|
lastone = putinterval(result, tdegree, ndata, lastone,
|
||||||
nscale, nlen, xdata[i], sign);
|
nscale, nlen, xdata[middle], sign);
|
||||||
}
|
}
|
||||||
|
lastone = putinterval(result, degree, ndata, lastone,
|
||||||
|
nscale, nlen, oscale[olen - 1], sign);
|
||||||
if (lastone < nlen - 1) /* ??? */
|
if (lastone < nlen - 1) /* ??? */
|
||||||
ndata[nlen - 1] = data[olen - 1];
|
ndata[nlen - 1] = data[olen - 1];
|
||||||
tfree(scratch);
|
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
|
* 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.
|
* 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
|
* 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)) {
|
if (nghash_insert(known_object_files, handle, DUMMYDATA)) {
|
||||||
txfree(path);
|
txfree(path);
|
||||||
return EMPTY_OBJECT;
|
return EMPTY_OBJECT;
|
||||||
|
|
|
||||||
|
|
@ -396,6 +396,7 @@ unsigned int main_id, ng_id, command_id;
|
||||||
mutexType triggerMutex;
|
mutexType triggerMutex;
|
||||||
mutexType allocMutex;
|
mutexType allocMutex;
|
||||||
mutexType fputsMutex;
|
mutexType fputsMutex;
|
||||||
|
mutexType vecreallocMutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* initialization status */
|
/* initialization status */
|
||||||
|
|
@ -774,6 +775,8 @@ read_initialisation_file(const char *dir, const char *name)
|
||||||
/* The functions exported explicitely from shared ngspice */
|
/* The functions exported explicitely from shared ngspice */
|
||||||
/**********************************************************/
|
/**********************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef THREADS
|
#ifdef THREADS
|
||||||
|
|
||||||
/* Checks if ngspice is running in the background */
|
/* 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(&triggerMutex, NULL);
|
||||||
pthread_mutex_init(&allocMutex, NULL);
|
pthread_mutex_init(&allocMutex, NULL);
|
||||||
pthread_mutex_init(&fputsMutex, NULL);
|
pthread_mutex_init(&fputsMutex, NULL);
|
||||||
|
pthread_mutex_init(&vecreallocMutex, NULL);
|
||||||
cont_condition = FALSE;
|
cont_condition = FALSE;
|
||||||
#else
|
#else
|
||||||
#ifdef SRW
|
#ifdef SRW
|
||||||
InitializeSRWLock(&triggerMutex);
|
InitializeSRWLock(&triggerMutex);
|
||||||
InitializeSRWLock(&allocMutex);
|
InitializeSRWLock(&allocMutex);
|
||||||
InitializeSRWLock(&fputsMutex);
|
InitializeSRWLock(&fputsMutex);
|
||||||
|
InitializeSRWLock(&vecreallocMutex);
|
||||||
#else
|
#else
|
||||||
InitializeCriticalSection(&triggerMutex);
|
InitializeCriticalSection(&triggerMutex);
|
||||||
InitializeCriticalSection(&allocMutex);
|
InitializeCriticalSection(&allocMutex);
|
||||||
InitializeCriticalSection(&fputsMutex);
|
InitializeCriticalSection(&fputsMutex);
|
||||||
|
InitializeCriticalSection(&vecreallocMutex);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
// Id of primary thread
|
// Id of primary thread
|
||||||
|
|
@ -1336,6 +1342,20 @@ char** ngSpice_AllEvtNodes(void)
|
||||||
}
|
}
|
||||||
#endif
|
#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.
|
/* add the preliminary breakpoints to the list.
|
||||||
called from dctran.c */
|
called from dctran.c */
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,18 @@ CKTacct(CKTcircuit *ckt, JOB *anal, int which, IFvalue *val)
|
||||||
case OPT_FILLNZ:
|
case OPT_FILLNZ:
|
||||||
if ( ckt->CKTmatrix != NULL ) {
|
if ( ckt->CKTmatrix != NULL ) {
|
||||||
#ifdef KLU
|
#ifdef KLU
|
||||||
if (ckt->CKTmatrix->CKTkluMODE)
|
if (ckt->CKTmatrix->CKTkluMODE) {
|
||||||
val->iValue = ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz + ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz
|
if (!ckt->CKTmatrix->SMPkluMatrix ||
|
||||||
- (int)ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNZ ;
|
!ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric) {
|
||||||
else
|
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);
|
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
|
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -72,10 +79,14 @@ CKTacct(CKTcircuit *ckt, JOB *anal, int which, IFvalue *val)
|
||||||
case OPT_TOTALNZ:
|
case OPT_TOTALNZ:
|
||||||
if ( ckt->CKTmatrix != NULL ) {
|
if ( ckt->CKTmatrix != NULL ) {
|
||||||
#ifdef KLU
|
#ifdef KLU
|
||||||
if (ckt->CKTmatrix->CKTkluMODE)
|
if (ckt->CKTmatrix->CKTkluMODE && ckt->CKTmatrix->SMPkluMatrix &&
|
||||||
val->iValue = ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz + ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz ;
|
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric) {
|
||||||
else
|
val->iValue =
|
||||||
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
|
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->lnz +
|
||||||
|
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixNumeric->unz ;
|
||||||
|
} else {
|
||||||
|
val->iValue = 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
|
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ CKTnewTask(CKTcircuit *ckt, TSKtask **taskPtr, IFuid taskName, TSKtask **defPtr)
|
||||||
tsk->TSKepsmin = 1e-28;
|
tsk->TSKepsmin = 1e-28;
|
||||||
|
|
||||||
#ifdef KLU
|
#ifdef KLU
|
||||||
tsk->TSKkluMODE = CKTkluON;
|
tsk->TSKkluMODE = CKTkluOFF;
|
||||||
tsk->TSKkluMemGrowFactor = 1.2 ;
|
tsk->TSKkluMemGrowFactor = 1.2 ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,9 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val)
|
||||||
case OPT_SPARSE:
|
case OPT_SPARSE:
|
||||||
task->TSKkluMODE = (val->iValue == 0);
|
task->TSKkluMODE = (val->iValue == 0);
|
||||||
break;
|
break;
|
||||||
|
case OPT_KLU:
|
||||||
|
task->TSKkluMODE = (val->iValue != 0);
|
||||||
|
break;
|
||||||
case OPT_KLU_MEMGROW_FACTOR:
|
case OPT_KLU_MEMGROW_FACTOR:
|
||||||
task->TSKkluMemGrowFactor = (val->rValue == 1.2);
|
task->TSKkluMemGrowFactor = (val->rValue == 1.2);
|
||||||
break;
|
break;
|
||||||
|
|
@ -348,6 +350,8 @@ static IFparm OPTtbl[] = {
|
||||||
#ifdef KLU
|
#ifdef KLU
|
||||||
{ "sparse", OPT_SPARSE, IF_SET|IF_FLAG,
|
{ "sparse", OPT_SPARSE, IF_SET|IF_FLAG,
|
||||||
"Set SPARSE 1.3 as Direct Linear Solver" },
|
"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_memgrow_factor", OPT_KLU_MEMGROW_FACTOR, IF_SET|IF_REAL,
|
||||||
"KLU Memory Grow Factor (default is 1.2)" }
|
"KLU Memory Grow Factor (default is 1.2)" }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -787,14 +787,6 @@ resume:
|
||||||
|
|
||||||
converged = NIiter(ckt,ckt->CKTtranMaxIter);
|
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->CKTstat->STATtimePts ++;
|
||||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITPRED;
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITPRED;
|
||||||
if(firsttime) {
|
if(firsttime) {
|
||||||
|
|
@ -830,8 +822,10 @@ resume:
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||||
|
|
||||||
/* Force backup if temporary breakpoint is < current time */
|
|
||||||
} else if(g_mif_info.breakpoint.current < ckt->CKTtime) {
|
} else if(g_mif_info.breakpoint.current < ckt->CKTtime) {
|
||||||
|
/* Force backup if temporary breakpoint is < current time */
|
||||||
|
|
||||||
|
past_breakpoint:
|
||||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||||
ckt->CKTtime -= ckt->CKTdelta;
|
ckt->CKTtime -= ckt->CKTdelta;
|
||||||
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
||||||
|
|
@ -879,6 +873,27 @@ resume:
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
if (newdelta > .9 * ckt->CKTdelta) {
|
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 */
|
if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */
|
||||||
newdelta = ckt->CKTdelta;
|
newdelta = ckt->CKTdelta;
|
||||||
ckt->CKTorder = 2;
|
ckt->CKTorder = 2;
|
||||||
|
|
@ -893,6 +908,7 @@ resume:
|
||||||
}
|
}
|
||||||
/* time point OK - 630 */
|
/* time point OK - 630 */
|
||||||
ckt->CKTdelta = newdelta;
|
ckt->CKTdelta = newdelta;
|
||||||
|
|
||||||
#ifdef NDEV
|
#ifdef NDEV
|
||||||
if (!ft_norefprint) {
|
if (!ft_norefprint) {
|
||||||
/* show a time process indicator, by Gong Ding, gdiso@ustc.edu */
|
/* 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) {
|
void mem_delete(void) {
|
||||||
#ifdef DB
|
#ifdef DB
|
||||||
char buf[128];
|
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 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));
|
printf("CPL GC size of hash table to be freed: %d entries.\n", nghash_get_size(memory_table));
|
||||||
#ifdef DB_FULL
|
#ifdef DB_FULL
|
||||||
|
|
@ -142,6 +144,7 @@ void mem_delete(void) {
|
||||||
#endif
|
#endif
|
||||||
gc_is_on = 0;
|
gc_is_on = 0;
|
||||||
nghash_free(memory_table, NULL, my_key_free);
|
nghash_free(memory_table, NULL, my_key_free);
|
||||||
|
memory_table = NULL;
|
||||||
#ifdef DB
|
#ifdef DB
|
||||||
/* printf via sh_printf will need some info from variables that have
|
/* printf via sh_printf will need some info from variables that have
|
||||||
been deleted already, therefore we use fputs */
|
been deleted already, therefore we use fputs */
|
||||||
|
|
|
||||||
|
|
@ -1934,7 +1934,8 @@ insert_ND(char* name, NDnamePt* ndn)
|
||||||
memsaved(p);
|
memsaved(p);
|
||||||
p->nd = NULL;
|
p->nd = NULL;
|
||||||
p->right = p->left = NULL;
|
p->right = p->left = NULL;
|
||||||
strcpy(p->id, name);
|
strncpy(p->id, name, 255);
|
||||||
|
p->id[255] = '\0';
|
||||||
return(p);
|
return(p);
|
||||||
}
|
}
|
||||||
cmp = strcmp((*ndn)->id, name);
|
cmp = strcmp((*ndn)->id, name);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||||
#include "ngspice/sperror.h"
|
#include "ngspice/sperror.h"
|
||||||
#include "ngspice/suffix.h"
|
#include "ngspice/suffix.h"
|
||||||
#include "ngspice/fteext.h"
|
#include "ngspice/fteext.h"
|
||||||
|
#include "ngspice/compatmode.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
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)) {
|
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 {
|
} else {
|
||||||
model->DIOconductance = 1/model->DIOresist;
|
model->DIOconductance = 1/model->DIOresist;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1035,7 +1035,8 @@ insert_ND(char *name, NDnamePt *ndn)
|
||||||
p = *ndn = TMALLOC(NDname, 1);
|
p = *ndn = TMALLOC(NDname, 1);
|
||||||
p->nd = NULL;
|
p->nd = NULL;
|
||||||
p->right = p->left = NULL;
|
p->right = p->left = NULL;
|
||||||
strcpy(p->id, name);
|
strncpy(p->id, name, 255);
|
||||||
|
p->id[255] = '\0';
|
||||||
return(p);
|
return(p);
|
||||||
}
|
}
|
||||||
cmp = strcmp((*ndn)->id, name);
|
cmp = strcmp((*ndn)->id, name);
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,16 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
||||||
else
|
else
|
||||||
Check_th = 0;
|
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
|
/* first, we compute a few useful values - these could be
|
||||||
* pre-computed, but for historical reasons are still done
|
* pre-computed, but for historical reasons are still done
|
||||||
* here. They may be moved at the expense of instance size
|
* 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
|
static int
|
||||||
MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
||||||
{
|
{
|
||||||
char *pC1; /* a temporary character pointer */
|
|
||||||
char *pWorkString = NULL; /* a working copy of cmdline */
|
char *pWorkString = NULL; /* a working copy of cmdline */
|
||||||
int i; /* a loop counter */
|
int i; /* a loop counter */
|
||||||
int quoteflag = 0; /* for the finite state machine parsing cmdline */
|
int quoteflag = 0; /* for the finite state machine parsing cmdline */
|
||||||
|
|
@ -899,13 +898,13 @@ MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
||||||
#endif
|
#endif
|
||||||
/* If we still have a string left, parse it for all
|
/* If we still have a string left, parse it for all
|
||||||
the arguments. */
|
the arguments. */
|
||||||
if (strlen(pWorkString))
|
if (pWorkString[0])
|
||||||
{
|
{
|
||||||
/* This could probably be done with strtok as well
|
/* This could probably be done with strtok as well
|
||||||
but strtok is destructive if I wanted to look for " \""
|
but strtok is destructive if I wanted to look for " \""
|
||||||
and I couldn't tell what delimiter that I had bumped
|
and I couldn't tell what delimiter that I had bumped
|
||||||
against */
|
against */
|
||||||
for (i = 0; i < (signed)strlen(pWorkString); i++)
|
for (i = 0; pWorkString[i]; i++)
|
||||||
switch (pWorkString[i])
|
switch (pWorkString[i])
|
||||||
{
|
{
|
||||||
case SPACE:
|
case SPACE:
|
||||||
|
|
@ -935,7 +934,7 @@ MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* malloc an argv */
|
/* malloc an argv */
|
||||||
tmpargv = (char**) malloc((unsigned)numargs * sizeof(char *));
|
tmpargv = (char**) malloc((unsigned)(numargs + 1) * sizeof(char *));
|
||||||
if (NULL == tmpargv)
|
if (NULL == tmpargv)
|
||||||
{
|
{
|
||||||
status = -1;
|
status = -1;
|
||||||
|
|
@ -949,18 +948,15 @@ MakeArgcArgv(char *cmdline, int *argc, char ***argv)
|
||||||
deli[0] = DELIMITER;
|
deli[0] = DELIMITER;
|
||||||
deli[1] = '\0'; /* delimiter for strtok */
|
deli[1] = '\0'; /* delimiter for strtok */
|
||||||
|
|
||||||
pC1 = NULL;
|
|
||||||
/* Now actually strdup all the arguments out of the string
|
/* Now actually strdup all the arguments out of the string
|
||||||
and store them in the argv */
|
and store them in the argv */
|
||||||
for (i = 1; i < numargs; i++) {
|
for (i = 1; i < numargs; i++) {
|
||||||
if (NULL == pC1)
|
|
||||||
pC1 = pWorkString;
|
|
||||||
|
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
tmpargv[i] = copy(strtok(pC1, deli));
|
tmpargv[i] = copy(strtok(pWorkString, deli));
|
||||||
else
|
else
|
||||||
tmpargv[i] = copy(strtok(NULL, deli));
|
tmpargv[i] = copy(strtok(NULL, deli));
|
||||||
}
|
}
|
||||||
|
tmpargv[i] = NULL;
|
||||||
|
|
||||||
/* copy the working values over to the arguments */
|
/* copy the working values over to the arguments */
|
||||||
*argc = numargs;
|
*argc = numargs;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# Process this file with automake
|
# 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
|
## This is removed because icm relies upon the existance of all other
|
||||||
## libs. It is currently compiled manually, last.
|
## 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
|
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:
|
dist-hook:
|
||||||
rm -f "$(distdir)/icm/makedefs"
|
rm -f "$(distdir)/icm/makedefs"
|
||||||
rm -f "$(distdir)/icm/GNUmakefile"
|
rm -f "$(distdir)/icm/GNUmakefile"
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ INTERFACES
|
||||||
cm_get_path()
|
cm_get_path()
|
||||||
cm_get_circuit()
|
cm_get_circuit()
|
||||||
|
|
||||||
|
cm_irreversible()
|
||||||
cm_get_node_name()
|
cm_get_node_name()
|
||||||
cm_probe_node()
|
cm_probe_node()
|
||||||
|
|
||||||
|
|
@ -57,6 +58,7 @@ NON-STANDARD FEATURES
|
||||||
#include "ngspice/enh.h"
|
#include "ngspice/enh.h"
|
||||||
#include "ngspice/mif.h"
|
#include "ngspice/mif.h"
|
||||||
#include "ngspice/cktdefs.h"
|
#include "ngspice/cktdefs.h"
|
||||||
|
#include "ngspice/cpextern.h"
|
||||||
//#include "util.h"
|
//#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -730,6 +732,100 @@ CKTcircuit *cm_get_circuit(void)
|
||||||
return(g_mif_info.ckt);
|
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. */
|
/* Get the name of a circuit node connected to a port. */
|
||||||
|
|
||||||
const char *cm_get_node_name(const char *port_name, unsigned int index)
|
const char *cm_get_node_name(const char *port_name, unsigned int index)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
#include "ngspice/cm.h"
|
#include "ngspice/cm.h"
|
||||||
#include "ngspice/dllitf.h"
|
#include "ngspice/dllitf.h"
|
||||||
|
|
||||||
extern bool cp_getvar(char *, enum cp_types, void *, size_t);
|
|
||||||
|
|
||||||
/*how annoying!, needed for structure below*/
|
/*how annoying!, needed for structure below*/
|
||||||
static void *tcalloc(size_t a, size_t b) {
|
static void *tcalloc(size_t a, size_t b) {
|
||||||
return tmalloc(a*b); /* FIXME, tcalloc must zero !?!? */
|
return tmalloc(a*b); /* FIXME, tcalloc must zero !?!? */
|
||||||
|
|
@ -60,6 +58,7 @@ struct coreInfo_t coreInfo =
|
||||||
cm_message_send,
|
cm_message_send,
|
||||||
cm_netlist_get_c,
|
cm_netlist_get_c,
|
||||||
cm_netlist_get_l,
|
cm_netlist_get_l,
|
||||||
|
cm_irreversible,
|
||||||
cm_get_node_name,
|
cm_get_node_name,
|
||||||
cm_probe_node,
|
cm_probe_node,
|
||||||
cm_schedule_output,
|
cm_schedule_output,
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,6 @@ NON-STANDARD FEATURES
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "ngspice/cm.h"
|
#include "ngspice/cm.h"
|
||||||
|
|
||||||
extern void controlled_exit(const int);
|
|
||||||
|
|
||||||
/* Corner Smoothing Function ************************************
|
/* Corner Smoothing Function ************************************
|
||||||
* *
|
* *
|
||||||
* The following function smooths the transition between two *
|
* The following function smooths the transition between two *
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,12 @@ MODIFICATIONS
|
||||||
SUMMARY
|
SUMMARY
|
||||||
|
|
||||||
This file contains function EVTcall_hybrids which calls all models
|
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
|
successful evaluation of an analog iteration attempt to allow
|
||||||
events to be scheduled by the hybrid models. The 'CALL_TYPE' is set
|
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
|
INTERFACES
|
||||||
|
|
||||||
|
|
@ -60,18 +62,18 @@ void EVTcall_hybrids(
|
||||||
CKTcircuit *ckt) /* the main circuit structure */
|
CKTcircuit *ckt) /* the main circuit structure */
|
||||||
{
|
{
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int num_hybrids;
|
int num_hybrids;
|
||||||
|
MIFinstance **hybrids;
|
||||||
int *hybrid_index;
|
|
||||||
|
|
||||||
|
|
||||||
/* Get needed data for fast access */
|
/* Get needed data for fast access */
|
||||||
|
|
||||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||||
hybrid_index = ckt->evt->info.hybrid_index;
|
hybrids = ckt->evt->info.hybrids;
|
||||||
|
|
||||||
/* Call EVTload for all 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->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_Port_Info_t **port_table = NULL;
|
||||||
Evt_Output_Info_t **output_table = NULL;
|
Evt_Output_Info_t **output_table = NULL;
|
||||||
|
|
||||||
int *hybrid_index = NULL;
|
MIFinstance **hybrids = NULL;
|
||||||
|
|
||||||
int num_hybrids;
|
int num_hybrids;
|
||||||
|
|
||||||
|
|
@ -253,15 +253,14 @@ static int EVTinit_info(
|
||||||
ckt->evt->info.output_table = output_table;
|
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;
|
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++) {
|
for(i = 0, j = 0; i < num_insts; i++) {
|
||||||
if(inst_table[i]->inst_ptr->analog)
|
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 */
|
||||||
return(OK);
|
return(OK);
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ int EVTiter(
|
||||||
for(i = 0; i < num_to_call; i++) {
|
for(i = 0; i < num_to_call; i++) {
|
||||||
inst_index = inst_queue->to_call_index[i];
|
inst_index = inst_queue->to_call_index[i];
|
||||||
inst_queue->to_call[inst_index] = MIF_FALSE;
|
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;
|
inst_queue->num_to_call = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,18 @@ ignored.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int EVTload(
|
int EVTload(
|
||||||
CKTcircuit *ckt, /* The circuit structure */
|
CKTcircuit *ckt, /* The circuit structure */
|
||||||
int inst_index) /* The instance to call code model for */
|
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;
|
int i;
|
||||||
|
|
@ -96,18 +106,16 @@ int EVTload(
|
||||||
Mif_Conn_Data_t *conn;
|
Mif_Conn_Data_t *conn;
|
||||||
Mif_Port_Data_t *port;
|
Mif_Port_Data_t *port;
|
||||||
Evt_Node_Data_t *node_data;
|
Evt_Node_Data_t *node_data;
|
||||||
MIFinstance *inst;
|
|
||||||
|
|
||||||
Mif_Private_t cm_data;
|
Mif_Private_t cm_data;
|
||||||
|
void *value_ptr;
|
||||||
|
|
||||||
/* ***************************** */
|
/* ***************************** */
|
||||||
/* Prepare the code model inputs */
|
/* Prepare the code model inputs */
|
||||||
/* ***************************** */
|
/* ***************************** */
|
||||||
|
|
||||||
/* Get pointer to instance data structure and other data */
|
/* Get pointer to data structure needed for fast access */
|
||||||
/* needed for fast access */
|
|
||||||
inst = ckt->evt->info.inst_table[inst_index]->inst_ptr;
|
|
||||||
node_data = ckt->evt->data.node;
|
node_data = ckt->evt->data.node;
|
||||||
|
|
||||||
/* Setup circuit data in struct to be passed to code model function */
|
/* Setup circuit data in struct to be passed to code model function */
|
||||||
|
|
@ -125,7 +133,14 @@ int EVTload(
|
||||||
else
|
else
|
||||||
cm_data.circuit.time = 0.0;
|
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;
|
cm_data.circuit.temperature = ckt->CKTtemp - 273.15;
|
||||||
|
|
||||||
/* Setup data needed by cm_... functions */
|
/* Setup data needed by cm_... functions */
|
||||||
|
|
@ -142,11 +157,12 @@ int EVTload(
|
||||||
|
|
||||||
|
|
||||||
/* If after initialization and in transient analysis mode */
|
/* If after initialization and in transient analysis mode */
|
||||||
/* create a new state for the instance */
|
/* create a new state for the instance, */
|
||||||
|
/* except analog-only irreversibles. */
|
||||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized)
|
|
||||||
EVTcreate_state(ckt, inst_index);
|
|
||||||
|
|
||||||
|
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 */
|
/* Loop through all connections on the instance and setup */
|
||||||
/* load, total_load, and msg on all ports, and changed flag */
|
/* 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
|
# When recursively making clean, cm-objs and cm-gens do not contain
|
||||||
# the files generated for individual code models, as cmpp has already gone
|
# 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 :
|
cm-clean :
|
||||||
-rm -f $(cm)/$(cm).cm
|
-rm -f $(cm)/$(cm).cm
|
||||||
-rm -f $(cm-descr) $(cm-objs) $(cm-gens)
|
-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)
|
-rm -f $(cm-deps)
|
||||||
|
|
||||||
cm-distclean :
|
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
|
%/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
|
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
|
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
|
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_tristate
|
||||||
d_xnor
|
d_xnor
|
||||||
d_xor
|
d_xor
|
||||||
|
d_cosim
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,11 @@ double cm_netlist_get_l(void) {
|
||||||
return (coreitf->dllitf_cm_netlist_get_l)();
|
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) {
|
const char *cm_get_node_name(const char *port, unsigned int index) {
|
||||||
return coreitf->dllitf_cm_get_node_name(port, 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%\bin
|
||||||
mkdir %dst%\lib\ngspice
|
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 "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
|
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%\xtraevt.cm %dst%\lib\ngspice\xtraevt.cm
|
||||||
copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm
|
copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm
|
||||||
copy %cmsrc%\spice2poly.cm %dst%\lib\ngspice\spice2poly.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 "%2" == "fftw" goto copy2
|
||||||
if "%3" == "fftw" goto copy2
|
if "%3" == "fftw" goto copy2
|
||||||
|
|
@ -42,7 +39,6 @@ set cmsrc=.\codemodels\x64\Release
|
||||||
|
|
||||||
mkdir %dst%\bin
|
mkdir %dst%\bin
|
||||||
mkdir %dst%\lib\ngspice
|
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 "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
|
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%\xtraevt64.cm %dst%\lib\ngspice\xtraevt.cm
|
||||||
copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm
|
copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm
|
||||||
copy %cmsrc%\spice2poly64.cm %dst%\lib\ngspice\spice2poly.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 "%2" == "fftw" goto copy2-64
|
||||||
if "%3" == "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\
|
copy ..\..\fftw-3.3-dll64\libfftw3-3.dll %dst%\bin\
|
||||||
|
|
||||||
:end
|
: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%\bin
|
||||||
mkdir %dst%\lib\ngspice
|
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 "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
|
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%\xtraevt.cm %dst%\lib\ngspice\xtraevt.cm
|
||||||
copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm
|
copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm
|
||||||
copy %cmsrc%\spice2poly.cm %dst%\lib\ngspice\spice2poly.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 "%2" == "fftw" goto copy2
|
||||||
if "%3" == "fftw" goto copy2
|
if "%3" == "fftw" goto copy2
|
||||||
|
|
@ -42,7 +39,6 @@ set cmsrc=.\codemodels\x64\Debug
|
||||||
|
|
||||||
mkdir %dst%\bin
|
mkdir %dst%\bin
|
||||||
mkdir %dst%\lib\ngspice
|
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 "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
|
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%\xtraevt64.cm %dst%\lib\ngspice\xtraevt.cm
|
||||||
copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm
|
copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm
|
||||||
copy %cmsrc%\spice2poly64.cm %dst%\lib\ngspice\spice2poly.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 "%2" == "fftw" goto copy2-64
|
||||||
if "%3" == "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\
|
copy ..\..\fftw-3.3-dll64\libfftw3-3.dll %dst%\bin\
|
||||||
|
|
||||||
:end
|
: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_dump.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_echo.h" />
|
<ClInclude Include="..\src\frontend\com_echo.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_fft.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_ghelp.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_gnuplot.h" />
|
<ClInclude Include="..\src\frontend\com_gnuplot.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_hardcopy.h" />
|
<ClInclude Include="..\src\frontend\com_hardcopy.h" />
|
||||||
|
|
@ -1007,6 +1008,7 @@
|
||||||
<ClCompile Include="..\src\frontend\com_dump.c" />
|
<ClCompile Include="..\src\frontend\com_dump.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_echo.c" />
|
<ClCompile Include="..\src\frontend\com_echo.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_fft.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_ghelp.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_gnuplot.c" />
|
<ClCompile Include="..\src\frontend\com_gnuplot.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_hardcopy.c" />
|
<ClCompile Include="..\src\frontend\com_hardcopy.c" />
|
||||||
|
|
@ -1220,6 +1222,7 @@
|
||||||
<ClCompile Include="..\src\misc\string.c" />
|
<ClCompile Include="..\src\misc\string.c" />
|
||||||
<ClCompile Include="..\src\misc\tilde.c" />
|
<ClCompile Include="..\src\misc\tilde.c" />
|
||||||
<ClCompile Include="..\src\misc\util.c" />
|
<ClCompile Include="..\src\misc\util.c" />
|
||||||
|
<ClCompile Include="..\src\misc\win_time.c" />
|
||||||
<ClCompile Include="..\src\misc\wlist.c" />
|
<ClCompile Include="..\src\misc\wlist.c" />
|
||||||
<ClCompile Include="..\src\ngspice.c" />
|
<ClCompile Include="..\src\ngspice.c" />
|
||||||
<ClCompile Include="..\src\osdi\osdiacld.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_dump.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_echo.h" />
|
<ClInclude Include="..\src\frontend\com_echo.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_fft.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_ghelp.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_gnuplot.h" />
|
<ClInclude Include="..\src\frontend\com_gnuplot.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_hardcopy.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_dump.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_echo.c" />
|
<ClCompile Include="..\src\frontend\com_echo.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_fft.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_ghelp.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_gnuplot.c" />
|
<ClCompile Include="..\src\frontend\com_gnuplot.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_hardcopy.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\string.c" />
|
||||||
<ClCompile Include="..\src\misc\tilde.c" />
|
<ClCompile Include="..\src\misc\tilde.c" />
|
||||||
<ClCompile Include="..\src\misc\util.c" />
|
<ClCompile Include="..\src\misc\util.c" />
|
||||||
|
<ClCompile Include="..\src\misc\win_time.c" />
|
||||||
<ClCompile Include="..\src\misc\wlist.c" />
|
<ClCompile Include="..\src\misc\wlist.c" />
|
||||||
<ClCompile Include="..\src\ngspice.c" />
|
<ClCompile Include="..\src\ngspice.c" />
|
||||||
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
||||||
|
|
|
||||||
|
|
@ -885,6 +885,7 @@
|
||||||
<ClInclude Include="..\src\frontend\com_shift.h" />
|
<ClInclude Include="..\src\frontend\com_shift.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_state.h" />
|
<ClInclude Include="..\src\frontend\com_state.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_strcmp.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_unset.h" />
|
||||||
<ClInclude Include="..\src\frontend\com_wr_ic.h" />
|
<ClInclude Include="..\src\frontend\com_wr_ic.h" />
|
||||||
<ClInclude Include="..\src\frontend\control.h" />
|
<ClInclude Include="..\src\frontend\control.h" />
|
||||||
|
|
@ -1498,6 +1499,7 @@
|
||||||
<ClCompile Include="..\src\frontend\com_shift.c" />
|
<ClCompile Include="..\src\frontend\com_shift.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_state.c" />
|
<ClCompile Include="..\src\frontend\com_state.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_strcmp.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_sysinfo.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_unset.c" />
|
<ClCompile Include="..\src\frontend\com_unset.c" />
|
||||||
<ClCompile Include="..\src\frontend\com_wr_ic.c" />
|
<ClCompile Include="..\src\frontend\com_wr_ic.c" />
|
||||||
|
|
@ -1700,6 +1702,7 @@
|
||||||
<ClCompile Include="..\src\misc\string.c" />
|
<ClCompile Include="..\src\misc\string.c" />
|
||||||
<ClCompile Include="..\src\misc\tilde.c" />
|
<ClCompile Include="..\src\misc\tilde.c" />
|
||||||
<ClCompile Include="..\src\misc\util.c" />
|
<ClCompile Include="..\src\misc\util.c" />
|
||||||
|
<ClCompile Include="..\src\misc\win_time.c" />
|
||||||
<ClCompile Include="..\src\misc\wlist.c" />
|
<ClCompile Include="..\src\misc\wlist.c" />
|
||||||
<ClCompile Include="..\src\ngspice.c" />
|
<ClCompile Include="..\src\ngspice.c" />
|
||||||
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
<ClCompile Include="..\src\osdi\osdiacld.c" />
|
||||||
|
|
@ -2893,4 +2896,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,10 @@
|
||||||
<AdditionalIncludeDirectories>..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="icm\digital\d_xor\d_xor-ifspec.c" />
|
<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" />
|
<ClCompile Include="..\..\src\xspice\icm\dlmain.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue