Merge branch 'pre-master-45' into bt_dev
This commit is contained in:
commit
c3f798874d
117
autogen.sh
117
autogen.sh
|
|
@ -11,13 +11,6 @@
|
|||
|
||||
PROJECT=ngspice
|
||||
|
||||
# ADMS variables
|
||||
|
||||
ADMSDIR=src/spicelib/devices/adms
|
||||
XMLPATH=src/spicelib/devices/adms/admst
|
||||
ADMSXML=${ADMSXML:-admsXml}
|
||||
ADMS=0
|
||||
|
||||
# Exit variable
|
||||
DIE=0
|
||||
|
||||
|
|
@ -35,7 +28,6 @@ help()
|
|||
echo
|
||||
echo "$PROJECT autogen.sh help"
|
||||
echo
|
||||
echo "--adms -a: enables adms feature"
|
||||
echo "--help -h: print this file"
|
||||
echo "--version -v: print version"
|
||||
echo
|
||||
|
|
@ -51,9 +43,6 @@ version()
|
|||
error_and_exit()
|
||||
{
|
||||
echo "Error: $1"
|
||||
if [ "$ADMS" -eq 1 ]; then
|
||||
rm -f temp-adms.ac
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
@ -95,53 +84,9 @@ check_autoconf()
|
|||
}
|
||||
|
||||
|
||||
check_adms()
|
||||
{
|
||||
($ADMSXML --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "You must have admsXml installed to compile adms models."
|
||||
echo "See https://sourceforge.net/projects/mot-adms/"
|
||||
echo "(version 2.3.6, tested for ngspice under MINGW on MS Windows)"
|
||||
DIE=1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# check if verilog-a files exist in every adms device directory
|
||||
check_adms_va()
|
||||
{
|
||||
echo
|
||||
# get the devices directories from configure.ac
|
||||
admsdirs=`awk '$1 ~ /#VLAMKF/ { print $2 }' < configure.ac`
|
||||
admsdirs=`echo $admsdirs | sed "s/\/Makefile//g"`
|
||||
|
||||
for adms_dir in $admsdirs ; do
|
||||
FOK=0
|
||||
if [ -d "$adms_dir" ]; then
|
||||
ls $adms_dir/admsva/*.va > /dev/null 2>&1
|
||||
exitcode=$?
|
||||
if [ $exitcode -ne 0 ]; then
|
||||
FOK=1
|
||||
fi
|
||||
else
|
||||
FOK=1
|
||||
fi
|
||||
if [ "$FOK" -eq 1 ]; then
|
||||
echo "Error: No *.va file found in $adms_dir/admsva"
|
||||
echo "Please download patch file ng-adms-va.tar.gz from"
|
||||
echo "http://ngspice.sourceforge.net/experimental/ngspice-adms-va.7z"
|
||||
echo "and expand it into the ngspice directory"
|
||||
echo
|
||||
DIE=1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
"--adms" | "-a")
|
||||
check_adms
|
||||
check_adms_va
|
||||
ADMS=1
|
||||
echo "Warning: adms is no longer available, ignored!"
|
||||
;;
|
||||
|
||||
"--help" | "-h")
|
||||
|
|
@ -170,54 +115,6 @@ fi
|
|||
exit 1
|
||||
}
|
||||
|
||||
# only for --adms:
|
||||
if [ "$ADMS" -gt 0 ]; then
|
||||
|
||||
check_awk
|
||||
|
||||
# add adms related Makefile entries to a configure.ac style file for
|
||||
# autoconf and automake
|
||||
|
||||
# Find all lines with "#VLAMKF" and put the second token of each line
|
||||
# into a shell variable
|
||||
adms_Makefiles=`awk '$1 ~ /#VLAMKF/ { print "./" $2 }' < configure.ac`
|
||||
|
||||
# just the same, but escape newlines with '\' for the following sed expression
|
||||
znew=`awk '$1 ~ /#VLAMKF/ { print " " $2 "\\\\" }' < configure.ac`
|
||||
|
||||
# Find "tests/vbic/Makefile" and insert the list of Makefiles
|
||||
# some sed's fail to process the '\n' escape on the RHS,
|
||||
# thus use an escaped plain newline
|
||||
sed \
|
||||
-e "s,tests\\/vbic\\/Makefile,&\\
|
||||
$znew
|
||||
," \
|
||||
configure.ac > temp-adms.ac
|
||||
|
||||
for adms_dir in `ls $ADMSDIR` ; do
|
||||
if [ -d "$ADMSDIR/$adms_dir" ]; then
|
||||
|
||||
case "$adms_dir" in
|
||||
|
||||
"admst")
|
||||
# echo "Skipping admst dir"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Entering into directory: $adms_dir"
|
||||
echo "-->"$ADMSDIR/$adms_dir
|
||||
(
|
||||
cd $ADMSDIR/$adms_dir
|
||||
$ADMSXML `ls admsva/*.va` -Iadmsva -xv -x \
|
||||
-e ../admst/ngspiceVersion.xml \
|
||||
-e ../admst/ngspiceMakefile.am.xml
|
||||
)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
echo "Running $LIBTOOLIZE"
|
||||
$LIBTOOLIZE --copy --force \
|
||||
|
|
@ -239,22 +136,10 @@ echo "Running automake -Wall --copy --add-missing"
|
|||
automake -Wall --copy --add-missing \
|
||||
|| error_and_exit "automake failed"
|
||||
|
||||
if [ "$ADMS" -gt 0 ]; then
|
||||
echo "Running automake for adms"
|
||||
automake -Wall --copy --add-missing $adms_Makefiles \
|
||||
|| error_and_exit "automake failed"
|
||||
fi
|
||||
|
||||
echo "Running autoconf"
|
||||
if [ "$ADMS" -gt 0 ]; then
|
||||
autoconf --force temp-adms.ac > configure \
|
||||
|| error_and_exit "autoconf failed, with adms"
|
||||
rm -f temp-adms.ac
|
||||
chmod +x configure
|
||||
else
|
||||
autoconf --force \
|
||||
|| error_and_exit "autoconf failed"
|
||||
fi
|
||||
|
||||
echo "Success."
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -1274,7 +1274,7 @@ else
|
|||
AC_CHECK_HEADERS([readline/readline.h readline/history.h],
|
||||
[AC_DEFINE([HAVE_GNUREADLINE], [], [Define if we have GNU readline])],
|
||||
[AC_MSG_ERROR([Couldn't find GNU readline headers.])])
|
||||
AC_SEARCH_LIBS([tputs], [ncurses tinfo termcap],
|
||||
AC_SEARCH_LIBS([tputs], [tinfo termcap ncurses],
|
||||
[AC_DEFINE([HAVE_TERMCAP], [], [Define if we have ncurses/terminfo or termcap])],
|
||||
[AC_MSG_ERROR([Found neither ncurses/terminfo or termcap])])
|
||||
AC_CHECK_LIB([readline], [readline],
|
||||
|
|
@ -1290,7 +1290,7 @@ else
|
|||
if test -f $dir/include/readline/readline.h && test -f $dir/include/readline/history.h ; then
|
||||
|
||||
AC_DEFINE([HAVE_GNUREADLINE], [], [Define if we have GNU readline])
|
||||
AC_SEARCH_LIBS([tputs], [ncurses tinfo termcap],
|
||||
AC_SEARCH_LIBS([tputs], [tinfo termcap ncurses],
|
||||
[AC_DEFINE([HAVE_TERMCAP], [], [Define if we have ncurses/terminfo or termcap])],
|
||||
[AC_MSG_ERROR([Found neither ncurses/terminfo or termcap])])
|
||||
AC_CHECK_LIB([readline], [readline],
|
||||
|
|
@ -1312,7 +1312,7 @@ else
|
|||
AC_CHECK_HEADERS([editline/readline.h],
|
||||
[AC_DEFINE([HAVE_BSDEDITLINE], [1], [Define to enable BSD editline])],
|
||||
[AC_MSG_ERROR([Couldn't find BSD editline headers.])])
|
||||
AC_SEARCH_LIBS([tputs], [ncurses tinfo termcap],
|
||||
AC_SEARCH_LIBS([tputs], [tinfo termcap ncurses],
|
||||
[AC_DEFINE([HAVE_TERMCAP], [], [Define if we have ncurses/terminfo or termcap])],
|
||||
[AC_MSG_ERROR([Found neither ncurses/terminfo or termcap])])
|
||||
AC_CHECK_LIB([edit], [readline],
|
||||
|
|
@ -1323,7 +1323,7 @@ else
|
|||
fi
|
||||
|
||||
# Use AC_CHECK_HEADERS so the HAVE_*_H symbol gets defined
|
||||
AC_CHECK_HEADERS([ncurses/termcap.h termcap.h])
|
||||
AC_CHECK_HEADERS([ncurses/termcap.h termcap.h term.h])
|
||||
AC_CHECK_HEADERS([sys/sysctl.h])
|
||||
|
||||
# Add OpenMP to ngspice.
|
||||
|
|
@ -1443,6 +1443,7 @@ AC_CONFIG_FILES([Makefile
|
|||
src/xspice/ipc/Makefile
|
||||
src/xspice/idn/Makefile
|
||||
src/xspice/verilog/Makefile
|
||||
src/xspice/vhdl/Makefile
|
||||
src/osdi/Makefile
|
||||
tests/Makefile
|
||||
tests/bsim1/Makefile
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,30 @@
|
|||
* simple examples using Skywater PDK
|
||||
|
||||
PDK sources:
|
||||
https://github.com/google/skywater-pdk
|
||||
http://opencircuitdesign.com/open_pdks/
|
||||
|
||||
Examples are: a simple inverter, and a benchmark circuit ISCAS85 C7552 with ca. 15k transistors.
|
||||
These examples serve as low level starters with given ngspice netlist. If you are to design a circuit,
|
||||
you will be better off with a GUI atop ngspice like XSCHEM, see
|
||||
http://repo.hu/projects/xschem/xschem_man/tutorial_run_simulation.html and many other web sites and videos.
|
||||
|
||||
How to run the circuits in ngspice:
|
||||
|
||||
Edit the input files for correcting the path to the Skywater library, as it is user and OS specific.
|
||||
|
||||
Create a file .spiceinit in your HOME directory (or in this project directory).
|
||||
It should contain the following statements:
|
||||
|
||||
set num_threads=8 ; number of physical core in your machine
|
||||
set ngbehavior=hsa ; set compatibility for reading PDK libs
|
||||
set skywaterpdk ; skip some checks for faster lib loading
|
||||
set ng_nomodcheck ; trust the models, don't check the model parameters
|
||||
unset interactive ; run scripts without interruption (default)
|
||||
set nginfo ; some more info
|
||||
option KLU ; select KLU solver over Sparse 1.3 solver
|
||||
|
||||
Run the simulation by calling
|
||||
ngspice skywater_inverter.net
|
||||
|
||||
A plotting alternative in addition to the internal graphics is gnuplot.
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
* SkyWater PDK
|
||||
* simple inverter
|
||||
|
||||
* Path to the PDK, to be set by you, the user
|
||||
*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice"
|
||||
*.lib "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\sky130.lib.spice" tt
|
||||
.lib D:\Spice_general\open_pdks\sky130\sky130A\libs.tech\combined\sky130.lib.spice tt
|
||||
|
||||
* the voltage sources:
|
||||
Vdd vdd gnd DC 1.8
|
||||
V1 in gnd pulse(0 1.8 0p 200p 100p 1n 2n)
|
||||
|
||||
* calling the inverter subcircuit
|
||||
Xnot1 in vdd gnd out not1
|
||||
|
||||
.subckt not1 a vdd vss z
|
||||
xm01 z a vdd vdd sky130_fd_pr__pfet_01v8_hvt l=0.15 w=0.99 as=0.26235 ad=0.26235 ps=2.51 pd=2.51
|
||||
xm02 z a vss vss sky130_fd_pr__nfet_01v8 l=0.15 w=0.495 as=0.131175 ad=0.131175 ps=1.52 pd=1.52
|
||||
c3 a vss 0.384f
|
||||
c2 z vss 0.576f
|
||||
.ends
|
||||
|
||||
* simulation command:
|
||||
.tran 1ps 10ns 0 10p
|
||||
|
||||
.control
|
||||
run
|
||||
rusage time
|
||||
set xbrushwidth=3
|
||||
plot in out
|
||||
*gnuplot interm in out
|
||||
.endc
|
||||
|
||||
.end
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
VHDL-controlled simple timer.
|
||||
|
||||
* This is the model for an RS flip-flop implemented by Icarus Verilog.
|
||||
|
||||
.model vlog_ff d_cosim simulation="./timer_core" sim_args=["555"]
|
||||
|
||||
* The bulk of the circuit is in a shared file.
|
||||
|
||||
.include ../verilator/555.shared
|
||||
.end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
-- Very simple logic for a 555 timer simulation
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity timer_core is
|
||||
port (
|
||||
Trigger, Threshold, Reset : in std_logic;
|
||||
Q, Qbar : out std_logic
|
||||
);
|
||||
end timer_core;
|
||||
|
||||
architecture rtl of timer_core is
|
||||
signal result : std_logic := '0';
|
||||
signal ireset, go : std_logic;
|
||||
begin
|
||||
go <= Trigger and Reset;
|
||||
ireset <= (Threshold and not go) or not Reset;
|
||||
Q <= result;
|
||||
Qbar <= not result;
|
||||
|
||||
process (go, ireset)
|
||||
begin
|
||||
if rising_edge(go) or rising_edge(ireset) then
|
||||
result <= go;
|
||||
end if;
|
||||
end process;
|
||||
end rtl;
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ngspice -- ghnggen -top timer_core 555.vhd
|
||||
ngspice ghnggen pwm.vhd
|
||||
ngspice ghnggen adc.vhd
|
||||
ngspice ghnggen mc.vhd
|
||||
|
|
@ -0,0 +1 @@
|
|||
del /q *.obj *.so* *.vpi *.DLL *.cf *.raw
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
The circuits in this directory illustrate the use of the d_cosim
|
||||
XSPICE code model as a container for a VHDL simulation using
|
||||
the GHDL compiler. Use a version of GHDL built with the LLVM back-end.
|
||||
|
||||
The circuits and steps below are intended to be used from the directory
|
||||
containing this file, certainly ouput files from GHDL should be in
|
||||
the current directory when simulating.
|
||||
|
||||
The example circuits are:
|
||||
|
||||
555.cir: The probably familiar NE555 oscillator provides a minimal example
|
||||
of combined simulation with SPICE and GHDL.
|
||||
The digital part of the IC, a simple SR flip-flop, is expressed in VHDL.
|
||||
|
||||
pwm.c: VHDL "wait" statements control a pulse-width modulated output to
|
||||
generate an approximate sine wave.
|
||||
|
||||
adc.cir: Slightly more complex VHDL describes the controlling part
|
||||
of a switched-capacitor ADC.
|
||||
|
||||
mc.cir: A motor-control simulation with the control algorithm written
|
||||
in non-sythesisable VHDL. It is used as a general-purpose programming
|
||||
language rather than a HDL. Apart from showing that this is easy to do,
|
||||
no part should be taken seriously: the algorithm is poor (but simple),
|
||||
the motor parameters are invented and the voltages and currents representing
|
||||
mechanical quantities do not match standard units.
|
||||
|
||||
Before a simulation can be run, the associated VHDL code must be compiled
|
||||
and an additional shared library, ghdlng.vpi must be built. A library script
|
||||
isavailable to simplify the steps, run like this:
|
||||
|
||||
ngspice ghnggen adc.vhd
|
||||
|
||||
A command interpreter script, ./build or BUILD.CMD, is provided to build
|
||||
all four examples, with clean/CLEAN.CMD to remove the files created.
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Simulation of a switched-capacitor SAR ADC with GHDL and d_cosim.
|
||||
|
||||
* Model line for the digital control implemented by GHDL.
|
||||
|
||||
.model dut d_cosim simulation="./adc" sim_args=["./adc"]
|
||||
|
||||
* The bulk of the circuit is in a shared file.
|
||||
|
||||
.include ../verilator/adc.shared
|
||||
.end
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity adc is
|
||||
generic ( Bits : integer := 6 );
|
||||
port (
|
||||
Clk : in std_logic;
|
||||
Comp : in std_logic;
|
||||
Start : in std_logic;
|
||||
Sample : out std_logic;
|
||||
Done : out std_logic;
|
||||
Result : out unsigned(0 to Bits - 1)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture ghdl_adc of adc is
|
||||
signal SR : unsigned(0 to Bits - 1);
|
||||
signal Result_Reg : unsigned(0 to Bits - 1);
|
||||
signal Sample_Reg : std_logic := '0';
|
||||
signal Running : std_logic := '0';
|
||||
begin
|
||||
Result <= Result_Reg;
|
||||
Sample <= Sample_Reg;
|
||||
|
||||
process (Clk)
|
||||
constant Zeros : unsigned(0 to Bits - 1) := (others => '0');
|
||||
variable NextSR : unsigned(0 to Bits - 1);
|
||||
begin
|
||||
if rising_edge(Clk) then
|
||||
if Running = '1' then
|
||||
if Sample_Reg = '1' then
|
||||
Sample_Reg <= '0';
|
||||
SR(Bits - 1) <= '1';
|
||||
Result_Reg(Bits - 1) <= '1';
|
||||
else
|
||||
if SR /= 0 then
|
||||
NextSR := shift_left(SR, 1);
|
||||
if Comp = '1' then
|
||||
Result_Reg <= (Result_Reg and not SR) or NextSR;
|
||||
else
|
||||
Result_Reg <= Result_Reg or NextSR;
|
||||
end if;
|
||||
SR <= NextSR;
|
||||
else
|
||||
Running <= '0';
|
||||
Done <= '1';
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
if Start = '1' then
|
||||
Running <= '1';
|
||||
Sample_Reg <= '1';
|
||||
Done <= '0';
|
||||
SR <= Zeros;
|
||||
Result_Reg <= Zeros;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end architecture;
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ngspice -- ghnggen -top timer_core 555.vhd
|
||||
ngspice ghnggen pwm.vhd
|
||||
ngspice ghnggen adc.vhd
|
||||
ngspice ghnggen mc.vhd
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
rm -f *~ *.o *.so* *.vpi *.cf *.dylib *.raw
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
Simulation of elecric motor and controller in behavioural VHDL.
|
||||
|
||||
* Power from a wall socket.
|
||||
|
||||
Vmains live 0 SIN 0 250 50
|
||||
|
||||
* Behavioral power-line zero-crossing detector,
|
||||
|
||||
Bcross cross 0 V=(V(live) > -2 && V(live) < 2) ? 5 : 0
|
||||
|
||||
* Motor and its rotor
|
||||
|
||||
Xmotor live mt1 tacho 0 motor
|
||||
|
||||
* A triac to control the motor is replaced by a voltage-controlled switch
|
||||
* to avoid including a manufacurer's triac library.
|
||||
|
||||
*Xtriac mt1 gate 0 BTA16-600B
|
||||
Striac mt1 0 drive 0 triac off
|
||||
.model triac sw vt=1.5 vh=1 roff=1meg
|
||||
|
||||
* The controller is implemented as VHDL code. The argument "-gTarget=5000"
|
||||
* in the model line overrides the default target motor speed in the VHDL file.
|
||||
* Tuning parameters Full_Band and Dead_band may also be set.
|
||||
|
||||
Ademo [ cross tacho ] [ drive ] controller
|
||||
.model controller d_cosim simulation="./mc"
|
||||
+ sim_args=["./mc.so" "-gTarget=4500"]
|
||||
|
||||
|
||||
* Motor electrical circuit - inductance, resistance and back-EMF
|
||||
* Loosley based on:
|
||||
* https://www.precisionmicrodrives.com/content/ab-025-using-spice-to-model-dc-motors/
|
||||
* No resemblance is claimed to any actual motor, living or dead.
|
||||
|
||||
.subckt motor live neutral tacho1 tacho2
|
||||
+ Lm=0.3 Rm=30 BackC=20 // Electrical
|
||||
+ TorqueC=30 Linertia=20 Rdrag=20 Load={50} // Mechanical
|
||||
|
||||
* Electrical inductance and resistance of the motor.
|
||||
|
||||
Lm live internal {Lm}
|
||||
Rm internal back_emf {Rm}
|
||||
|
||||
* Back EMF: here I(Bmech) is proportional to speed, I(Bback) is motor current.
|
||||
|
||||
Bback back_emf neutral V=-I(Bmech)*I(Bback)*{BackC}
|
||||
|
||||
* Mechanical simulation: torque (V), speed (I), inertia (L) and
|
||||
* friction/load (R).
|
||||
* Series (Universal) motor so torque proportional to current squared.
|
||||
|
||||
Bmech torque 0 V=I(Bback)*I(Bback)*{TorqueC} // Motor torque
|
||||
Lmech torque inertia {Linertia}
|
||||
Rmech inertia load {Rdrag}
|
||||
|
||||
* In addition to friction (Rdrag) there is a varying load.
|
||||
|
||||
* Delay
|
||||
* | Rise time
|
||||
* | | Fall time
|
||||
* | | | Pulse width
|
||||
* | | | | Period
|
||||
* | | | | |
|
||||
* V V V V V
|
||||
Vload load 0 PULSE 0 {Load} 1.2 10m 10m 200m 400m
|
||||
|
||||
* Tachometer: integrate speed for position and pulse.
|
||||
|
||||
Bpos i1 0 I=I(Bmech)
|
||||
Cpos i1 0 0.01
|
||||
.ic v(i1)=0
|
||||
Btach tacho1 tacho2 V=((V(i1) - floor(V(i1)) > 0.5) ? 5 : 0)
|
||||
|
||||
.ends
|
||||
|
||||
.control
|
||||
save drive @b.xmotor.bback[i] @b.xmotor.bmech[i] xmotor.load
|
||||
tran 50u 3
|
||||
plot @b.xmotor.bback[i] @b.xmotor.bmech[i]*-10 drive xmotor.load/10
|
||||
.endc
|
||||
.end
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
-- Test crude algorithm for a simple motor controller.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity mc is
|
||||
-- Control values that may be overrriden by the "sim_args" option
|
||||
-- in a netlist's .model line. Intgers are used as GHDL does not
|
||||
-- support overriding Real values.
|
||||
generic (
|
||||
Target : Integer := 4000; -- notional RPM
|
||||
Dead_Band : Integer := 200;
|
||||
Full_Band : Integer := 600
|
||||
);
|
||||
port (
|
||||
Zero : in std_logic;
|
||||
Tach : in std_logic;
|
||||
Trigger : out std_logic
|
||||
);
|
||||
end mc;
|
||||
|
||||
architecture mc_arch of mc is
|
||||
shared variable Speed : Real := 0.0;
|
||||
begin
|
||||
Tachometer : process (Tach) is
|
||||
variable Time : Real := 0.0;
|
||||
variable Last_pulse : Real := 0.0;
|
||||
begin
|
||||
if rising_edge(Tach) or falling_edge(Tach) then
|
||||
Time := real(now / 1 ns) * 1.0e-9;
|
||||
Speed := 30.0 / (Time - Last_pulse);
|
||||
Last_pulse := Time;
|
||||
end if;
|
||||
end process Tachometer;
|
||||
|
||||
Controller : process (Zero) is
|
||||
variable Skip : Integer := 0;
|
||||
variable Count : Integer := 0;
|
||||
variable Even : Boolean := True;
|
||||
variable Was_even : Boolean := True;
|
||||
variable Error : Integer;
|
||||
begin
|
||||
-- Trigger triac on zero crossings, preventing DC current.
|
||||
|
||||
if rising_edge(Zero) then
|
||||
Even := not Even;
|
||||
if (Count >= Skip) and (Even /= Was_even) then
|
||||
Trigger <= '1';
|
||||
Was_even := Even;
|
||||
if Count > Skip then
|
||||
Count := 0;
|
||||
else
|
||||
Count := -1;
|
||||
end if;
|
||||
else
|
||||
Trigger <= '0';
|
||||
end if;
|
||||
Count := Count + 1;
|
||||
|
||||
-- A very crude feedback mechanism.
|
||||
|
||||
Error := integer(Speed) - Target;
|
||||
if Error > Full_Band then
|
||||
-- No drive
|
||||
Skip := 1;
|
||||
Count := 0;
|
||||
elsif Error < -Full_Band then
|
||||
-- Full Drive
|
||||
Skip := 0;
|
||||
elsif Error > Dead_Band then
|
||||
Skip := Skip + 1;
|
||||
elsif Error < -Dead_Band then
|
||||
if Skip > 0 then
|
||||
Skip := Skip - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process Controller;
|
||||
end mc_arch;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
* Waveform generation by PWM in VHDL.
|
||||
|
||||
adut null [ out ] pwm_sin
|
||||
.model pwm_sin d_cosim simulation="./pwm" sim_args = [ "pwm" ]
|
||||
|
||||
r1 out smooth 100k
|
||||
c1 smooth 0 1u
|
||||
.control
|
||||
tran 1m 2
|
||||
plot out-3.3 smooth
|
||||
.endc
|
||||
.end
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
-- Very simple logic for PWM waveform generation.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity pwm is
|
||||
port ( output : out std_logic := '1');
|
||||
end pwm;
|
||||
|
||||
architecture pwm_impl of pwm is
|
||||
constant Cycles : Integer := 1000;
|
||||
constant Samples : Integer := 1000;
|
||||
constant uSec : Time := 1 us;
|
||||
begin
|
||||
process
|
||||
variable j : Integer := 0;
|
||||
variable width : Integer := Cycles / 2;
|
||||
variable sine : Real;
|
||||
begin
|
||||
wait for width * uSec;
|
||||
output <= '0';
|
||||
wait for (Cycles - width) * uSec;
|
||||
j := j + 1;
|
||||
if j = Samples then
|
||||
j := 0;
|
||||
end if;
|
||||
sine := sin(real(j) * MATH_2_PI / real(Samples));
|
||||
width := integer(real(Samples) * (1.0 + sine) / 2.0);
|
||||
if width = 0 then
|
||||
output <= '0';
|
||||
else
|
||||
output <= '1';
|
||||
end if;
|
||||
end process;
|
||||
end pwm_impl;
|
||||
|
||||
|
|
@ -973,6 +973,26 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
FILE *fdo = fopen("debug-out2.txt", "w");
|
||||
if (fdo) {
|
||||
struct card *tc = NULL;
|
||||
fprintf(fdo,
|
||||
"\n\n**************** uncommented deck without source file info "
|
||||
"**************\n\n");
|
||||
/* always print first line */
|
||||
fprintf(fdo, "%6d %s\n", deck->linenum,
|
||||
deck->line);
|
||||
/* here without out-commented lines */
|
||||
for (tc = deck->nextcard; tc; tc = tc->nextcard) {
|
||||
if (*(tc->line) == '*')
|
||||
continue;
|
||||
/* Only truncated .model lines */
|
||||
if (ciprefix(".model", tc->line)) {
|
||||
fprintf(fdo, "%6d %.100s ...\n",
|
||||
tc->linenum, tc->line);
|
||||
}
|
||||
else {
|
||||
fprintf(fdo, "%6d %s\n",
|
||||
tc->linenum, tc->line);
|
||||
}
|
||||
}
|
||||
fprintf(fdo, "**************** uncommented deck **************\n\n");
|
||||
/* always print first line */
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line);
|
||||
|
|
|
|||
|
|
@ -1231,8 +1231,15 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
|
|||
for (t = cc->nextcard; t; t = t->nextcard) {
|
||||
if (*(t->line) == '*')
|
||||
continue;
|
||||
fprintf(fd, "%6d %s\n",
|
||||
/* Only truncated .model lines */
|
||||
if (ciprefix(".model", t->line)) {
|
||||
fprintf(fd, "%6d %.100s ...\n",
|
||||
t->linenum, t->line);
|
||||
}
|
||||
else {
|
||||
fprintf(fd, "%6d %s\n",
|
||||
t->linenum, t->line);
|
||||
}
|
||||
}
|
||||
fprintf(fd,
|
||||
"\n\n**************** uncommented deck "
|
||||
|
|
|
|||
|
|
@ -256,9 +256,6 @@ com_version(wordlist *wl)
|
|||
#ifdef NGDEBUG
|
||||
fprintf(cp_out, "** Debugging option (-g) enabled\n");
|
||||
#endif
|
||||
#ifdef ADMS
|
||||
fprintf(cp_out, "** Adms interface enabled\n");
|
||||
#endif
|
||||
#ifdef USE_OMP
|
||||
fprintf(cp_out, "** OpenMP multithreading for BSIM3, BSIM4 enabled\n");
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,19 +21,6 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_TERMCAP
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_TERMCAP_H
|
||||
#include <termcap.h>
|
||||
#elif HAVE_NCURSES_TERMCAP_H
|
||||
#include <ncurses/termcap.h>
|
||||
#endif
|
||||
|
||||
#include "ngspice/cpdefs.h"
|
||||
|
||||
#include "variable.h"
|
||||
|
|
@ -45,6 +32,22 @@ bool out_isatty = TRUE;
|
|||
|
||||
#if !defined (TCL_MODULE) && !defined (SHARED_MODULE)
|
||||
|
||||
#ifdef HAVE_TERMCAP
|
||||
/* The tputs() function was found in a library, but there are several
|
||||
* candidates for the header file location.
|
||||
*/
|
||||
|
||||
#if HAVE_TERM_H
|
||||
#include <term.h>
|
||||
#elif HAVE_TERMCAP_H
|
||||
#include <termcap.h>
|
||||
#elif HAVE_NCURSES_TERMCAP_H
|
||||
#include <ncurses/termcap.h>
|
||||
#else
|
||||
#undef HAVE_TERMCAP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMCAP
|
||||
static char *motion_chars;
|
||||
static char *clear_chars;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ void com_optran(wordlist* wl) {
|
|||
return;
|
||||
}
|
||||
else if (!ft_curckt && !dataset && wl == NULL) {
|
||||
fprintf(stderr, "Error: syntax error with command 'optran'!\n");
|
||||
fprintf(stderr, "Warning: syntax error with command 'optran'!\n");
|
||||
fprintf(stderr, " Command ingnored\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -169,7 +169,8 @@ void com_optran(wordlist* wl) {
|
|||
goto bugquit;
|
||||
}
|
||||
if (opstepsize > opfinaltime/50.) {
|
||||
fprintf(stderr, "Warning: Optran step size potentially too large.\n");
|
||||
opstepsize = opfinaltime / 50.;
|
||||
fprintf(stdout, "Note: Optran step size set to %e, (stepsize = finaltime / 50).\n", opstepsize);
|
||||
}
|
||||
if (opramptime > opfinaltime) {
|
||||
fprintf(stderr, "Error: Optran ramp time larger than final time.\n");
|
||||
|
|
|
|||
|
|
@ -137,8 +137,6 @@ libdev_la_SOURCES = \
|
|||
cktsoachk.c \
|
||||
limit.c
|
||||
|
||||
EXTRA_DIST = adms/admst
|
||||
|
||||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
|
||||
AM_CFLAGS = $(STATIC)
|
||||
|
||||
|
|
|
|||
|
|
@ -126,16 +126,6 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */
|
|||
#include "vcvs/vcvsitf.h"
|
||||
#include "vsrc/vsrcitf.h"
|
||||
#include "vdmos/vdmositf.h"
|
||||
#ifdef ADMS
|
||||
#include "adms/hicum0/hicum0itf.h"
|
||||
#include "adms/mextram/bjt504titf.h"
|
||||
#include "adms/ekv/ekvitf.h"
|
||||
#include "adms/psp102/psp102itf.h"
|
||||
#include "adms/psp103/psp103itf.h"
|
||||
#include "adms/bsimbulk/bsimbulkitf.h"
|
||||
#include "adms/bsimcmg/bsimcmgitf.h"
|
||||
#include "adms/r2_cmc/r2_cmcitf.h"
|
||||
#endif
|
||||
#ifdef CIDER
|
||||
/* Numerical devices (Cider integration) */
|
||||
#include "nbjt/nbjtitf.h"
|
||||
|
|
@ -211,17 +201,6 @@ static SPICEdev *(*static_devices[])(void) = {
|
|||
get_numos_info,
|
||||
#endif
|
||||
|
||||
#ifdef ADMS
|
||||
(SPICEdev *(*)(void)) get_hicum0_info,
|
||||
(SPICEdev *(*)(void)) get_bjt504t_info,
|
||||
(SPICEdev *(*)(void)) get_ekv_info,
|
||||
(SPICEdev *(*)(void)) get_psp102_info,
|
||||
(SPICEdev *(*)(void)) get_psp103_info,
|
||||
(SPICEdev *(*)(void)) get_bsimbulk_info,
|
||||
(SPICEdev *(*)(void)) get_bsimcmg_info,
|
||||
(SPICEdev *(*)(void)) get_r2_cmc_info,
|
||||
#endif
|
||||
|
||||
#ifdef NDEV
|
||||
get_ndev_info,
|
||||
#endif
|
||||
|
|
@ -303,17 +282,12 @@ SPICEdev ** devices(void)
|
|||
#ifdef DEVLIB
|
||||
/*not yet usable*/
|
||||
|
||||
#ifdef ADMS
|
||||
#define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \
|
||||
"bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \
|
||||
"cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \
|
||||
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum0", "bjt504t", "ekv", "psp102", "psp103", "bsimbulk", "bsimcmg"}
|
||||
#else
|
||||
|
||||
#define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \
|
||||
"bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \
|
||||
"cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \
|
||||
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum2"}
|
||||
#endif
|
||||
|
||||
int load_dev(char *name) {
|
||||
char *msg;
|
||||
char libname[50];
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ IFparm DIOpTable[] = { /* parameters */
|
|||
IOPAU("ic", DIO_IC, IF_REAL, "Initial device voltage"),
|
||||
IOPU("area", DIO_AREA, IF_REAL, "Area factor"),
|
||||
IOPU("pj", DIO_PJ, IF_REAL, "Perimeter factor"),
|
||||
IOPUR("perim", DIO_PJ, IF_REAL, "Perimeter factor"),
|
||||
IOPU("w", DIO_W, IF_REAL, "Diode width"),
|
||||
IOPU("l", DIO_L, IF_REAL, "Diode length"),
|
||||
IOPU("m", DIO_M, IF_REAL, "Multiplier"),
|
||||
|
|
@ -49,6 +50,7 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "is", DIO_MOD_IS, IF_REAL, "Saturation current"),
|
||||
IOPR( "js", DIO_MOD_IS, IF_REAL, "Saturation current"),
|
||||
IOP( "jsw", DIO_MOD_JSW, IF_REAL, "Sidewall Saturation current"),
|
||||
IOPR( "isw", DIO_MOD_JSW, IF_REAL, "Sidewall Saturation current"),
|
||||
|
||||
IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"),
|
||||
IOPUR("tref",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"),
|
||||
|
|
@ -73,6 +75,7 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "cjp", DIO_MOD_CJSW, IF_REAL, "Sidewall junction capacitance"),
|
||||
IOPR( "cjsw", DIO_MOD_CJSW, IF_REAL, "Sidewall junction capacitance"),
|
||||
IOP( "php", DIO_MOD_VJSW, IF_REAL, "Sidewall junction potential"),
|
||||
IOPR( "vjsw", DIO_MOD_VJSW, IF_REAL, "Sidewall junction potential"),
|
||||
IOP( "mjsw", DIO_MOD_MJSW, IF_REAL, "Sidewall Grading coefficient"),
|
||||
IOP( "ikf", DIO_MOD_IKF, IF_REAL, "Forward Knee current"),
|
||||
IOPR( "ik", DIO_MOD_IKF, IF_REAL, "Forward Knee current"),
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ IFparm VBICpTable[] = { /* parameters */
|
|||
OP("ib", VBIC_QUEST_CB, IF_REAL, "Base current"),
|
||||
OP("ie", VBIC_QUEST_CE, IF_REAL, "Emitter current"),
|
||||
OP("is", VBIC_QUEST_CS, IF_REAL, "Substrate current"),
|
||||
OP("p", VBIC_QUEST_POWER,IF_REAL, "Power dissipation"),
|
||||
OPR("power",VBIC_QUEST_POWER,IF_REAL, "Power dissipation"),
|
||||
OP("beta", VBIC_QUEST_BETA, IF_REAL, "CE current gain DC"),
|
||||
OPR("betad",VBIC_QUEST_BETA, IF_REAL, "CE current gain DC"),
|
||||
OP("gm", VBIC_QUEST_GM, IF_REAL, "Small signal transconductance dIc/dVbe"),
|
||||
OP("go", VBIC_QUEST_GO, IF_REAL, "Small signal output conductance dIc/dVbc"),
|
||||
OP("gpi", VBIC_QUEST_GPI, IF_REAL, "Small signal input conductance dIb/dVbe"),
|
||||
|
|
@ -53,15 +57,8 @@ IFparm VBICpTable[] = { /* parameters */
|
|||
OP("cbcx", VBIC_QUEST_CBCX, IF_REAL, "External Base to collector capacitance"),
|
||||
OP("cbep", VBIC_QUEST_CBEP, IF_REAL, "Parasitic Base to emitter capacitance"),
|
||||
OP("cbcp", VBIC_QUEST_CBCP, IF_REAL, "Parasitic Base to collector capacitance"),
|
||||
OP("p", VBIC_QUEST_POWER,IF_REAL, "Power dissipation"),
|
||||
OPU("geqcb",VBIC_QUEST_GEQCB,IF_REAL, "Internal C-B-base cap. equiv. cond."),
|
||||
OPU("geqbx",VBIC_QUEST_GEQBX,IF_REAL, "External C-B-base cap. equiv. cond."),
|
||||
OPU("qbe", VBIC_QUEST_QBE, IF_REAL, "Charge storage B-E junction"),
|
||||
OPU("cqbe", VBIC_QUEST_CQBE, IF_REAL, "Cap. due to charge storage in B-E jct."),
|
||||
OPU("qbc", VBIC_QUEST_QBC, IF_REAL, "Charge storage B-C junction"),
|
||||
OPU("cqbc", VBIC_QUEST_CQBC, IF_REAL, "Cap. due to charge storage in B-C jct."),
|
||||
OPU("qbx", VBIC_QUEST_QBX, IF_REAL, "Charge storage B-X junction"),
|
||||
OPU("cqbx", VBIC_QUEST_CQBX, IF_REAL, "Cap. due to charge storage in B-X jct.")
|
||||
};
|
||||
|
||||
IFparm VBICmPTable[] = { /* model parameters */
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ VBICacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
VBICinstance *here;
|
||||
VBICmodel *model = (VBICmodel*)inModel;
|
||||
double Ibe_Vbei,Ibex_Vbex
|
||||
,Itzf_Vbei,Itzf_Vbci,Itzr_Vbci,Itzr_Vbei,Ibc_Vbci
|
||||
,Iciei_Vbei,Iciei_Vbci,Ibc_Vbci
|
||||
,Ibc_Vbei,Ibep_Vbep,Ircx_Vrcx,Irci_Vrci
|
||||
,Irci_Vbci,Irci_Vbcx,Irbx_Vrbx,Irbi_Vrbi,Irbi_Vbei
|
||||
,Irbi_Vbci,Ire_Vre,Irbp_Vrbp,Irbp_Vbep,Irbp_Vbci
|
||||
|
|
@ -32,7 +32,7 @@ VBICacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
XQbcx_Vbcx, XQbep_Vbep, XQbep_Vbci,
|
||||
XQbcp_Vbcp, XQbeo_Vbe, XQbco_Vbc;
|
||||
|
||||
double Ibe_Vrth, Ibex_Vrth, Itzf_Vrth=0.0, Itzr_Vrth, Ibc_Vrth, Ibep_Vrth,
|
||||
double Ibe_Vrth, Ibex_Vrth, Iciei_Vrth, Iciei_Vxf2, Ibc_Vrth, Ibep_Vrth,
|
||||
Ircx_Vrth, Irci_Vrth, Irbx_Vrth, Irbi_Vrth, Ire_Vrth, Irbp_Vrth,
|
||||
Ibcp_Vrth, Iccp_Vrth, Irs_Vrth, Irth_Vrth, Ith_Vrth,
|
||||
Ith_Vbei, Ith_Vbci, Ith_Vcei, Ith_Vbex, Ith_Vbep, Ith_Vbcp, Ith_Vcep,
|
||||
|
|
@ -40,42 +40,60 @@ VBICacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double XQcth_Vrth, XQbe_Vrth, XQbex_Vrth, XQbc_Vrth, XQbcx_Vrth, XQbep_Vrth, XQbcp_Vrth;
|
||||
|
||||
//NQS
|
||||
double Itxf_Vrxf, Ibc_Vrxf, Ith_Vrxf, Ixzf_Vrth, Ixxf_Vrxf, XQcxf_Vcxf;
|
||||
double Ixzf_Vbei, Ixzf_Vbci, Xl;
|
||||
double XQxf1_Vxf1;
|
||||
double XQxf2_Vxf2;
|
||||
|
||||
double Ixf1_Vbei;
|
||||
double Ixf1_Vbci;
|
||||
double Ixf1_Vxf2;
|
||||
double Ixf1_Vxf1;
|
||||
double Ixf1_Vrth;
|
||||
|
||||
double Ixf2_Vxf2;
|
||||
double Ixf2_Vxf1;
|
||||
|
||||
/* loop through all the models */
|
||||
for( ; model != NULL; model = VBICnextModel(model)) {
|
||||
|
||||
/* loop through all the instances of the model */
|
||||
for( here = VBICinstances(model); here!= NULL;
|
||||
for( here = VBICinstances(model); here!= NULL;
|
||||
here = VBICnextInstance(here)) {
|
||||
|
||||
Ibe_Vbei = *(ckt->CKTstate0 + here->VBICibe_Vbei);
|
||||
Ibex_Vbex = *(ckt->CKTstate0 + here->VBICibex_Vbex);
|
||||
Itzf_Vbei = *(ckt->CKTstate0 + here->VBICitzf_Vbei);
|
||||
Itzf_Vbci = *(ckt->CKTstate0 + here->VBICitzf_Vbci);
|
||||
Itzr_Vbci = *(ckt->CKTstate0 + here->VBICitzr_Vbci);
|
||||
Itzr_Vbei = *(ckt->CKTstate0 + here->VBICitzr_Vbei);
|
||||
Ibc_Vbci = *(ckt->CKTstate0 + here->VBICibc_Vbci);
|
||||
Ibc_Vbei = *(ckt->CKTstate0 + here->VBICibc_Vbei);
|
||||
Ibep_Vbep = *(ckt->CKTstate0 + here->VBICibep_Vbep);
|
||||
Irci_Vrci = *(ckt->CKTstate0 + here->VBICirci_Vrci);
|
||||
Irci_Vbci = *(ckt->CKTstate0 + here->VBICirci_Vbci);
|
||||
Irci_Vbcx = *(ckt->CKTstate0 + here->VBICirci_Vbcx);
|
||||
Irbi_Vrbi = *(ckt->CKTstate0 + here->VBICirbi_Vrbi);
|
||||
Irbi_Vbei = *(ckt->CKTstate0 + here->VBICirbi_Vbei);
|
||||
Irbi_Vbci = *(ckt->CKTstate0 + here->VBICirbi_Vbci);
|
||||
Irbp_Vrbp = *(ckt->CKTstate0 + here->VBICirbp_Vrbp);
|
||||
Irbp_Vbep = *(ckt->CKTstate0 + here->VBICirbp_Vbep);
|
||||
Irbp_Vbci = *(ckt->CKTstate0 + here->VBICirbp_Vbci);
|
||||
Ibcp_Vbcp = *(ckt->CKTstate0 + here->VBICibcp_Vbcp);
|
||||
Iccp_Vbep = *(ckt->CKTstate0 + here->VBICiccp_Vbep);
|
||||
Iccp_Vbci = *(ckt->CKTstate0 + here->VBICiccp_Vbci);
|
||||
Iccp_Vbcp = *(ckt->CKTstate0 + here->VBICiccp_Vbcp);
|
||||
Ircx_Vrcx = *(ckt->CKTstate0 + here->VBICircx_Vrcx);
|
||||
Irbx_Vrbx = *(ckt->CKTstate0 + here->VBICirbx_Vrbx);
|
||||
Irs_Vrs = *(ckt->CKTstate0 + here->VBICirs_Vrs);
|
||||
Ire_Vre = *(ckt->CKTstate0 + here->VBICire_Vre);
|
||||
Ibe_Vbei = *(ckt->CKTstate0 + here->VBICibe_Vbei);
|
||||
Ibex_Vbex = *(ckt->CKTstate0 + here->VBICibex_Vbex);
|
||||
Iciei_Vbei = *(ckt->CKTstate0 + here->VBICiciei_Vbei);
|
||||
Iciei_Vbci = *(ckt->CKTstate0 + here->VBICiciei_Vbci);
|
||||
Iciei_Vrth = *(ckt->CKTstate0 + here->VBICiciei_Vrth);
|
||||
Iciei_Vxf2 = *(ckt->CKTstate0 + here->VBICiciei_Vxf2);
|
||||
Ibc_Vbci = *(ckt->CKTstate0 + here->VBICibc_Vbci);
|
||||
Ibc_Vbei = *(ckt->CKTstate0 + here->VBICibc_Vbei);
|
||||
Ibep_Vbep = *(ckt->CKTstate0 + here->VBICibep_Vbep);
|
||||
Irci_Vrci = *(ckt->CKTstate0 + here->VBICirci_Vrci);
|
||||
Irci_Vbci = *(ckt->CKTstate0 + here->VBICirci_Vbci);
|
||||
Irci_Vbcx = *(ckt->CKTstate0 + here->VBICirci_Vbcx);
|
||||
Irbi_Vrbi = *(ckt->CKTstate0 + here->VBICirbi_Vrbi);
|
||||
Irbi_Vbei = *(ckt->CKTstate0 + here->VBICirbi_Vbei);
|
||||
Irbi_Vbci = *(ckt->CKTstate0 + here->VBICirbi_Vbci);
|
||||
Irbp_Vrbp = *(ckt->CKTstate0 + here->VBICirbp_Vrbp);
|
||||
Irbp_Vbep = *(ckt->CKTstate0 + here->VBICirbp_Vbep);
|
||||
Irbp_Vbci = *(ckt->CKTstate0 + here->VBICirbp_Vbci);
|
||||
Ibcp_Vbcp = *(ckt->CKTstate0 + here->VBICibcp_Vbcp);
|
||||
Iccp_Vbep = *(ckt->CKTstate0 + here->VBICiccp_Vbep);
|
||||
Iccp_Vbci = *(ckt->CKTstate0 + here->VBICiccp_Vbci);
|
||||
Iccp_Vbcp = *(ckt->CKTstate0 + here->VBICiccp_Vbcp);
|
||||
Ircx_Vrcx = *(ckt->CKTstate0 + here->VBICircx_Vrcx);
|
||||
Irbx_Vrbx = *(ckt->CKTstate0 + here->VBICirbx_Vrbx);
|
||||
Irs_Vrs = *(ckt->CKTstate0 + here->VBICirs_Vrs);
|
||||
Ire_Vre = *(ckt->CKTstate0 + here->VBICire_Vre);
|
||||
|
||||
Ixf1_Vbei = *(ckt->CKTstate0 + here->VBICixf1_Vbei);
|
||||
Ixf1_Vbci = *(ckt->CKTstate0 + here->VBICixf1_Vbci);
|
||||
Ixf1_Vxf1 = *(ckt->CKTstate0 + here->VBICixf1_Vxf1);
|
||||
Ixf1_Vxf2 = *(ckt->CKTstate0 + here->VBICixf1_Vxf2);
|
||||
Ixf1_Vrth = *(ckt->CKTstate0 + here->VBICixf1_Vrth);
|
||||
|
||||
Ixf2_Vxf1 = *(ckt->CKTstate0 + here->VBICixf2_Vxf1);
|
||||
Ixf2_Vxf2 = *(ckt->CKTstate0 + here->VBICixf2_Vxf2);
|
||||
|
||||
/*
|
||||
c The real part
|
||||
|
|
@ -94,32 +112,22 @@ c Stamp element: Ibex
|
|||
*(here->VBICbaseBXEmitEIPtr) += -Ibex_Vbex;
|
||||
*(here->VBICemitEIBaseBXPtr) += -Ibex_Vbex;
|
||||
*(here->VBICemitEIEmitEIPtr) += Ibex_Vbex;
|
||||
|
||||
if (!here->VBIC_excessPhase) {
|
||||
/*
|
||||
c Stamp element: Itzf
|
||||
c Stamp element: Iciei
|
||||
*/
|
||||
*(here->VBICcollCIBaseBIPtr) += Itzf_Vbei;
|
||||
*(here->VBICcollCIEmitEIPtr) += -Itzf_Vbei;
|
||||
*(here->VBICcollCIBaseBIPtr) += Itzf_Vbci;
|
||||
*(here->VBICcollCICollCIPtr) += -Itzf_Vbci;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Itzf_Vbei;
|
||||
*(here->VBICemitEIEmitEIPtr) += Itzf_Vbei;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Itzf_Vbci;
|
||||
*(here->VBICemitEICollCIPtr) += Itzf_Vbci;
|
||||
*(here->VBICcollCIBaseBIPtr) += Iciei_Vbei;
|
||||
*(here->VBICcollCIEmitEIPtr) += -Iciei_Vbei;
|
||||
*(here->VBICcollCIBaseBIPtr) += Iciei_Vbci;
|
||||
*(here->VBICcollCICollCIPtr) += -Iciei_Vbci;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Iciei_Vbei;
|
||||
*(here->VBICemitEIEmitEIPtr) += Iciei_Vbei;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Iciei_Vbci;
|
||||
*(here->VBICemitEICollCIPtr) += Iciei_Vbci;
|
||||
if (here->VBIC_excessPhase) {
|
||||
*(here->VBICcollCIXf2Ptr) += Iciei_Vxf2;
|
||||
*(here->VBICemitEIXf2Ptr) += -Iciei_Vxf2;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Itzr
|
||||
*/
|
||||
*(here->VBICemitEIBaseBIPtr) += Itzr_Vbei;
|
||||
*(here->VBICemitEIEmitEIPtr) += -Itzr_Vbei;
|
||||
*(here->VBICemitEIBaseBIPtr) += Itzr_Vbci;
|
||||
*(here->VBICemitEICollCIPtr) += -Itzr_Vbci;
|
||||
*(here->VBICcollCIBaseBIPtr) += -Itzr_Vbei;
|
||||
*(here->VBICcollCIEmitEIPtr) += Itzr_Vbei;
|
||||
*(here->VBICcollCIBaseBIPtr) += -Itzr_Vbci;
|
||||
*(here->VBICcollCICollCIPtr) += Itzr_Vbci;
|
||||
/*
|
||||
c Stamp element: Ibc
|
||||
*/
|
||||
*(here->VBICbaseBIBaseBIPtr) += Ibc_Vbci;
|
||||
|
|
@ -145,7 +153,7 @@ c Stamp element: Rcx
|
|||
*(here->VBICcollCXCollPtr) += -Ircx_Vrcx;
|
||||
*(here->VBICcollCollCXPtr) += -Ircx_Vrcx;
|
||||
/*
|
||||
c Stamp element: Irci
|
||||
c Stamp element: Rci
|
||||
*/
|
||||
*(here->VBICcollCXCollCXPtr) += Irci_Vrci;
|
||||
*(here->VBICcollCXCollCIPtr) += -Irci_Vrci;
|
||||
|
|
@ -167,7 +175,7 @@ c Stamp element: Rbx
|
|||
*(here->VBICbaseBXBasePtr) += -Irbx_Vrbx;
|
||||
*(here->VBICbaseBaseBXPtr) += -Irbx_Vrbx;
|
||||
/*
|
||||
c Stamp element: Irbi
|
||||
c Stamp element: Rbi
|
||||
*/
|
||||
*(here->VBICbaseBXBaseBXPtr) += Irbi_Vrbi;
|
||||
*(here->VBICbaseBXBaseBIPtr) += -Irbi_Vrbi;
|
||||
|
|
@ -189,7 +197,7 @@ c Stamp element: Re
|
|||
*(here->VBICemitEIEmitPtr) += -Ire_Vre;
|
||||
*(here->VBICemitEmitEIPtr) += -Ire_Vre;
|
||||
/*
|
||||
c Stamp element: Irbp
|
||||
c Stamp element: Rbp
|
||||
*/
|
||||
*(here->VBICbaseBPBaseBPPtr) += Irbp_Vrbp;
|
||||
*(here->VBICbaseBPCollCXPtr) += -Irbp_Vrbp;
|
||||
|
|
@ -233,13 +241,23 @@ c Stamp element: Rs
|
|||
*(here->VBICsubsSISubsPtr) += -Irs_Vrs;
|
||||
*(here->VBICsubsSubsSIPtr) += -Irs_Vrs;
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
//Ixf1
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixf1_Vbei;
|
||||
*(here->VBICxf1EmitEIPtr) += -Ixf1_Vbei;
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixf1_Vbci;
|
||||
*(here->VBICxf1CollCIPtr) += -Ixf1_Vbci;
|
||||
*(here->VBICxf1Xf2Ptr) += +Ixf1_Vxf2;
|
||||
*(here->VBICxf1Xf1Ptr) += +Ixf1_Vxf1;
|
||||
//Ixf2
|
||||
*(here->VBICxf2Xf2Ptr) += +Ixf2_Vxf2;
|
||||
*(here->VBICxf2Xf1Ptr) += +Ixf2_Vxf1;
|
||||
}
|
||||
|
||||
if (here->VBIC_selfheat) {
|
||||
|
||||
Ibe_Vrth = here->VBICibe_Vrth;
|
||||
Ibex_Vrth = here->VBICibex_Vrth;
|
||||
if (!here->VBIC_excessPhase)
|
||||
Itzf_Vrth = here->VBICitzf_vrth;
|
||||
Itzr_Vrth = here->VBICitzr_Vrth;
|
||||
Ibc_Vrth = here->VBICibc_Vrth;
|
||||
Ibep_Vrth = here->VBICibep_Vrth;
|
||||
Ircx_Vrth = here->VBICircx_Vrth;
|
||||
|
|
@ -279,19 +297,11 @@ c Stamp element: Ibex
|
|||
*/
|
||||
*(here->VBICbaseBXtempPtr) += Ibex_Vrth;
|
||||
*(here->VBICemitEItempPtr) += -Ibex_Vrth;
|
||||
|
||||
if (!here->VBIC_excessPhase) {
|
||||
/*
|
||||
c Stamp element: Itzf
|
||||
c Stamp element: Iciei
|
||||
*/
|
||||
*(here->VBICcollCItempPtr) += Itzf_Vrth;
|
||||
*(here->VBICemitEItempPtr) += -Itzf_Vrth;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Itzr
|
||||
*/
|
||||
*(here->VBICemitEItempPtr) += Itzr_Vrth;
|
||||
*(here->VBICcollCItempPtr) += -Itzr_Vrth;
|
||||
*(here->VBICcollCItempPtr) += Iciei_Vrth;
|
||||
*(here->VBICemitEItempPtr) += -Iciei_Vrth;
|
||||
/*
|
||||
c Stamp element: Ibc
|
||||
*/
|
||||
|
|
@ -347,6 +357,11 @@ c Stamp element: Rs
|
|||
*/
|
||||
*(here->VBICsubsTempPtr) += Irs_Vrth;
|
||||
*(here->VBICsubsSItempPtr) += -Irs_Vrth;
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
// Stamp element: Ixf1 f_xf1 = +
|
||||
*(here->VBICxf1TempPtr) += Ixf1_Vrth;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Rth
|
||||
*/
|
||||
|
|
@ -386,44 +401,6 @@ c Stamp element: Ith
|
|||
*(here->VBICtempEmitEIPtr) += +Ith_Vre;
|
||||
*(here->VBICtempSubsPtr) += -Ith_Vrs;
|
||||
*(here->VBICtempSubsSIPtr) += +Ith_Vrs;
|
||||
if (here->VBIC_excessPhase) {
|
||||
Ith_Vrxf = *(ckt->CKTstate0 + here->VBICith_Vrxf);
|
||||
*(here->VBICtempXf2Ptr) += +Ith_Vrxf;
|
||||
}
|
||||
}
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
Itxf_Vrxf = *(ckt->CKTstate0 + here->VBICitxf_Vrxf);
|
||||
Ibc_Vrxf = *(ckt->CKTstate0 + here->VBICibc_Vrxf);
|
||||
Ixzf_Vbei = *(ckt->CKTstate0 + here->VBICixzf_Vbei);
|
||||
Ixzf_Vbci = *(ckt->CKTstate0 + here->VBICixzf_Vbci);
|
||||
Ixxf_Vrxf = *(ckt->CKTstate0 + here->VBICixxf_Vrxf);
|
||||
/*
|
||||
c Stamp element: Itxf
|
||||
*/
|
||||
*(here->VBICcollCIXf2Ptr) += Itxf_Vrxf;
|
||||
*(here->VBICemitEIXf2Ptr) += -Itxf_Vrxf;
|
||||
/*
|
||||
c Stamp element: Ibc
|
||||
*/
|
||||
*(here->VBICbaseBIXf2Ptr) += Ibc_Vrxf;
|
||||
*(here->VBICcollCIXf2Ptr) += -Ibc_Vrxf;
|
||||
/*
|
||||
c Stamp element: Ixzf, Branch: xf1-ground
|
||||
*/
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixzf_Vbei;
|
||||
*(here->VBICxf1EmitEIPtr) += -Ixzf_Vbei;
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixzf_Vbci;
|
||||
*(here->VBICxf1CollCIPtr) += -Ixzf_Vbci;
|
||||
if (here->VBIC_selfheat) {
|
||||
Ixzf_Vrth = *(ckt->CKTstate0 + here->VBICixzf_Vrth);
|
||||
*(here->VBICxf1TempPtr) += Ixzf_Vrth;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Ixxf, Branch: xf2-ground
|
||||
*/
|
||||
*(here->VBICxf2Xf2Ptr) += +Ixxf_Vrxf;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -439,6 +416,8 @@ c The complex part
|
|||
XQbcp_Vbcp = *(ckt->CKTstate0 + here->VBICcqbcp) * ckt->CKTomega;
|
||||
XQbeo_Vbe = *(ckt->CKTstate0 + here->VBICcqbeo) * ckt->CKTomega;
|
||||
XQbco_Vbc = *(ckt->CKTstate0 + here->VBICcqbco) * ckt->CKTomega;
|
||||
XQxf1_Vxf1 = *(ckt->CKTstate0 + here->VBICcqxf1) * ckt->CKTomega;
|
||||
XQxf2_Vxf2 = *(ckt->CKTstate0 + here->VBICcqxf2) * ckt->CKTomega;
|
||||
/*
|
||||
c Stamp element: Qbe
|
||||
*/
|
||||
|
|
@ -504,6 +483,13 @@ c Stamp element: Qbco
|
|||
*(here->VBICbaseCollPtr + 1) += -XQbco_Vbc;
|
||||
*(here->VBICcollBasePtr + 1) += -XQbco_Vbc;
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
//Qxf1
|
||||
*(here->VBICxf1Xf1Ptr + 1) += +XQxf1_Vxf1;
|
||||
//Qxf2
|
||||
*(here->VBICxf2Xf2Ptr + 1) += +XQxf2_Vxf2;
|
||||
}
|
||||
|
||||
if (here->VBIC_selfheat) {
|
||||
XQcth_Vrth = here->VBICcapcth * ckt->CKTomega;
|
||||
XQbe_Vrth = here->VBICcapqbeth * ckt->CKTomega;
|
||||
|
|
@ -528,24 +514,6 @@ c Stamp element: Qbco
|
|||
*(here->VBICsubsSItempPtr + 1) += XQbcp_Vrth;
|
||||
*(here->VBICbaseBPtempPtr + 1) += -XQbcp_Vrth;
|
||||
}
|
||||
if (here->VBIC_excessPhase) {
|
||||
/*
|
||||
c Stamp element: Qcxf
|
||||
*/
|
||||
XQcxf_Vcxf = here->VBICcapQcxf * ckt->CKTomega;
|
||||
*(here->VBICxf1Xf1Ptr + 1) += XQcxf_Vcxf;
|
||||
/*
|
||||
c Stamp element: L = TD/3
|
||||
*/
|
||||
Xl = here->VBICindInduct * ckt->CKTomega;
|
||||
|
||||
*(here->VBICxf1IbrPtr) += 1;
|
||||
*(here->VBICxf2IbrPtr) -= 1;
|
||||
*(here->VBICibrXf1Ptr) += 1;
|
||||
*(here->VBICibrXf2Ptr) -= 1;
|
||||
*(here->VBICibrIbrPtr + 1) -= Xl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ Spice3 Implementation: 2003 Dietmar Warning DAnalyse GmbH
|
|||
int
|
||||
VBICask(CKTcircuit *ckt, GENinstance *instPtr, int which, IFvalue *value, IFvalue *select)
|
||||
{
|
||||
IFvalue IC, IB, IE, IS;
|
||||
NG_IGNORE(select);
|
||||
VBICinstance *here = (VBICinstance*)instPtr;
|
||||
|
||||
IFvalue IC, IB;
|
||||
|
||||
switch(which) {
|
||||
case VBIC_AREA:
|
||||
value->rValue = here->VBICarea;
|
||||
|
|
@ -75,14 +77,9 @@ VBICask(CKTcircuit *ckt, GENinstance *instPtr, int which, IFvalue *value, IFvalu
|
|||
value->rValue = *(ckt->CKTstate0 + here->VBICvbci);
|
||||
return(OK);
|
||||
case VBIC_QUEST_CC:
|
||||
if (!here->VBIC_excessPhase)
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICitzf) -
|
||||
*(ckt->CKTstate0 + here->VBICitzr) -
|
||||
*(ckt->CKTstate0 + here->VBICibc);
|
||||
else
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICitxf) -
|
||||
*(ckt->CKTstate0 + here->VBICitzr) -
|
||||
*(ckt->CKTstate0 + here->VBICibc);
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICiciei) -
|
||||
*(ckt->CKTstate0 + here->VBICiccp) -
|
||||
*(ckt->CKTstate0 + here->VBICibc);
|
||||
value->rValue *= VBICmodPtr(here)->VBICtype;
|
||||
return(OK);
|
||||
case VBIC_QUEST_CB:
|
||||
|
|
@ -94,16 +91,9 @@ VBICask(CKTcircuit *ckt, GENinstance *instPtr, int which, IFvalue *value, IFvalu
|
|||
value->rValue *= VBICmodPtr(here)->VBICtype;
|
||||
return(OK);
|
||||
case VBIC_QUEST_CE:
|
||||
if (!here->VBIC_excessPhase)
|
||||
value->rValue = - *(ckt->CKTstate0 + here->VBICibe) -
|
||||
*(ckt->CKTstate0 + here->VBICibex) -
|
||||
*(ckt->CKTstate0 + here->VBICitzf) +
|
||||
*(ckt->CKTstate0 + here->VBICitzr);
|
||||
else
|
||||
value->rValue = - *(ckt->CKTstate0 + here->VBICibe) -
|
||||
*(ckt->CKTstate0 + here->VBICibex) -
|
||||
*(ckt->CKTstate0 + here->VBICitxf) +
|
||||
*(ckt->CKTstate0 + here->VBICitzr);
|
||||
value->rValue = - *(ckt->CKTstate0 + here->VBICibe) -
|
||||
*(ckt->CKTstate0 + here->VBICibex) -
|
||||
*(ckt->CKTstate0 + here->VBICiciei);
|
||||
value->rValue *= VBICmodPtr(here)->VBICtype;
|
||||
return(OK);
|
||||
case VBIC_QUEST_CS:
|
||||
|
|
@ -112,48 +102,22 @@ VBICask(CKTcircuit *ckt, GENinstance *instPtr, int which, IFvalue *value, IFvalu
|
|||
value->rValue *= VBICmodPtr(here)->VBICtype;
|
||||
return(OK);
|
||||
case VBIC_QUEST_POWER:
|
||||
value->rValue = fabs(here->VBICpower);
|
||||
return(OK);
|
||||
case VBIC_QUEST_BETA:
|
||||
VBICask(ckt, instPtr, VBIC_QUEST_CC, &IC, select);
|
||||
VBICask(ckt, instPtr, VBIC_QUEST_CB, &IB, select);
|
||||
VBICask(ckt, instPtr, VBIC_QUEST_CE, &IE, select);
|
||||
VBICask(ckt, instPtr, VBIC_QUEST_CS, &IS, select);
|
||||
if (!here->VBIC_excessPhase)
|
||||
value->rValue = fabs(*(ckt->CKTstate0 + here->VBICibe) * *(ckt->CKTstate0 + here->VBICvbei)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibc) * *(ckt->CKTstate0 + here->VBICvbci)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICitzf) - *(ckt->CKTstate0 + here->VBICitzr))
|
||||
* fabs(*(ckt->CKTstate0 + here->VBICvbei) - *(ckt->CKTstate0 + here->VBICvbci)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibex) * *(ckt->CKTstate0 + here->VBICvbex)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibep) * *(ckt->CKTstate0 + here->VBICvbep)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibcp) * *(ckt->CKTstate0 + here->VBICvbcp)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICiccp))
|
||||
* fabs(*(ckt->CKTstate0 + here->VBICvbep) - *(ckt->CKTstate0 + here->VBICvbcp)) +
|
||||
fabs(IC.rValue * IC.rValue * here->VBICtextCollResist) +
|
||||
fabs(IC.rValue * *(ckt->CKTstate0 + here->VBICvrci)) +
|
||||
fabs(IB.rValue * IB.rValue * here->VBICtextBaseResist) +
|
||||
fabs(IB.rValue * *(ckt->CKTstate0 + here->VBICvrbi)) +
|
||||
fabs(IE.rValue * IE.rValue * here->VBICtemitterResist) +
|
||||
fabs(IS.rValue * *(ckt->CKTstate0 + here->VBICvrbp));
|
||||
else
|
||||
value->rValue = fabs(*(ckt->CKTstate0 + here->VBICibe) * *(ckt->CKTstate0 + here->VBICvbei)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibc) * *(ckt->CKTstate0 + here->VBICvbci)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICitxf) - *(ckt->CKTstate0 + here->VBICitzr))
|
||||
* fabs(*(ckt->CKTstate0 + here->VBICvbei) - *(ckt->CKTstate0 + here->VBICvbci)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibex) * *(ckt->CKTstate0 + here->VBICvbex)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibep) * *(ckt->CKTstate0 + here->VBICvbep)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICibcp) * *(ckt->CKTstate0 + here->VBICvbcp)) +
|
||||
fabs(*(ckt->CKTstate0 + here->VBICiccp))
|
||||
* fabs(*(ckt->CKTstate0 + here->VBICvbep) - *(ckt->CKTstate0 + here->VBICvbcp)) +
|
||||
fabs(IC.rValue * IC.rValue * here->VBICtextCollResist) +
|
||||
fabs(IC.rValue * *(ckt->CKTstate0 + here->VBICvrci)) +
|
||||
fabs(IB.rValue * IB.rValue * here->VBICtextBaseResist) +
|
||||
fabs(IB.rValue * *(ckt->CKTstate0 + here->VBICvrbi)) +
|
||||
fabs(IE.rValue * IE.rValue * here->VBICtemitterResist) +
|
||||
fabs(IS.rValue * *(ckt->CKTstate0 + here->VBICvrbp));
|
||||
if (IB.rValue != 0.0) {
|
||||
value->rValue = IC.rValue/IB.rValue;
|
||||
} else {
|
||||
value->rValue = 0.0;
|
||||
}
|
||||
return(OK);
|
||||
case VBIC_QUEST_GM:
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICitzf_Vbei);
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICiciei_Vbei);
|
||||
return(OK);
|
||||
case VBIC_QUEST_GO:
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICitzf_Vbci);
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICiciei_Vbci);
|
||||
return(OK);
|
||||
case VBIC_QUEST_GPI:
|
||||
value->rValue = *(ckt->CKTstate0 + here->VBICibe_Vbei);
|
||||
|
|
|
|||
|
|
@ -104,27 +104,21 @@ VBICbindCSC (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CREATE_KLU_BINDING_TABLE(VBICtempSubsSIPtr, VBICtempSubsSIBinding, VBICtempNode, VBICsubsSINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICtempTempPtr, VBICtempTempBinding, VBICtempNode, VBICtempNode);
|
||||
if (here->VBIC_excessPhase) {
|
||||
CREATE_KLU_BINDING_TABLE(VBICtempXf2Ptr, VBICtempXf2Binding, VBICtempNode, VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1TempPtr, VBICxf1TempBinding, VBICxf1Node ,VBICtempNode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1TempPtr, VBICxf1TempBinding, VBICxf1Node, VBICtempNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1Xf1Ptr , VBICxf1Xf1Binding , VBICxf1Node , VBICxf1Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1Xf2Ptr , VBICxf1Xf2Binding , VBICxf1Node , VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1CollCIPtr, VBICxf1CollCIBinding, VBICxf1Node , VBICcollCINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1BaseBIPtr, VBICxf1BaseBIBinding, VBICxf1Node , VBICbaseBINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1EmitEIPtr, VBICxf1EmitEIBinding, VBICxf1Node , VBICemitEINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf2Xf2Ptr , VBICxf2Xf2Binding , VBICxf2Node , VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf2Xf1Ptr , VBICxf2Xf1Binding , VBICxf2Node , VBICxf1Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICcollCIXf2Ptr, VBICcollCIXf2Binding, VBICcollCINode, VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICbaseBIXf2Ptr, VBICbaseBIXf2Binding, VBICbaseBINode, VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1Xf1Ptr, VBICxf1Xf1Binding, VBICxf1Node, VBICxf1Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1BaseBIPtr, VBICxf1BaseBIBinding, VBICxf1Node, VBICbaseBINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1EmitEIPtr, VBICxf1EmitEIBinding, VBICxf1Node, VBICemitEINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1CollCIPtr, VBICxf1CollCIBinding, VBICxf1Node, VBICcollCINode);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1Xf2Ptr, VBICxf1Xf2Binding, VBICxf1Node, VBICxf2Node);
|
||||
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf2Xf1Ptr, VBICxf2Xf1Binding, VBICxf2Node, VBICxf1Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf2Xf2Ptr, VBICxf2Xf2Binding, VBICxf2Node, VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICemitEIXf2Ptr, VBICemitEIXf2Binding, VBICemitEINode, VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf1IbrPtr , VBICxf1IbrBinding , VBICxf1Node , VBICbrEq);
|
||||
CREATE_KLU_BINDING_TABLE(VBICxf2IbrPtr , VBICxf2IbrBinding , VBICxf2Node , VBICbrEq);
|
||||
CREATE_KLU_BINDING_TABLE(VBICibrXf2Ptr , VBICibrXf2Binding , VBICbrEq , VBICxf2Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICibrXf1Ptr , VBICibrXf1Binding , VBICbrEq , VBICxf1Node);
|
||||
CREATE_KLU_BINDING_TABLE(VBICibrIbrPtr , VBICibrIbrBinding , VBICbrEq , VBICbrEq);
|
||||
CREATE_KLU_BINDING_TABLE(VBICcollCIXf2Ptr, VBICcollCIXf2Binding, VBICcollCINode, VBICxf2Node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -223,25 +217,21 @@ VBICbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICtempSubsPtr, VBICtempSubsBinding, VBICtempNode, VBICsubsNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICtempSubsSIPtr, VBICtempSubsSIBinding, VBICtempNode, VBICsubsSINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICtempTempPtr, VBICtempTempBinding, VBICtempNode, VBICtempNode);
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf1Xf1Ptr , VBICxf1Xf1Binding , VBICxf1Node , VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf1Xf2Ptr , VBICxf1Xf2Binding , VBICxf1Node , VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf1CollCIPtr, VBICxf1CollCIBinding, VBICxf1Node , VBICcollCINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf1BaseBIPtr, VBICxf1BaseBIBinding, VBICxf1Node , VBICbaseBINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf1EmitEIPtr, VBICxf1EmitEIBinding, VBICxf1Node , VBICemitEINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf2Xf2Ptr , VBICxf2Xf2Binding , VBICxf2Node , VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf2Xf1Ptr , VBICxf2Xf1Binding , VBICxf2Node , VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICcollCIXf2Ptr, VBICcollCIXf2Binding, VBICcollCINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICbaseBIXf2Ptr, VBICbaseBIXf2Binding, VBICbaseBINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICemitEIXf2Ptr, VBICemitEIXf2Binding, VBICemitEINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf1IbrPtr , VBICxf1IbrBinding , VBICxf1Node , VBICbrEq);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICxf2IbrPtr , VBICxf2IbrBinding , VBICxf2Node , VBICbrEq);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICibrXf2Ptr , VBICibrXf2Binding , VBICbrEq , VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICibrXf1Ptr , VBICibrXf1Binding , VBICbrEq , VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VBICibrIbrPtr , VBICibrIbrBinding , VBICbrEq , VBICbrEq);
|
||||
if (here->VBIC_excessPhase) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1TempPtr, VBICxf1TempBinding, VBICxf1Node, VBICtempNode);
|
||||
}
|
||||
}
|
||||
if (here->VBIC_excessPhase) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1Xf1Ptr, VBICxf1Xf1Binding, VBICxf1Node, VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1BaseBIPtr, VBICxf1BaseBIBinding, VBICxf1Node, VBICbaseBINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1EmitEIPtr, VBICxf1EmitEIBinding, VBICxf1Node, VBICemitEINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1CollCIPtr, VBICxf1CollCIBinding, VBICxf1Node, VBICcollCINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1Xf2Ptr, VBICxf1Xf2Binding, VBICxf1Node, VBICxf2Node);
|
||||
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2Xf1Ptr, VBICxf2Xf1Binding, VBICxf2Node, VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2Xf2Ptr, VBICxf2Xf2Binding, VBICxf2Node, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICemitEIXf2Ptr, VBICemitEIXf2Binding, VBICemitEINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICcollCIXf2Ptr, VBICcollCIXf2Binding, VBICcollCINode, VBICxf2Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -339,24 +329,22 @@ VBICbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICtempSubsPtr, VBICtempSubsBinding, VBICtempNode, VBICsubsNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICtempSubsSIPtr, VBICtempSubsSIBinding, VBICtempNode, VBICsubsSINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICtempTempPtr, VBICtempTempBinding, VBICtempNode, VBICtempNode);
|
||||
if (here->VBIC_excessPhase) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1TempPtr, VBICxf1TempBinding, VBICxf1Node, VBICtempNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1Xf1Ptr , VBICxf1Xf1Binding , VBICxf1Node , VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1Xf2Ptr , VBICxf1Xf2Binding , VBICxf1Node , VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1CollCIPtr, VBICxf1CollCIBinding, VBICxf1Node , VBICcollCINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1BaseBIPtr, VBICxf1BaseBIBinding, VBICxf1Node , VBICbaseBINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1EmitEIPtr, VBICxf1EmitEIBinding, VBICxf1Node , VBICemitEINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2Xf2Ptr , VBICxf2Xf2Binding , VBICxf2Node , VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2Xf1Ptr , VBICxf2Xf1Binding , VBICxf2Node , VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICcollCIXf2Ptr, VBICcollCIXf2Binding, VBICcollCINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICbaseBIXf2Ptr, VBICbaseBIXf2Binding, VBICbaseBINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1Xf1Ptr, VBICxf1Xf1Binding, VBICxf1Node, VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1BaseBIPtr, VBICxf1BaseBIBinding, VBICxf1Node, VBICbaseBINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1EmitEIPtr, VBICxf1EmitEIBinding, VBICxf1Node, VBICemitEINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1CollCIPtr, VBICxf1CollCIBinding, VBICxf1Node, VBICcollCINode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1Xf2Ptr, VBICxf1Xf2Binding, VBICxf1Node, VBICxf2Node);
|
||||
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2Xf1Ptr, VBICxf2Xf1Binding, VBICxf2Node, VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2Xf2Ptr, VBICxf2Xf2Binding, VBICxf2Node, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICemitEIXf2Ptr, VBICemitEIXf2Binding, VBICemitEINode, VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf1IbrPtr , VBICxf1IbrBinding , VBICxf1Node , VBICbrEq);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICxf2IbrPtr , VBICxf2IbrBinding , VBICxf2Node , VBICbrEq);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICibrXf2Ptr , VBICibrXf2Binding , VBICbrEq , VBICxf2Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICibrXf1Ptr , VBICibrXf1Binding , VBICbrEq , VBICxf1Node);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICibrIbrPtr , VBICibrIbrBinding , VBICbrEq , VBICbrEq);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VBICcollCIXf2Ptr, VBICcollCIXf2Binding, VBICcollCINode, VBICxf2Node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ VBICconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double delvbcp;
|
||||
double ibehat;
|
||||
double ibexhat;
|
||||
double itzfhat;
|
||||
double itzrhat;
|
||||
double icieihat;
|
||||
double ibchat;
|
||||
double ibephat;
|
||||
double ircihat;
|
||||
|
|
@ -43,7 +42,7 @@ VBICconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double ibcphat;
|
||||
double iccphat;
|
||||
double Vbei, Vbex, Vbci, Vbcx, Vbep, Vrci, Vrbi, Vrbp, Vbcp;
|
||||
double Ibe, Ibex, Itzf, Itzr, Ibc, Ibep, Irci, Irbi, Irbp, Ibcp, Iccp;
|
||||
double Ibe, Ibex, Iciei, Ibc, Ibep, Irci, Irbi, Irbp, Ibcp, Iccp;
|
||||
|
||||
for( ; model != NULL; model = VBICnextModel(model)) {
|
||||
for(here=VBICinstances(model);here!=NULL;here = VBICnextInstance(here)) {
|
||||
|
|
@ -88,10 +87,8 @@ VBICconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate0 + here->VBICibe_Vbei)*delvbei;
|
||||
ibexhat = *(ckt->CKTstate0 + here->VBICibex) +
|
||||
*(ckt->CKTstate0 + here->VBICibex_Vbex)*delvbex;
|
||||
itzfhat = *(ckt->CKTstate0 + here->VBICitzf) +
|
||||
*(ckt->CKTstate0 + here->VBICitzf_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICitzf_Vbci)*delvbci;
|
||||
itzrhat = *(ckt->CKTstate0 + here->VBICitzr) +
|
||||
*(ckt->CKTstate0 + here->VBICitzr_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICitzr_Vbci)*delvbci;
|
||||
icieihat = *(ckt->CKTstate0 + here->VBICiciei) +
|
||||
*(ckt->CKTstate0 + here->VBICiciei_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICiciei_Vbci)*delvbci;
|
||||
ibchat = *(ckt->CKTstate0 + here->VBICibc) +
|
||||
*(ckt->CKTstate0 + here->VBICibc_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICibc_Vbci)*delvbci;
|
||||
ibephat = *(ckt->CKTstate0 + here->VBICibep) +
|
||||
|
|
@ -108,8 +105,7 @@ VBICconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate0 + here->VBICiccp_Vbci)*delvbci + *(ckt->CKTstate0 + here->VBICiccp_Vbcp)*delvbcp;
|
||||
Ibe = *(ckt->CKTstate0 + here->VBICibe);
|
||||
Ibex = *(ckt->CKTstate0 + here->VBICibex);
|
||||
Itzf = *(ckt->CKTstate0 + here->VBICitzf);
|
||||
Itzr = *(ckt->CKTstate0 + here->VBICitzr);
|
||||
Iciei = *(ckt->CKTstate0 + here->VBICiciei);
|
||||
Ibc = *(ckt->CKTstate0 + here->VBICibc);
|
||||
Ibep = *(ckt->CKTstate0 + here->VBICibep);
|
||||
Irci = *(ckt->CKTstate0 + here->VBICirci);
|
||||
|
|
@ -132,60 +128,53 @@ VBICconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(itzfhat),fabs(Itzf))+ckt->CKTabstol;
|
||||
if (fabs(itzfhat-Itzf) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(icieihat),fabs(Iciei))+ckt->CKTabstol;
|
||||
if (fabs(icieihat-Iciei) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(itzrhat),fabs(Itzr))+ckt->CKTabstol;
|
||||
if (fabs(itzrhat-Itzr) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ibchat),fabs(Ibc))+ckt->CKTabstol;
|
||||
if (fabs(ibchat-Ibc) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ibchat),fabs(Ibc))+ckt->CKTabstol;
|
||||
if (fabs(ibchat-Ibc) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ibephat),fabs(Ibep))+ckt->CKTabstol;
|
||||
if (fabs(ibephat-Ibep) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ibephat),fabs(Ibep))+ckt->CKTabstol;
|
||||
if (fabs(ibephat-Ibep) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ircihat),fabs(Irci))+ckt->CKTabstol;
|
||||
if (fabs(ircihat-Irci) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ircihat),fabs(Irci))+ckt->CKTabstol;
|
||||
if (fabs(ircihat-Irci) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(irbihat),fabs(Irbi))+ckt->CKTabstol;
|
||||
if (fabs(irbihat-Irbi) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(irbihat),fabs(Irbi))+ckt->CKTabstol;
|
||||
if (fabs(irbihat-Irbi) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(irbphat),fabs(Irbp))+ckt->CKTabstol;
|
||||
if (fabs(irbphat-Irbp) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(irbphat),fabs(Irbp))+ckt->CKTabstol;
|
||||
if (fabs(irbphat-Irbp) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ibcphat),fabs(Ibcp))+ckt->CKTabstol;
|
||||
if (fabs(ibcphat-Ibcp) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(ibcphat),fabs(Ibcp))+ckt->CKTabstol;
|
||||
if (fabs(ibcphat-Ibcp) > tol) {
|
||||
tol=ckt->CKTreltol*MAX(fabs(iccphat),fabs(Iccp))+ckt->CKTabstol;
|
||||
if (fabs(iccphat-Iccp) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
} else {
|
||||
tol=ckt->CKTreltol*MAX(fabs(iccphat),fabs(Iccp))+ckt->CKTabstol;
|
||||
if (fabs(iccphat-Iccp) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ typedef struct sVBICinstance {
|
|||
int VBICsubsSINode; /* number of internal substrate node */
|
||||
int VBICxf1Node; /* number of internal excess phase 1 node itf */
|
||||
int VBICxf2Node; /* number of internal excess phase 2 node itf */
|
||||
int VBICbrEq; /* number of the branch equation added for current */
|
||||
|
||||
double VBICarea; /* area factor for the vbic */
|
||||
double VBICicVBE; /* initial condition voltage B-E*/
|
||||
|
|
@ -241,26 +240,22 @@ typedef struct sVBICinstance {
|
|||
double *VBICtempTempPtr;
|
||||
|
||||
/* excess phase */
|
||||
double *VBICtempXf2Ptr;
|
||||
double *VBICxf1TempPtr;
|
||||
|
||||
double *VBICxf1Xf1Ptr;
|
||||
double *VBICxf1Xf2Ptr;
|
||||
double *VBICxf1CollCIPtr;
|
||||
double *VBICxf1TempPtr;
|
||||
double *VBICxf1BaseBIPtr;
|
||||
double *VBICxf1EmitEIPtr;
|
||||
double *VBICxf1CollCIPtr;
|
||||
double *VBICxf1Xf2Ptr;
|
||||
|
||||
double *VBICxf2Xf2Ptr;
|
||||
double *VBICxf2Xf1Ptr;
|
||||
double *VBICcollCIXf2Ptr;
|
||||
double *VBICbaseBIXf2Ptr;
|
||||
double *VBICxf2TempPtr;
|
||||
double *VBICxf2BaseBIPtr;
|
||||
double *VBICxf2EmitEIPtr;
|
||||
double *VBICxf2CollCIPtr;
|
||||
double *VBICxf2Xf2Ptr;
|
||||
double *VBICemitXf2Ptr;
|
||||
double *VBICemitEIXf2Ptr;
|
||||
|
||||
double *VBICxf1IbrPtr;
|
||||
double *VBICxf2IbrPtr;
|
||||
double *VBICibrXf1Ptr;
|
||||
double *VBICibrXf2Ptr;
|
||||
double *VBICibrIbrPtr;
|
||||
double *VBICcollCIXf2Ptr;
|
||||
|
||||
unsigned VBICareaGiven :1; /* flag to indicate area was specified */
|
||||
unsigned VBICoff :1; /* 'off' flag for vbic */
|
||||
|
|
@ -287,8 +282,6 @@ typedef struct sVBICinstance {
|
|||
|
||||
double VBICibe_Vrth;
|
||||
double VBICibex_Vrth;
|
||||
double VBICitzf_vrth;
|
||||
double VBICitzr_Vrth;
|
||||
double VBICibc_Vrth;
|
||||
double VBICibep_Vrth;
|
||||
double VBICircx_Vrth;
|
||||
|
|
@ -319,8 +312,7 @@ typedef struct sVBICinstance {
|
|||
double VBICith_Vre;
|
||||
double VBICith_Vrs;
|
||||
|
||||
double VBICindInduct;
|
||||
double VBICcapQcxf;
|
||||
double VBICpower;
|
||||
|
||||
int VBIC_selfheat; /* self-heating enabled */
|
||||
int VBIC_excessPhase; /* excess phase enabled */
|
||||
|
|
@ -411,24 +403,17 @@ typedef struct sVBICinstance {
|
|||
BindElement *VBICtempSubsSIBinding ;
|
||||
BindElement *VBICtempTempBinding ;
|
||||
|
||||
BindElement *VBICtempXf2Binding ;
|
||||
BindElement *VBICxf1TempBinding ;
|
||||
BindElement *VBICcollCIXf2Binding ;
|
||||
BindElement *VBICemitEIXf2Binding ;
|
||||
|
||||
BindElement *VBICxf1BaseBIBinding ;
|
||||
BindElement *VBICxf1CollCIBinding ;
|
||||
BindElement *VBICxf1EmitEIBinding ;
|
||||
BindElement *VBICxf1TempBinding ;
|
||||
BindElement *VBICxf1Xf1Binding ;
|
||||
BindElement *VBICxf1Xf2Binding ;
|
||||
BindElement *VBICxf1CollCIBinding ;
|
||||
BindElement *VBICxf1BaseBIBinding ;
|
||||
BindElement *VBICxf1EmitEIBinding ;
|
||||
BindElement *VBICxf2Xf2Binding ;
|
||||
BindElement *VBICxf2Xf1Binding ;
|
||||
BindElement *VBICcollCIXf2Binding ;
|
||||
BindElement *VBICbaseBIXf2Binding ;
|
||||
BindElement *VBICemitEIXf2Binding ;
|
||||
BindElement *VBICxf1IbrBinding ;
|
||||
BindElement *VBICxf2IbrBinding ;
|
||||
BindElement *VBICibrXf2Binding ;
|
||||
BindElement *VBICibrXf1Binding ;
|
||||
BindElement *VBICibrIbrBinding ;
|
||||
BindElement *VBICxf2Xf2Binding ;
|
||||
#endif
|
||||
|
||||
} VBICinstance ;
|
||||
|
|
@ -444,21 +429,20 @@ typedef struct sVBICinstance {
|
|||
#define VBICvrbi VBICstate+6
|
||||
#define VBICvrbp VBICstate+7
|
||||
#define VBICvbcp VBICstate+8
|
||||
#define VBICvxf1 VBICstate+9
|
||||
#define VBICvxf2 VBICstate+10
|
||||
|
||||
#define VBICibe VBICstate+9
|
||||
#define VBICibe_Vbei VBICstate+10
|
||||
#define VBICibe VBICstate+11
|
||||
#define VBICibe_Vbei VBICstate+12
|
||||
|
||||
#define VBICibex VBICstate+11
|
||||
#define VBICibex_Vbex VBICstate+12
|
||||
#define VBICibex VBICstate+13
|
||||
#define VBICibex_Vbex VBICstate+14
|
||||
|
||||
#define VBICitzf VBICstate+13
|
||||
#define VBICitzf_Vbei VBICstate+14
|
||||
#define VBICitzf_Vbci VBICstate+15
|
||||
#define VBICitzf_Vrth VBICstate+16
|
||||
|
||||
#define VBICitzr VBICstate+17
|
||||
#define VBICitzr_Vbci VBICstate+18
|
||||
#define VBICitzr_Vbei VBICstate+19
|
||||
#define VBICiciei VBICstate+15
|
||||
#define VBICiciei_Vbei VBICstate+16
|
||||
#define VBICiciei_Vbci VBICstate+17
|
||||
#define VBICiciei_Vrth VBICstate+18
|
||||
#define VBICiciei_Vxf2 VBICstate+19
|
||||
|
||||
#define VBICibc VBICstate+20
|
||||
#define VBICibc_Vbci VBICstate+21
|
||||
|
|
@ -482,7 +466,6 @@ typedef struct sVBICinstance {
|
|||
#define VBICirbp_Vbep VBICstate+35
|
||||
#define VBICirbp_Vbci VBICstate+36
|
||||
|
||||
|
||||
#define VBICqbe VBICstate+37
|
||||
#define VBICcqbe VBICstate+38
|
||||
#define VBICcqbeci VBICstate+39
|
||||
|
|
@ -530,26 +513,24 @@ typedef struct sVBICinstance {
|
|||
#define VBICvrth VBICstate+69
|
||||
#define VBICicth_Vrth VBICstate+70
|
||||
|
||||
#define VBICqcxf VBICstate+71
|
||||
#define VBICcqcxf VBICstate+72
|
||||
#define VBICgqcxf VBICstate+73
|
||||
#define VBICqxf1 VBICstate+71
|
||||
#define VBICcqxf1 VBICstate+72
|
||||
#define VBICgqxf1 VBICstate+73
|
||||
|
||||
#define VBICibc_Vrxf VBICstate+74
|
||||
#define VBICixf1 VBICstate+74
|
||||
#define VBICixf1_Vbei VBICstate+75
|
||||
#define VBICixf1_Vbci VBICstate+76
|
||||
#define VBICixf1_Vxf1 VBICstate+77
|
||||
#define VBICixf1_Vxf2 VBICstate+78
|
||||
#define VBICixf1_Vrth VBICstate+79
|
||||
|
||||
#define VBICixzf VBICstate+75
|
||||
#define VBICixzf_Vbei VBICstate+76
|
||||
#define VBICixzf_Vbci VBICstate+77
|
||||
#define VBICixzf_Vrth VBICstate+78
|
||||
#define VBICqxf2 VBICstate+80
|
||||
#define VBICcqxf2 VBICstate+81
|
||||
#define VBICgqxf2 VBICstate+82
|
||||
|
||||
#define VBICixxf VBICstate+79
|
||||
#define VBICixxf_Vrxf VBICstate+80
|
||||
|
||||
#define VBICitxf VBICstate+81
|
||||
#define VBICitxf_Vrxf VBICstate+82
|
||||
#define VBICith_Vrxf VBICstate+83
|
||||
|
||||
#define VBICindFlux VBICstate+84
|
||||
#define VBICindVolt VBICstate+85
|
||||
#define VBICixf2 VBICstate+83
|
||||
#define VBICixf2_Vxf1 VBICstate+84
|
||||
#define VBICixf2_Vxf2 VBICstate+85
|
||||
|
||||
#define VBICnumStates 86
|
||||
|
||||
|
|
@ -945,8 +926,7 @@ enum {
|
|||
|
||||
/* device questions */
|
||||
enum {
|
||||
VBIC_QUEST_FT = 221,
|
||||
VBIC_QUEST_COLLNODE,
|
||||
VBIC_QUEST_COLLNODE = 221,
|
||||
VBIC_QUEST_BASENODE,
|
||||
VBIC_QUEST_EMITNODE,
|
||||
VBIC_QUEST_SUBSNODE,
|
||||
|
|
@ -963,31 +943,21 @@ enum {
|
|||
VBIC_QUEST_CB,
|
||||
VBIC_QUEST_CE,
|
||||
VBIC_QUEST_CS,
|
||||
VBIC_QUEST_POWER,
|
||||
VBIC_QUEST_BETA,
|
||||
VBIC_QUEST_GM,
|
||||
VBIC_QUEST_GO,
|
||||
VBIC_QUEST_GPI,
|
||||
VBIC_QUEST_GMU,
|
||||
VBIC_QUEST_GX,
|
||||
VBIC_QUEST_QBE,
|
||||
VBIC_QUEST_CQBE,
|
||||
VBIC_QUEST_QBC,
|
||||
VBIC_QUEST_CQBC,
|
||||
VBIC_QUEST_QBX,
|
||||
VBIC_QUEST_CQBX,
|
||||
VBIC_QUEST_QBCP,
|
||||
VBIC_QUEST_CQBCP,
|
||||
VBIC_QUEST_CEXBC,
|
||||
VBIC_QUEST_GEQCB,
|
||||
VBIC_QUEST_GCSUB,
|
||||
VBIC_QUEST_GDSUB,
|
||||
VBIC_QUEST_GEQBX,
|
||||
VBIC_QUEST_CBE,
|
||||
VBIC_QUEST_CBEX,
|
||||
VBIC_QUEST_CBC,
|
||||
VBIC_QUEST_CBCX,
|
||||
VBIC_QUEST_CBEP,
|
||||
VBIC_QUEST_CBCP,
|
||||
VBIC_QUEST_POWER,
|
||||
VBIC_QUEST_QBE,
|
||||
VBIC_QUEST_QBC,
|
||||
};
|
||||
|
||||
/* model questions */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -127,16 +127,10 @@ VBICnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *
|
|||
ckt,THERMNOISE,inst->VBICsubsSINode,inst->VBICsubsNode,
|
||||
*(ckt->CKTstate0 + inst->VBICirs_Vrs), dtemp);
|
||||
|
||||
if (!inst->VBIC_excessPhase) {
|
||||
NevalSrc(&noizDens[VBICICNOIZ],&lnNdens[VBICICNOIZ],
|
||||
ckt,SHOTNOISE,inst->VBICcollCINode, inst->VBICemitEINode,
|
||||
*(ckt->CKTstate0 + inst->VBICitzf));
|
||||
}
|
||||
if (inst->VBIC_excessPhase) {
|
||||
NevalSrc(&noizDens[VBICICNOIZ],&lnNdens[VBICICNOIZ],
|
||||
ckt,SHOTNOISE,inst->VBICcollCINode, inst->VBICemitEINode,
|
||||
*(ckt->CKTstate0 + inst->VBICitxf));
|
||||
}
|
||||
NevalSrc(&noizDens[VBICICNOIZ],&lnNdens[VBICICNOIZ],
|
||||
ckt,SHOTNOISE,inst->VBICcollCINode, inst->VBICemitEINode,
|
||||
*(ckt->CKTstate0 + inst->VBICiciei));
|
||||
|
||||
NevalSrc(&noizDens[VBICIBNOIZ],&lnNdens[VBICIBNOIZ],
|
||||
ckt,SHOTNOISE,inst->VBICbaseBINode, inst->VBICemitEINode,
|
||||
*(ckt->CKTstate0 + inst->VBICibe));
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ VBICpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
|||
VBICinstance *here;
|
||||
VBICmodel *model = (VBICmodel*)inModel;
|
||||
double Ibe_Vbei,Ibex_Vbex
|
||||
,Itzf_Vbei,Itzf_Vbci,Itzr_Vbci,Itzr_Vbei,Ibc_Vbci
|
||||
,Iciei_Vbei,Iciei_Vbci,Ibc_Vbci
|
||||
,Ibc_Vbei,Ibep_Vbep,Ircx_Vrcx,Irci_Vrci
|
||||
,Irci_Vbci,Irci_Vbcx,Irbx_Vrbx,Irbi_Vrbi,Irbi_Vbei
|
||||
,Irbi_Vbci,Ire_Vre,Irbp_Vrbp,Irbp_Vbep,Irbp_Vbci
|
||||
|
|
@ -32,7 +32,7 @@ VBICpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
|||
XQbcx_Vbcx, XQbep_Vbep, XQbep_Vbci,
|
||||
XQbcp_Vbcp, XQbeo_Vbe, XQbco_Vbc;
|
||||
|
||||
double Ibe_Vrth, Ibex_Vrth, Itzf_Vrth=0.0, Itzr_Vrth, Ibc_Vrth, Ibep_Vrth,
|
||||
double Ibe_Vrth, Ibex_Vrth, Iciei_Vrth, Iciei_Vxf2, Ibc_Vrth, Ibep_Vrth,
|
||||
Ircx_Vrth, Irci_Vrth, Irbx_Vrth, Irbi_Vrth, Ire_Vrth, Irbp_Vrth,
|
||||
Ibcp_Vrth, Iccp_Vrth, Irs_Vrth, Irth_Vrth, Ith_Vrth,
|
||||
Ith_Vbei, Ith_Vbci, Ith_Vcei, Ith_Vbex, Ith_Vbep, Ith_Vbcp, Ith_Vcep,
|
||||
|
|
@ -40,22 +40,31 @@ VBICpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
|||
double XQcth_Vrth, XQbe_Vrth, XQbex_Vrth, XQbc_Vrth, XQbcx_Vrth, XQbep_Vrth, XQbcp_Vrth;
|
||||
|
||||
//NQS
|
||||
double Itxf_Vrxf, Ibc_Vrxf, Ith_Vrxf, Ixzf_Vrth, Ixxf_Vrxf, XQcxf_Vcxf;
|
||||
double Ixzf_Vbei, Ixzf_Vbci, Xl;
|
||||
double XQxf1_Vxf1;
|
||||
double XQxf2_Vxf2;
|
||||
|
||||
double Ixf1_Vbei;
|
||||
double Ixf1_Vbci;
|
||||
double Ixf1_Vxf2;
|
||||
double Ixf1_Vxf1;
|
||||
double Ixf1_Vrth;
|
||||
|
||||
double Ixf2_Vxf2;
|
||||
double Ixf2_Vxf1;
|
||||
|
||||
/* loop through all the models */
|
||||
for( ; model != NULL; model = VBICnextModel(model)) {
|
||||
|
||||
/* loop through all the instances of the model */
|
||||
for( here = VBICinstances(model); here!= NULL;
|
||||
for( here = VBICinstances(model); here!= NULL;
|
||||
here = VBICnextInstance(here)) {
|
||||
|
||||
Ibe_Vbei = *(ckt->CKTstate0 + here->VBICibe_Vbei);
|
||||
Ibex_Vbex = *(ckt->CKTstate0 + here->VBICibex_Vbex);
|
||||
Itzf_Vbei = *(ckt->CKTstate0 + here->VBICitzf_Vbei);
|
||||
Itzf_Vbci = *(ckt->CKTstate0 + here->VBICitzf_Vbci);
|
||||
Itzr_Vbci = *(ckt->CKTstate0 + here->VBICitzr_Vbci);
|
||||
Itzr_Vbei = *(ckt->CKTstate0 + here->VBICitzr_Vbei);
|
||||
Iciei_Vbei = *(ckt->CKTstate0 + here->VBICiciei_Vbei);
|
||||
Iciei_Vbci = *(ckt->CKTstate0 + here->VBICiciei_Vbci);
|
||||
Iciei_Vrth = *(ckt->CKTstate0 + here->VBICiciei_Vrth);
|
||||
Iciei_Vxf2 = *(ckt->CKTstate0 + here->VBICiciei_Vxf2);
|
||||
Ibc_Vbci = *(ckt->CKTstate0 + here->VBICibc_Vbci);
|
||||
Ibc_Vbei = *(ckt->CKTstate0 + here->VBICibc_Vbei);
|
||||
Ibep_Vbep = *(ckt->CKTstate0 + here->VBICibep_Vbep);
|
||||
|
|
@ -77,6 +86,15 @@ VBICpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
|||
Irs_Vrs = *(ckt->CKTstate0 + here->VBICirs_Vrs);
|
||||
Ire_Vre = *(ckt->CKTstate0 + here->VBICire_Vre);
|
||||
|
||||
Ixf1_Vbei = *(ckt->CKTstate0 + here->VBICixf1_Vbei);
|
||||
Ixf1_Vbci = *(ckt->CKTstate0 + here->VBICixf1_Vbci);
|
||||
Ixf1_Vxf2 = *(ckt->CKTstate0 + here->VBICixf1_Vxf2);
|
||||
Ixf1_Vxf1 = *(ckt->CKTstate0 + here->VBICixf1_Vxf1);
|
||||
Ixf1_Vrth = *(ckt->CKTstate0 + here->VBICixf1_Vrth);
|
||||
|
||||
Ixf2_Vxf2 = *(ckt->CKTstate0 + here->VBICixf2_Vxf2);
|
||||
Ixf2_Vxf1 = *(ckt->CKTstate0 + here->VBICixf2_Vxf1);
|
||||
|
||||
/*
|
||||
c The real part
|
||||
*/
|
||||
|
|
@ -94,32 +112,22 @@ c Stamp element: Ibex
|
|||
*(here->VBICbaseBXEmitEIPtr) += -Ibex_Vbex;
|
||||
*(here->VBICemitEIBaseBXPtr) += -Ibex_Vbex;
|
||||
*(here->VBICemitEIEmitEIPtr) += Ibex_Vbex;
|
||||
|
||||
if (!here->VBIC_excessPhase) {
|
||||
/*
|
||||
c Stamp element: Itzf
|
||||
c Stamp element: Iciei
|
||||
*/
|
||||
*(here->VBICcollCIBaseBIPtr) += Itzf_Vbei;
|
||||
*(here->VBICcollCIEmitEIPtr) += -Itzf_Vbei;
|
||||
*(here->VBICcollCIBaseBIPtr) += Itzf_Vbci;
|
||||
*(here->VBICcollCICollCIPtr) += -Itzf_Vbci;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Itzf_Vbei;
|
||||
*(here->VBICemitEIEmitEIPtr) += Itzf_Vbei;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Itzf_Vbci;
|
||||
*(here->VBICemitEICollCIPtr) += Itzf_Vbci;
|
||||
*(here->VBICcollCIBaseBIPtr) += Iciei_Vbei;
|
||||
*(here->VBICcollCIEmitEIPtr) += -Iciei_Vbei;
|
||||
*(here->VBICcollCIBaseBIPtr) += Iciei_Vbci;
|
||||
*(here->VBICcollCICollCIPtr) += -Iciei_Vbci;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Iciei_Vbei;
|
||||
*(here->VBICemitEIEmitEIPtr) += Iciei_Vbei;
|
||||
*(here->VBICemitEIBaseBIPtr) += -Iciei_Vbci;
|
||||
*(here->VBICemitEICollCIPtr) += Iciei_Vbci;
|
||||
if (here->VBIC_excessPhase) {
|
||||
*(here->VBICcollCIXf2Ptr) += Iciei_Vxf2;
|
||||
*(here->VBICemitEIXf2Ptr) += -Iciei_Vxf2;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Itzr
|
||||
*/
|
||||
*(here->VBICemitEIBaseBIPtr) += Itzr_Vbci;
|
||||
*(here->VBICemitEICollCIPtr) += -Itzr_Vbci;
|
||||
*(here->VBICemitEIBaseBIPtr) += Itzr_Vbei;
|
||||
*(here->VBICemitEIEmitEIPtr) += -Itzr_Vbei;
|
||||
*(here->VBICcollCIBaseBIPtr) += -Itzr_Vbci;
|
||||
*(here->VBICcollCICollCIPtr) += Itzr_Vbci;
|
||||
*(here->VBICcollCIBaseBIPtr) += -Itzr_Vbei;
|
||||
*(here->VBICcollCIEmitEIPtr) += Itzr_Vbei;
|
||||
/*
|
||||
c Stamp element: Ibc
|
||||
*/
|
||||
*(here->VBICbaseBIBaseBIPtr) += Ibc_Vbci;
|
||||
|
|
@ -138,14 +146,14 @@ c Stamp element: Ibep
|
|||
*(here->VBICbaseBPBaseBXPtr) += -Ibep_Vbep;
|
||||
*(here->VBICbaseBPBaseBPPtr) += Ibep_Vbep;
|
||||
/*
|
||||
c Stamp element: Ircx
|
||||
c Stamp element: Rcx
|
||||
*/
|
||||
*(here->VBICcollCollPtr) += Ircx_Vrcx;
|
||||
*(here->VBICcollCXCollCXPtr) += Ircx_Vrcx;
|
||||
*(here->VBICcollCXCollPtr) += -Ircx_Vrcx;
|
||||
*(here->VBICcollCollCXPtr) += -Ircx_Vrcx;
|
||||
/*
|
||||
c Stamp element: Irci
|
||||
c Stamp element: Rci
|
||||
*/
|
||||
*(here->VBICcollCXCollCXPtr) += Irci_Vrci;
|
||||
*(here->VBICcollCXCollCIPtr) += -Irci_Vrci;
|
||||
|
|
@ -160,14 +168,14 @@ c Stamp element: Irci
|
|||
*(here->VBICcollCIBaseBIPtr) += -Irci_Vbcx;
|
||||
*(here->VBICcollCICollCXPtr) += Irci_Vbcx;
|
||||
/*
|
||||
c Stamp element: Irbx
|
||||
c Stamp element: Rbx
|
||||
*/
|
||||
*(here->VBICbaseBasePtr) += Irbx_Vrbx;
|
||||
*(here->VBICbaseBXBaseBXPtr) += Irbx_Vrbx;
|
||||
*(here->VBICbaseBXBasePtr) += -Irbx_Vrbx;
|
||||
*(here->VBICbaseBaseBXPtr) += -Irbx_Vrbx;
|
||||
/*
|
||||
c Stamp element: Irbi
|
||||
c Stamp element: Rbi
|
||||
*/
|
||||
*(here->VBICbaseBXBaseBXPtr) += Irbi_Vrbi;
|
||||
*(here->VBICbaseBXBaseBIPtr) += -Irbi_Vrbi;
|
||||
|
|
@ -182,14 +190,14 @@ c Stamp element: Irbi
|
|||
*(here->VBICbaseBIBaseBIPtr) += -Irbi_Vbci;
|
||||
*(here->VBICbaseBICollCIPtr) += Irbi_Vbci;
|
||||
/*
|
||||
c Stamp element: Ire
|
||||
c Stamp element: Re
|
||||
*/
|
||||
*(here->VBICemitEmitPtr) += Ire_Vre;
|
||||
*(here->VBICemitEIEmitEIPtr) += Ire_Vre;
|
||||
*(here->VBICemitEIEmitPtr) += -Ire_Vre;
|
||||
*(here->VBICemitEmitEIPtr) += -Ire_Vre;
|
||||
/*
|
||||
c Stamp element: Irbp
|
||||
c Stamp element: Rbp
|
||||
*/
|
||||
*(here->VBICbaseBPBaseBPPtr) += Irbp_Vrbp;
|
||||
*(here->VBICbaseBPCollCXPtr) += -Irbp_Vrbp;
|
||||
|
|
@ -226,7 +234,7 @@ c Stamp element: Iccp
|
|||
*(here->VBICsubsSISubsSIPtr) += -Iccp_Vbcp;
|
||||
*(here->VBICsubsSIBaseBPPtr) += Iccp_Vbcp;
|
||||
/*
|
||||
c Stamp element: Irs
|
||||
c Stamp element: Rs
|
||||
*/
|
||||
*(here->VBICsubsSubsPtr) += Irs_Vrs;
|
||||
*(here->VBICsubsSISubsSIPtr) += Irs_Vrs;
|
||||
|
|
@ -237,9 +245,6 @@ c Stamp element: Irs
|
|||
|
||||
Ibe_Vrth = here->VBICibe_Vrth;
|
||||
Ibex_Vrth = here->VBICibex_Vrth;
|
||||
if (!here->VBIC_excessPhase)
|
||||
Itzf_Vrth = here->VBICitzf_vrth;
|
||||
Itzr_Vrth = here->VBICitzr_Vrth;
|
||||
Ibc_Vrth = here->VBICibc_Vrth;
|
||||
Ibep_Vrth = here->VBICibep_Vrth;
|
||||
Ircx_Vrth = here->VBICircx_Vrth;
|
||||
|
|
@ -279,19 +284,11 @@ c Stamp element: Ibex
|
|||
*/
|
||||
*(here->VBICbaseBXtempPtr) += Ibex_Vrth;
|
||||
*(here->VBICemitEItempPtr) += -Ibex_Vrth;
|
||||
|
||||
if (!here->VBIC_excessPhase) {
|
||||
/*
|
||||
c Stamp element: Itzf
|
||||
c Stamp element: Iciei
|
||||
*/
|
||||
*(here->VBICcollCItempPtr) += Itzf_Vrth;
|
||||
*(here->VBICemitEItempPtr) += -Itzf_Vrth;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Itzr
|
||||
*/
|
||||
*(here->VBICemitEItempPtr) += Itzr_Vrth;
|
||||
*(here->VBICcollCItempPtr) += -Itzr_Vrth;
|
||||
*(here->VBICcollCItempPtr) += Iciei_Vrth;
|
||||
*(here->VBICemitEItempPtr) += -Iciei_Vrth;
|
||||
/*
|
||||
c Stamp element: Ibc
|
||||
*/
|
||||
|
|
@ -386,44 +383,19 @@ c Stamp element: Ith
|
|||
*(here->VBICtempEmitEIPtr) += +Ith_Vre;
|
||||
*(here->VBICtempSubsPtr) += -Ith_Vrs;
|
||||
*(here->VBICtempSubsSIPtr) += +Ith_Vrs;
|
||||
if (here->VBIC_excessPhase) {
|
||||
Ith_Vrxf = *(ckt->CKTstate0 + here->VBICith_Vrxf);
|
||||
*(here->VBICtempXf2Ptr) += +Ith_Vrxf;
|
||||
}
|
||||
}
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
Itxf_Vrxf = *(ckt->CKTstate0 + here->VBICitxf_Vrxf);
|
||||
Ibc_Vrxf = *(ckt->CKTstate0 + here->VBICibc_Vrxf);
|
||||
Ixzf_Vbei = *(ckt->CKTstate0 + here->VBICixzf_Vbei);
|
||||
Ixzf_Vbci = *(ckt->CKTstate0 + here->VBICixzf_Vbci);
|
||||
Ixxf_Vrxf = *(ckt->CKTstate0 + here->VBICixxf_Vrxf);
|
||||
/*
|
||||
c Stamp element: Itxf
|
||||
*/
|
||||
*(here->VBICcollCIXf2Ptr) += Itxf_Vrxf;
|
||||
*(here->VBICemitEIXf2Ptr) += -Itxf_Vrxf;
|
||||
/*
|
||||
c Stamp element: Ibc
|
||||
*/
|
||||
*(here->VBICbaseBIXf2Ptr) += Ibc_Vrxf;
|
||||
*(here->VBICcollCIXf2Ptr) += -Ibc_Vrxf;
|
||||
/*
|
||||
c Stamp element: Ixzf, Branch: xf1-ground
|
||||
*/
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixzf_Vbei;
|
||||
*(here->VBICxf1EmitEIPtr) += -Ixzf_Vbei;
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixzf_Vbci;
|
||||
*(here->VBICxf1CollCIPtr) += -Ixzf_Vbci;
|
||||
if (here->VBIC_selfheat) {
|
||||
Ixzf_Vrth = *(ckt->CKTstate0 + here->VBICixzf_Vrth);
|
||||
*(here->VBICxf1TempPtr) += Ixzf_Vrth;
|
||||
}
|
||||
/*
|
||||
c Stamp element: Ixxf, Branch: xf2-ground
|
||||
*/
|
||||
*(here->VBICxf2Xf2Ptr) += +Ixxf_Vrxf;
|
||||
|
||||
//Ixf1
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixf1_Vbei;
|
||||
*(here->VBICxf1EmitEIPtr) += -Ixf1_Vbei;
|
||||
*(here->VBICxf1BaseBIPtr) += +Ixf1_Vbci;
|
||||
*(here->VBICxf1CollCIPtr) += -Ixf1_Vbci;
|
||||
*(here->VBICxf1Xf2Ptr) += +Ixf1_Vxf2;
|
||||
*(here->VBICxf1Xf1Ptr) += +Ixf1_Vxf1;
|
||||
//Ixf2
|
||||
*(here->VBICxf2Xf2Ptr) += +Ixf2_Vxf2;
|
||||
*(here->VBICxf2Xf1Ptr) += +Ixf2_Vxf1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -439,6 +411,8 @@ c The complex part
|
|||
XQbcp_Vbcp = *(ckt->CKTstate0 + here->VBICcqbcp);
|
||||
XQbeo_Vbe = *(ckt->CKTstate0 + here->VBICcqbeo);
|
||||
XQbco_Vbc = *(ckt->CKTstate0 + here->VBICcqbco);
|
||||
XQxf1_Vxf1 = *(ckt->CKTstate0 + here->VBICcqxf1);
|
||||
XQxf2_Vxf2 = *(ckt->CKTstate0 + here->VBICcqxf2);
|
||||
/*
|
||||
c Stamp element: Qbe
|
||||
*/
|
||||
|
|
@ -545,6 +519,14 @@ c Stamp element: Qbco
|
|||
*(here->VBICcollBasePtr ) += -XQbco_Vbc * (s->real);
|
||||
*(here->VBICcollBasePtr + 1) += -XQbco_Vbc * (s->imag);
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
//Qxf1
|
||||
*(here->VBICxf1Xf1Ptr + 1) += +XQxf1_Vxf1*(s->imag);
|
||||
*(here->VBICxf1Xf1Ptr) += +XQxf1_Vxf1*(s->real);
|
||||
//Qxf2
|
||||
*(here->VBICxf2Xf2Ptr + 1) += +XQxf2_Vxf2*(s->imag);
|
||||
*(here->VBICxf2Xf2Ptr ) += +XQxf2_Vxf2*(s->real);
|
||||
}
|
||||
if (here->VBIC_selfheat) {
|
||||
XQcth_Vrth = here->VBICcapcth;
|
||||
XQbe_Vrth = here->VBICcapqbeth;
|
||||
|
|
@ -581,28 +563,12 @@ c Stamp element: Qbco
|
|||
*(here->VBICsubsSItempPtr + 1) += XQbcp_Vrth * (s->imag);
|
||||
*(here->VBICbaseBPtempPtr ) += -XQbcp_Vrth * (s->real);
|
||||
*(here->VBICbaseBPtempPtr + 1) += -XQbcp_Vrth * (s->imag);
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
// Stamp element: Ixf1 f_xf1 = +
|
||||
*(here->VBICxf1TempPtr) += Ixf1_Vrth;
|
||||
}
|
||||
}
|
||||
if (here->VBIC_excessPhase) {
|
||||
/*
|
||||
c Stamp element: Qcxf
|
||||
*/
|
||||
XQcxf_Vcxf = here->VBICcapQcxf;
|
||||
*(here->VBICxf1Xf1Ptr ) += XQcxf_Vcxf * s->real;
|
||||
*(here->VBICxf1Xf1Ptr + 1) += XQcxf_Vcxf * s->imag;
|
||||
/*
|
||||
c Stamp element: L = TD/3
|
||||
*/
|
||||
Xl = here->VBICindInduct;
|
||||
|
||||
*(here->VBICxf1IbrPtr) += 1;
|
||||
*(here->VBICxf2IbrPtr) -= 1;
|
||||
*(here->VBICibrXf1Ptr) += 1;
|
||||
*(here->VBICibrXf2Ptr) -= 1;
|
||||
*(here->VBICibrIbrPtr ) -= Xl * s->real;
|
||||
*(here->VBICibrIbrPtr + 1) -= Xl * s->imag;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -483,7 +483,6 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
model->VBICthermalCapacitance = 1e-12;
|
||||
|
||||
if((model->VBICdelayTimeFGiven) && (model->VBICdelayTimeF > 0.0)) {
|
||||
here->VBICindInduct = model->VBICdelayTimeF / 3.0 / here->VBICm;
|
||||
here->VBIC_excessPhase = 1;
|
||||
} else {
|
||||
here->VBIC_excessPhase = 0;
|
||||
|
|
@ -518,11 +517,6 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
if(error) return(error);
|
||||
here->VBICxf2Node = tmp->number;
|
||||
}
|
||||
if(here->VBICbrEq == 0) {
|
||||
error = CKTmkCur(ckt,&tmp,here->VBICname,"branch");
|
||||
if(error) return(error);
|
||||
here->VBICbrEq = tmp->number;
|
||||
}
|
||||
} else {
|
||||
here->VBICxf1Node = 0;
|
||||
here->VBICxf2Node = 0;
|
||||
|
|
@ -612,27 +606,21 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|||
TSTALLOC(VBICtempSubsSIPtr,VBICtempNode,VBICsubsSINode);
|
||||
TSTALLOC(VBICtempTempPtr,VBICtempNode,VBICtempNode);
|
||||
if (here->VBIC_excessPhase) {
|
||||
TSTALLOC(VBICtempXf2Ptr, VBICtempNode, VBICxf2Node);
|
||||
TSTALLOC(VBICxf1TempPtr, VBICxf1Node ,VBICtempNode);
|
||||
TSTALLOC(VBICxf1TempPtr ,VBICxf1Node ,VBICtempNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (here->VBIC_excessPhase) {
|
||||
TSTALLOC(VBICxf1Xf1Ptr , VBICxf1Node , VBICxf1Node);
|
||||
TSTALLOC(VBICxf1Xf2Ptr , VBICxf1Node , VBICxf2Node);
|
||||
TSTALLOC(VBICxf1CollCIPtr, VBICxf1Node , VBICcollCINode);
|
||||
TSTALLOC(VBICxf1BaseBIPtr, VBICxf1Node , VBICbaseBINode);
|
||||
TSTALLOC(VBICxf1EmitEIPtr, VBICxf1Node , VBICemitEINode);
|
||||
TSTALLOC(VBICxf2Xf2Ptr , VBICxf2Node , VBICxf2Node);
|
||||
TSTALLOC(VBICxf2Xf1Ptr , VBICxf2Node , VBICxf1Node);
|
||||
TSTALLOC(VBICcollCIXf2Ptr, VBICcollCINode, VBICxf2Node);
|
||||
TSTALLOC(VBICbaseBIXf2Ptr, VBICbaseBINode, VBICxf2Node);
|
||||
TSTALLOC(VBICemitEIXf2Ptr, VBICemitEINode, VBICxf2Node);
|
||||
TSTALLOC(VBICxf1IbrPtr, VBICxf1Node, VBICbrEq);
|
||||
TSTALLOC(VBICxf2IbrPtr, VBICxf2Node, VBICbrEq);
|
||||
TSTALLOC(VBICibrXf2Ptr, VBICbrEq, VBICxf2Node);
|
||||
TSTALLOC(VBICibrXf1Ptr, VBICbrEq, VBICxf1Node);
|
||||
TSTALLOC(VBICibrIbrPtr, VBICbrEq, VBICbrEq);
|
||||
TSTALLOC(VBICxf1Xf1Ptr ,VBICxf1Node ,VBICxf1Node);
|
||||
TSTALLOC(VBICxf1BaseBIPtr,VBICxf1Node ,VBICbaseBINode);
|
||||
TSTALLOC(VBICxf1EmitEIPtr,VBICxf1Node ,VBICemitEINode);
|
||||
TSTALLOC(VBICxf1CollCIPtr,VBICxf1Node ,VBICcollCINode);
|
||||
TSTALLOC(VBICxf1Xf2Ptr ,VBICxf1Node ,VBICxf2Node);
|
||||
|
||||
TSTALLOC(VBICxf2Xf1Ptr ,VBICxf2Node ,VBICxf1Node);
|
||||
TSTALLOC(VBICxf2Xf2Ptr ,VBICxf2Node ,VBICxf2Node);
|
||||
TSTALLOC(VBICemitEIXf2Ptr,VBICemitEINode,VBICxf2Node);
|
||||
TSTALLOC(VBICcollCIXf2Ptr,VBICcollCINode,VBICxf2Node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -694,11 +682,8 @@ VBICunsetup(
|
|||
if(here->VBICxf2Node > 0)
|
||||
CKTdltNNum(ckt, here->VBICxf2Node);
|
||||
here->VBICxf2Node = 0;
|
||||
|
||||
if (here->VBICbrEq > 0)
|
||||
CKTdltNNum(ckt, here->VBICbrEq);
|
||||
here->VBICbrEq = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
|
|
|
|||
|
|
@ -31,14 +31,6 @@ model_numnodes(int type)
|
|||
return 6;
|
||||
}
|
||||
|
||||
#ifdef ADMS
|
||||
if (type == INPtypelook("BSIMBULK") || /* bsimbulk.va */
|
||||
type == INPtypelook("BSIMCMG")) /* bsimcmg.va */
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (type == INPtypelook("VDMOS")) /* 3 ; VDMOSnames */
|
||||
{
|
||||
return 5;
|
||||
|
|
@ -141,13 +133,6 @@ INP2M(CKTcircuit *ckt, INPtables *tab, struct card *current)
|
|||
thismodel->INPmodType != INPtypelook("SOI3") &&
|
||||
#ifdef CIDER
|
||||
thismodel->INPmodType != INPtypelook("NUMOS") &&
|
||||
#endif
|
||||
#ifdef ADMS
|
||||
thismodel->INPmodType != INPtypelook("ekv") &&
|
||||
thismodel->INPmodType != INPtypelook("psp102") &&
|
||||
thismodel->INPmodType != INPtypelook("psp103") &&
|
||||
thismodel->INPmodType != INPtypelook("bsimbulk") &&
|
||||
thismodel->INPmodType != INPtypelook("bsimcmg") &&
|
||||
#endif
|
||||
thismodel->INPmodType != INPtypelook("HiSIM2") &&
|
||||
thismodel->INPmodType != INPtypelook("HiSIMHV1") &&
|
||||
|
|
|
|||
|
|
@ -18,11 +18,6 @@ model_max_numnodes(int type)
|
|||
if (type == INPtypelook("VBIC") ||
|
||||
type == INPtypelook("hicum2"))
|
||||
return 5;
|
||||
#ifdef ADMS
|
||||
if (type == INPtypelook("hicum0") ||
|
||||
type == INPtypelook("bjt504t"))
|
||||
return 5;
|
||||
#endif
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
|
@ -96,10 +91,6 @@ void INP2Q(CKTcircuit *ckt, INPtables * tab, struct card *current, CKTnode *gnod
|
|||
#ifdef CIDER
|
||||
thismodel->INPmodType != INPtypelook("NBJT") &&
|
||||
thismodel->INPmodType != INPtypelook("NBJT2") &&
|
||||
#endif
|
||||
#ifdef ADMS
|
||||
thismodel->INPmodType != INPtypelook("hicum0") &&
|
||||
thismodel->INPmodType != INPtypelook("bjt504t") &&
|
||||
#endif
|
||||
thismodel->INPmodType != INPtypelook("hicum2") &&
|
||||
thismodel->INPmodType != INPtypelook("VBIC"))
|
||||
|
|
|
|||
|
|
@ -169,11 +169,8 @@ void INP2R(CKTcircuit *ckt, INPtables * tab, struct card *current)
|
|||
INPinsert(&model, tab);
|
||||
current->error = INPgetMod(ckt, model, &thismodel, tab);
|
||||
if (thismodel != NULL) {
|
||||
if ((INPtypelook("Resistor") != thismodel->INPmodType)
|
||||
#ifdef ADMS
|
||||
&& (INPtypelook("r2_cmc") != thismodel->INPmodType)
|
||||
#endif
|
||||
) {
|
||||
if (INPtypelook("Resistor") != thismodel->INPmodType)
|
||||
{
|
||||
LITERR("incorrect model type for resistor");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,22 +63,6 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
"Device type VBIC not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
#ifdef ADMS
|
||||
case 6:
|
||||
type = INPtypelook("bjt504t");
|
||||
if(type < 0) {
|
||||
err = INPmkTemp(
|
||||
"Device type MEXTRAM not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
type = INPtypelook("hicum0");
|
||||
if(type < 0) {
|
||||
err = INPmkTemp(
|
||||
"Device type HICUM0 not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 8:
|
||||
type = INPtypelook("hicum2");
|
||||
if(type < 0) {
|
||||
|
|
@ -87,13 +71,8 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
}
|
||||
break;
|
||||
default: /* placeholder; use level 4 for the next model */
|
||||
#ifdef ADMS
|
||||
err = INPmkTemp(
|
||||
"Only BJT levels 1-2, 4, 6-9 are supported in this binary\n");
|
||||
#else
|
||||
err = INPmkTemp(
|
||||
"Only BJT levels 1-2, 4, 8, 9 are supported in this binary\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
}
|
||||
|
|
@ -341,48 +320,6 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
("Device type BSIM5 not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
#ifdef ADMS
|
||||
case 16:
|
||||
case 77:
|
||||
type = INPtypelook("BSIMBULK");
|
||||
if (type < 0) {
|
||||
err =
|
||||
INPmkTemp
|
||||
("Device type BSIMBULK not available in this binary\n");}
|
||||
break;
|
||||
case 17:
|
||||
case 72:
|
||||
type = INPtypelook("BSIMCMG");
|
||||
if (type < 0) {
|
||||
err =
|
||||
INPmkTemp
|
||||
("Device type BSIMCMG not available in this binary\n");}
|
||||
break;
|
||||
case 44:
|
||||
type = INPtypelook("ekv");
|
||||
if (type < 0) {
|
||||
err =
|
||||
INPmkTemp
|
||||
("Device type EKV not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
case 45:
|
||||
type = INPtypelook("psp102");
|
||||
if (type < 0) {
|
||||
err =
|
||||
INPmkTemp
|
||||
("Device type PSP102 not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
case 69:
|
||||
type = INPtypelook("psp103");
|
||||
if (type < 0) {
|
||||
err =
|
||||
INPmkTemp
|
||||
("Device type PSP103 not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 55:
|
||||
type = INPtypelook("B3SOIFD");
|
||||
if (type < 0) {
|
||||
|
|
@ -444,13 +381,8 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
}
|
||||
break;
|
||||
default: /* placeholder; use level xxx for the next model */
|
||||
#ifdef ADMS
|
||||
err = INPmkTemp
|
||||
("Only MOS device levels 1-6,8-10,14,16,17,44,45,49,54-58,60,68,72,73,77 are supported in this binary\n");
|
||||
#else
|
||||
err = INPmkTemp
|
||||
("Only MOS device levels 1-6,8-10,14,49,54-58,60,68,73 are supported in this binary\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
INPmakeMod(modname, type, image);
|
||||
|
|
@ -481,15 +413,6 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
("Device type Resistor not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
#ifdef ADMS
|
||||
case 2:
|
||||
type = INPtypelook("r2_cmc");
|
||||
if (type < 0) {
|
||||
err = INPmkTemp(
|
||||
"Device type R2_CMC not available in this binary\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
INPmakeMod(modname, type, image);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,15 @@
|
|||
EXTRA_DIST = README examples icm xspice.c .gitignore \
|
||||
verilog/vlnggen \
|
||||
verilog/verilator_shim.cpp verilog/verilator_main.cpp \
|
||||
verilog/libvvp.def verilog/MSVC.CMD verilog/README.txt
|
||||
verilog/libvvp.def verilog/MSVC.CMD verilog/README.txt \
|
||||
vhdl/ghnggen \
|
||||
vhdl/ghdl_shim.h vhdl/ghdl_shim.c vhdl/ghdl_vpi.c
|
||||
|
||||
## This is removed because icm relies upon the existance of all other
|
||||
## libs. It is currently compiled manually, last.
|
||||
##SUBDIRS = mif cm enh evt ipc idn icm
|
||||
|
||||
SUBDIRS = mif cm enh evt ipc idn cmpp icm verilog
|
||||
SUBDIRS = mif cm enh evt ipc idn cmpp icm verilog vhdl
|
||||
|
||||
dist-hook:
|
||||
rm -f "$(distdir)/icm/makedefs"
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ NON-STANDARD FEATURES
|
|||
|
||||
#include "ngspice/fteext.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <locale.h>
|
||||
|
||||
|
|
@ -511,7 +512,7 @@ static double get_real(int index, double when, struct reals *ctx)
|
|||
{
|
||||
struct dvec *dv;
|
||||
|
||||
if (index < ctx->last_i) {
|
||||
if (index <= ctx->last_i) {
|
||||
/* Starting a new pass. */
|
||||
|
||||
if (!ctx->time) {
|
||||
|
|
@ -568,11 +569,9 @@ static double get_real(int index, double when, struct reals *ctx)
|
|||
/*
|
||||
* A simple vcd file printer.
|
||||
* command 'eprvcd a0 a1 a2 b0 b1 b2 clk > myvcd.vcd'
|
||||
* prints the event nodes listed to file myvcd.vcd
|
||||
* which then may be viewed with an vcd viewer,
|
||||
* for example 'gtkwave'
|
||||
* Still missing:
|
||||
* hierarchy, vector variables
|
||||
* prints the event nodes and vector expressions listed to file myvcd.vcd
|
||||
* which then may be viewed with an vcd viewer, for example 'gtkwave'.
|
||||
* Still missing: hierarchy, bit vectors.
|
||||
*/
|
||||
|
||||
void
|
||||
|
|
@ -588,7 +587,6 @@ EVTprintvcd(wordlist *wl)
|
|||
|
||||
double out_time, last_out_time;
|
||||
|
||||
|
||||
char *node_name[EPRINT_MAXARGS];
|
||||
int node_index[EPRINT_MAXARGS];
|
||||
int udn_index[EPRINT_MAXARGS];
|
||||
|
|
@ -621,8 +619,9 @@ EVTprintvcd(wordlist *wl)
|
|||
double input;
|
||||
int error = 0;
|
||||
char* inword = wl->wl_word;
|
||||
|
||||
input = INPevaluate(&inword, &error, 0);
|
||||
tspower = (int)ceil(- 1. * log10(input));
|
||||
tspower = (int)ceil(-log10(input));
|
||||
if (tspower < 0)
|
||||
tspower = 0;
|
||||
}
|
||||
|
|
@ -654,7 +653,7 @@ EVTprintvcd(wordlist *wl)
|
|||
fprintf(cp_err, "Error: no circuit loaded.\n");
|
||||
return;
|
||||
}
|
||||
if (!ckt->evt->data.node) {
|
||||
if (!ckt->evt->data.node && !timesteps) {
|
||||
fprintf(cp_err, "ERROR - No node data: simulation not yet run?\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -866,7 +865,7 @@ EVTprintvcd(wordlist *wl)
|
|||
(timesteps && !more))) {
|
||||
|
||||
/* Analogue output at each time step, skipping if they would
|
||||
* appear simulataneous in the output.
|
||||
* appear simultaneous in the output.
|
||||
*/
|
||||
|
||||
out_time = ctx.time->v_realdata[ctx.v_index + 1];
|
||||
|
|
@ -919,7 +918,6 @@ EVTprintvcd(wordlist *wl)
|
|||
|
||||
out_printf("#%lld\n",
|
||||
(unsigned long long)(out_time * scale));
|
||||
last_out_time = out_time;;
|
||||
got_one = 1;
|
||||
}
|
||||
|
||||
|
|
@ -942,6 +940,7 @@ EVTprintvcd(wordlist *wl)
|
|||
tfree(buf);
|
||||
}
|
||||
}
|
||||
last_out_time = out_time;
|
||||
} /* end while there is more data */
|
||||
|
||||
out_printf("\n\n");
|
||||
|
|
|
|||
|
|
@ -94,14 +94,21 @@ static void callback(ARGS, Mif_Callback_Reason_t reason)
|
|||
if (reason == MIF_CB_DESTROY) {
|
||||
if (!ip)
|
||||
return;
|
||||
if (ip->info.cleanup)
|
||||
if (ip->info.cleanup) {
|
||||
DBG("Calling cleanup.");
|
||||
(*ip->info.cleanup)(&ip->info);
|
||||
}
|
||||
if (ip->info.lib_argv)
|
||||
free((void *)ip->info.lib_argv);
|
||||
if (ip->info.sim_argv)
|
||||
free((void *)ip->info.sim_argv);
|
||||
if (ip->so_handle)
|
||||
dlclose(ip->so_handle);
|
||||
if (ip->so_handle) {
|
||||
DBG("Unloading co-simulation.");
|
||||
if (dlclose(ip->so_handle)) {
|
||||
cm_message_printf("Error unloading co-simulation: %s",
|
||||
dlerror());
|
||||
}
|
||||
}
|
||||
if (ip->q)
|
||||
free(ip->q);
|
||||
if (ip->out_vals)
|
||||
|
|
@ -131,6 +138,13 @@ static const char *exts[] = { "", ".so", ".DLL", NULL};
|
|||
#define NGSPICELIBDIR "C:\\Spice64\\lib\\ngspice" // Defined by configure?
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
static const char *exts[] = { "", ".so", ".dylib", NULL};
|
||||
#define CMPFN strcmp
|
||||
#define TESTFN(f) (access(f, R_OK) == 0)
|
||||
#define SLIBFILE "dynamic library"
|
||||
|
||||
#else
|
||||
|
||||
static const char *exts[] = { "", ".so", NULL};
|
||||
|
|
@ -138,6 +152,7 @@ static const char *exts[] = { "", ".so", NULL};
|
|||
#define TESTFN(f) (access(f, R_OK) == 0)
|
||||
#define SLIBFILE "shared library"
|
||||
#endif
|
||||
|
||||
#define FLAGS (RTLD_GLOBAL | RTLD_NOW)
|
||||
|
||||
static void *cosim_dlopen(const char *fn)
|
||||
|
|
@ -422,6 +437,8 @@ static bool check_input(struct instance *ip, Digital_t *ovp,
|
|||
while (ip->q_index >= 0 && ip->q[ip->q_index].when >= rp->when)
|
||||
--ip->q_index;
|
||||
if (ip->q_index >= 0) {
|
||||
DBG("Input Q full: d_cosim setting back to %.15g.",
|
||||
(rp->when + ip->q[ip->q_index].when) / 2);
|
||||
cm_analog_set_temp_bkpt(
|
||||
(rp->when + ip->q[ip->q_index].when) / 2);
|
||||
} else {
|
||||
|
|
@ -473,7 +490,8 @@ void ucm_d_cosim(ARGS)
|
|||
fn = PARAM(simulation);
|
||||
handle = cosim_dlopen(fn);
|
||||
if (!handle) {
|
||||
cm_message_send("d_cosim failed to load simulation binary.");
|
||||
cm_message_printf("d_cosim failed to load simulation binary %s.",
|
||||
fn);
|
||||
return;
|
||||
}
|
||||
ifp = (void (*)(struct co_info *))dlsym(handle, "Cosim_setup");
|
||||
|
|
|
|||
|
|
@ -570,39 +570,23 @@ MIF_INP2A (
|
|||
}
|
||||
}
|
||||
|
||||
/* check model parameter constraints */
|
||||
/* some of these should probably be done in MIFgetMod() */
|
||||
/* to prevent multiple error messages */
|
||||
/* Check model parameter constraints. */
|
||||
|
||||
for(i = 0; i < DEVices[type]->DEVpublic.num_param; i++) {
|
||||
char* emessage = NULL;
|
||||
|
||||
param_info = &(DEVices[type]->DEVpublic.param[i]);
|
||||
|
||||
if (mdfast->param[i]->is_null) {
|
||||
char* emessage = NULL;
|
||||
|
||||
if (!param_info->null_allowed) {
|
||||
emessage = tprintf("Null not allowed for parameter %s "
|
||||
"on model %s.",
|
||||
param_info->name, mdfast->gen.GENmodName);
|
||||
} else if (param_info->default_value_siz == 0) {
|
||||
if (param_info->type == MIF_STRING)
|
||||
continue; // Allow NULL
|
||||
emessage = tprintf("Parameter %s on model %s has no default",
|
||||
param_info->name, mdfast->gen.GENmodName);
|
||||
}
|
||||
|
||||
if (emessage) {
|
||||
LITERR(emessage);
|
||||
tfree(emessage);
|
||||
gc_end();
|
||||
return;
|
||||
}
|
||||
} else if (param_info->is_array && param_info->has_conn_ref &&
|
||||
if (!mdfast->param[i]->is_null &&
|
||||
param_info->is_array && param_info->has_conn_ref &&
|
||||
fast->conn[param_info->conn_ref]->size !=
|
||||
fast->param[i]->size) {
|
||||
LITERR("Array parameter size on model does not match "
|
||||
"connection size");
|
||||
emessage = tprintf("Size of array parameter %s on model %s "
|
||||
"does not match connection size",
|
||||
param_info->name, mdfast->gen.GENmodName);
|
||||
}
|
||||
if (emessage) {
|
||||
LITERR(emessage);
|
||||
tfree(emessage);
|
||||
gc_end();
|
||||
return;
|
||||
}
|
||||
|
|
@ -1081,7 +1065,3 @@ copy_gc(char* in)
|
|||
alltokens[curtoknr++] = newtok;
|
||||
return newtok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ NON-STANDARD FEATURES
|
|||
|
||||
#include "ngspice/mifproto.h"
|
||||
#include "ngspice/mifdefs.h"
|
||||
#include "ngspice/mifparse.h"
|
||||
#include "ngspice/mifcmdat.h"
|
||||
|
||||
#include "ngspice/suffix.h"
|
||||
|
|
@ -101,8 +102,6 @@ char *MIFgetMod(
|
|||
char *err2;
|
||||
|
||||
MIFmodel *mdfast;
|
||||
/* Mif_Param_Info_t *param_info;*/
|
||||
|
||||
|
||||
/* =========== First locate the named model in the modtab list ================= */
|
||||
|
||||
|
|
@ -143,34 +142,46 @@ char *MIFgetMod(
|
|||
/* ============== and return an appropriate pointer to it ===================== */
|
||||
|
||||
/* make sure the type is valid before proceeding */
|
||||
if(modtmp->INPmodType < 0) {
|
||||
/* illegal device type, so can't handle */
|
||||
*model = NULL;
|
||||
return tprintf("MIF: Unknown device type for model %s\n", name);
|
||||
}
|
||||
if (modtmp->INPmodType < 0) {
|
||||
/* illegal device type, so can't handle */
|
||||
|
||||
*model = NULL;
|
||||
return tprintf("MIF: Unknown device type for model %s\n", name);
|
||||
}
|
||||
|
||||
/* check to see if this model's parameters have been processed */
|
||||
if(! modtmp->INPmodfast) {
|
||||
|
||||
if (!modtmp->INPmodfast) {
|
||||
struct IFdevice *device;
|
||||
int num_pars;
|
||||
|
||||
/* not already processed, so create data struct */
|
||||
error = ft_sim->newModel ( ckt, modtmp->INPmodType,
|
||||
&(modtmp->INPmodfast), modtmp->INPmodName);
|
||||
if(error)
|
||||
return(INPerror(error));
|
||||
|
||||
/* gtri modification: allocate and initialize MIF specific model struct items */
|
||||
error = ft_sim->newModel(ckt, modtmp->INPmodType,
|
||||
&(modtmp->INPmodfast),
|
||||
modtmp->INPmodName);
|
||||
if (error)
|
||||
return INPerror(error);
|
||||
|
||||
/* Allocate and initialize MIF specific model struct items. */
|
||||
|
||||
mdfast = (MIFmodel*) modtmp->INPmodfast;
|
||||
mdfast->num_param = DEVices[modtmp->INPmodType]->DEVpublic.num_param;
|
||||
mdfast->num_param =
|
||||
DEVices[modtmp->INPmodType]->DEVpublic.num_param;
|
||||
mdfast->param = TMALLOC(Mif_Param_Data_t *, mdfast->num_param);
|
||||
for(i = 0; i < mdfast->num_param; i++) {
|
||||
for (i = 0; i < mdfast->num_param; i++) {
|
||||
mdfast->param[i] = TMALLOC(Mif_Param_Data_t, 1);
|
||||
mdfast->param[i]->is_null = MIF_TRUE;
|
||||
mdfast->param[i]->size = 0;
|
||||
mdfast->param[i]->element = NULL;
|
||||
}
|
||||
/* remaining initializations will be done by MIFmParam() and MIFsetup() */
|
||||
|
||||
/* Remaining initializations will be done by
|
||||
* MIFmParam() and MIFsetup().
|
||||
*/
|
||||
|
||||
/* parameter isolation, identification, binding */
|
||||
|
||||
line = modtmp->INPmodLine->line;
|
||||
INPgetTok(&line,&parm,1); /* throw away '.model' */
|
||||
tfree(parm);
|
||||
|
|
@ -179,28 +190,39 @@ char *MIFgetMod(
|
|||
|
||||
/* throw away the modtype - we don't treat it as a parameter */
|
||||
/* like SPICE does */
|
||||
INPgetTok(&line,&parm,1); /* throw away 'modtype' */
|
||||
|
||||
INPgetTok(&line, &parm, 1); /* throw away 'modtype' */
|
||||
tfree(parm);
|
||||
|
||||
while(*line != '\0') {
|
||||
INPgetTok(&line,&parm,1);
|
||||
for(j=0 ; j < *(ft_sim->devices[modtmp->INPmodType]->numModelParms); j++) {
|
||||
if (strcmp(parm, ft_sim->devices[modtmp->INPmodType]->modelParms[j].keyword) == 0) {
|
||||
/* gtri modification: call MIFgetValue instead of INPgetValue */
|
||||
device = ft_sim->devices[modtmp->INPmodType];
|
||||
num_pars = *device->numModelParms;
|
||||
while (*line != '\0') {
|
||||
INPgetTok(&line, &parm, 1);
|
||||
if (!parm || !*parm) // May be closing ')'.
|
||||
break;
|
||||
for (j = 0; j < num_pars; j++) {
|
||||
if (strcmp(parm, device->modelParms[j].keyword) == 0) {
|
||||
err1 = NULL;
|
||||
val = MIFgetValue(ckt,&line,
|
||||
ft_sim->devices[modtmp->INPmodType]->modelParms[j].dataType,
|
||||
val = MIFgetValue(ckt, &line,
|
||||
device->modelParms[j].dataType,
|
||||
tab, &err1);
|
||||
if(err1) {
|
||||
err2 = tprintf("MIF-ERROR - model: %s - %s\n", name, err1);
|
||||
return(err2);
|
||||
if (err1) {
|
||||
err2 = tprintf("MIF-ERROR - model: %s - %s\n",
|
||||
name, err1);
|
||||
return err2;
|
||||
}
|
||||
error = ft_sim->setModelParm (ckt,
|
||||
modtmp->INPmodfast,
|
||||
ft_sim->devices[modtmp->INPmodType]->modelParms[j].id,
|
||||
val, NULL);
|
||||
|
||||
/* Store the parameter value. */
|
||||
|
||||
error =
|
||||
ft_sim->setModelParm(ckt,
|
||||
modtmp->INPmodfast,
|
||||
device->modelParms[j].id,
|
||||
val, NULL);
|
||||
/* free val, allocated by MIFgetValue */
|
||||
int vtype = (ft_sim->devices[modtmp->INPmodType]->modelParms[j].dataType & IF_VARTYPES);
|
||||
|
||||
int vtype =
|
||||
(device->modelParms[j].dataType & IF_VARTYPES);
|
||||
if (vtype == IF_FLAGVEC || vtype == IF_INTVEC)
|
||||
tfree(val->v.vec.iVec);
|
||||
if (vtype == IF_REALVEC)
|
||||
|
|
@ -214,14 +236,16 @@ char *MIFgetMod(
|
|||
tfree(val->v.vec.sVec[i]);
|
||||
tfree(val->v.vec.sVec);
|
||||
}
|
||||
if(error)
|
||||
return(INPerror(error));
|
||||
if (error)
|
||||
return INPerror(error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* gtri modification: processing of special parameter "level" removed */
|
||||
if(j >= *(ft_sim->devices[modtmp->INPmodType]->numModelParms)) {
|
||||
char *temp = tprintf("MIF: unrecognized parameter (%s) - ignored", parm);
|
||||
|
||||
if (j >= *(device->numModelParms)) {
|
||||
char *temp = tprintf("MIF: unrecognized parameter "
|
||||
"(%s) - ignored",
|
||||
parm);
|
||||
err = INPerrCat(err, temp);
|
||||
}
|
||||
FREE(parm);
|
||||
|
|
@ -230,20 +254,44 @@ char *MIFgetMod(
|
|||
|
||||
modtmp->INPmodLine->error = err;
|
||||
|
||||
/* Make some consistency checks. */
|
||||
|
||||
for (i = 0; i < mdfast->num_param; i++) {
|
||||
Mif_Param_Info_t *param_info;
|
||||
char *emessage;
|
||||
|
||||
param_info = device->param + i;
|
||||
|
||||
if (mdfast->param[i]->is_null) {
|
||||
if (!param_info->null_allowed) {
|
||||
emessage = tprintf("Null not allowed for "
|
||||
"parameter '%s' on model '%s'.",
|
||||
param_info->name,
|
||||
mdfast->gen.GENmodName);
|
||||
return emessage;
|
||||
} else if (param_info->default_value_siz == 0) {
|
||||
if (param_info->type == MIF_STRING)
|
||||
continue; // Allow NULL
|
||||
emessage = tprintf("Parameter '%s' on model '%s' "
|
||||
"has no default.",
|
||||
param_info->name,
|
||||
mdfast->gen.GENmodName);
|
||||
return emessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* end if model parameters not processed yet */
|
||||
|
||||
*model = modtmp;
|
||||
return(NULL);
|
||||
|
||||
return NULL;
|
||||
} /* end if name matches */
|
||||
|
||||
} /* end for all models in modtab linked list */
|
||||
|
||||
|
||||
/* didn't find model - ERROR - return NULL model */
|
||||
*model = NULL;
|
||||
err = tprintf(" MIF-ERROR - unable to find definition of model %s\n", name);
|
||||
|
||||
return(err);
|
||||
*model = NULL;
|
||||
err = tprintf("MIF-ERROR - unable to find definition of model %s\n", name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,13 +62,56 @@ static int MIFget_integer(char *token, char **err);
|
|||
|
||||
static double MIFget_real(char *token, char **err);
|
||||
|
||||
static char *MIFget_string(char *token, char **err);
|
||||
|
||||
static IFcomplex MIFget_complex(char *token, Mif_Token_Type_t token_type,
|
||||
char **line, char **err);
|
||||
|
||||
|
||||
|
||||
/* Pull a string from a .model card, like MIFget_token() but do not break
|
||||
* on any special characters except '"' and ']'.
|
||||
*/
|
||||
|
||||
static char *get_string(char **s, int is_array, Mif_Token_Type_t *token_type)
|
||||
{
|
||||
char *ret_str; /* storage for returned string */
|
||||
char *end;
|
||||
char *beg;
|
||||
|
||||
/* Skip over white space. */
|
||||
|
||||
while (isspace_c(**s))
|
||||
(*s)++;
|
||||
if (!*s) {
|
||||
*token_type = MIF_NO_TOK;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If first character is a quote, read until the closing
|
||||
* quote, or the end of string, discarding the quotes.
|
||||
*/
|
||||
|
||||
if (**s == '"') {
|
||||
(*s)++;
|
||||
ret_str = gettok_char(s, '"', FALSE, FALSE);
|
||||
if (**s == '"')
|
||||
(*s)++;
|
||||
} else if (is_array && **s == ']') {
|
||||
*token_type = MIF_RARRAY_TOK;
|
||||
(*s)++;
|
||||
return NULL;
|
||||
} else {
|
||||
/* Read to next white-space, end of line, or end of array. */
|
||||
|
||||
beg = *s;
|
||||
while (**s != '\0' && !(isspace_c(**s) || (is_array && **s == ']')))
|
||||
(*s)++;
|
||||
end = *s;
|
||||
ret_str = copy_substring(beg, end);
|
||||
}
|
||||
*token_type = MIF_STRING;
|
||||
return ret_str;
|
||||
}
|
||||
|
||||
/*
|
||||
MIFgetValue
|
||||
|
||||
|
|
@ -94,7 +137,6 @@ MIFgetValue (
|
|||
int btemp;
|
||||
int itemp;
|
||||
double rtemp;
|
||||
char *stemp;
|
||||
IFcomplex ctemp;
|
||||
|
||||
char *token;
|
||||
|
|
@ -114,6 +156,7 @@ MIFgetValue (
|
|||
|
||||
|
||||
/* initialize stuff if array */
|
||||
|
||||
if(is_array) {
|
||||
token = MIFget_token(line, &token_type);
|
||||
tfree(token);
|
||||
|
|
@ -129,8 +172,10 @@ MIFgetValue (
|
|||
/* now get the values into val */
|
||||
|
||||
for (;;) {
|
||||
|
||||
token = MIFget_token(line, &token_type);
|
||||
if ((value_type & ~IF_VECTOR) == IF_STRING)
|
||||
token = get_string(line, is_array, &token_type);
|
||||
else
|
||||
token = MIFget_token(line, &token_type);
|
||||
|
||||
/* exit if no more tokens */
|
||||
if(token_type == MIF_NO_TOK) {
|
||||
|
|
@ -163,14 +208,14 @@ MIFgetValue (
|
|||
break;
|
||||
|
||||
case IF_STRING:
|
||||
val.sValue = MIFget_string(token, err);
|
||||
val.sValue = token;
|
||||
token = NULL;
|
||||
break;
|
||||
|
||||
case IF_COMPLEX:
|
||||
val.cValue = MIFget_complex(token, token_type, line, err);
|
||||
break;
|
||||
|
||||
|
||||
case IF_FLAGVEC:
|
||||
btemp = MIFget_boolean(token, err);
|
||||
val.v.vec.iVec = TREALLOC(int, val.v.vec.iVec, val.v.numValue + 1);
|
||||
|
|
@ -193,10 +238,10 @@ MIFgetValue (
|
|||
break;
|
||||
|
||||
case IF_STRINGVEC:
|
||||
stemp = MIFget_string(token, err);
|
||||
val.v.vec.sVec = TREALLOC(char *, val.v.vec.sVec, val.v.numValue + 1);
|
||||
val.v.vec.sVec[val.v.numValue] = stemp;
|
||||
val.v.vec.sVec[val.v.numValue] = token;
|
||||
val.v.numValue++;
|
||||
token = NULL;
|
||||
break;
|
||||
|
||||
case IF_CPLXVEC:
|
||||
|
|
@ -220,7 +265,8 @@ MIFgetValue (
|
|||
if(! is_array)
|
||||
break;
|
||||
|
||||
tfree(token);
|
||||
if (token)
|
||||
tfree(token);
|
||||
|
||||
} /* end forever loop */
|
||||
|
||||
|
|
@ -302,16 +348,6 @@ static double MIFget_real(char *token, char **err)
|
|||
}
|
||||
|
||||
|
||||
/* *************************************************************** */
|
||||
|
||||
static char *MIFget_string(char *token, char **err)
|
||||
{
|
||||
char* ctoken = MIFcopy(token);
|
||||
*err = NULL;
|
||||
return(ctoken);
|
||||
}
|
||||
|
||||
|
||||
/* *************************************************************** */
|
||||
|
||||
static IFcomplex MIFget_complex(char *token, Mif_Token_Type_t token_type,
|
||||
|
|
|
|||
|
|
@ -36,13 +36,9 @@ NON-STANDARD FEATURES
|
|||
|
||||
============================================================================*/
|
||||
|
||||
/* #include "prefix.h" */
|
||||
#include "ngspice/ngspice.h"
|
||||
#include <stdio.h>
|
||||
//#include "CONST.h"
|
||||
//#include "util.h"
|
||||
#include "ngspice/ifsim.h"
|
||||
//#include "resdefs.h"
|
||||
#include "ngspice/devdefs.h"
|
||||
#include "ngspice/sperror.h"
|
||||
|
||||
|
|
@ -53,8 +49,48 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/mifdefs.h"
|
||||
#include "ngspice/mifcmdat.h"
|
||||
|
||||
/* #include "suffix.h" */
|
||||
/* Check value constraints from IFS file. */
|
||||
|
||||
static int check_int(int v, Mif_Param_Info_t *param_info, const char *name)
|
||||
{
|
||||
if (param_info->has_lower_limit && v < param_info->lower_limit.ivalue) {
|
||||
fprintf(stderr,
|
||||
"Value %d below limit %d for parameter '%s' of model '%s'.\n",
|
||||
v, param_info->lower_limit.ivalue,
|
||||
param_info->name, name);
|
||||
v = param_info->lower_limit.ivalue;
|
||||
} else if (param_info->has_upper_limit &&
|
||||
v > param_info->upper_limit.ivalue) {
|
||||
fprintf(stderr,
|
||||
"Value %d exceeds limit %d for parameter '%s' of "
|
||||
"model '%s'.\n",
|
||||
v, param_info->upper_limit.ivalue,
|
||||
param_info->name, name);
|
||||
v = param_info->upper_limit.ivalue;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static double check_double(double v, Mif_Param_Info_t *param_info,
|
||||
const char *name)
|
||||
{
|
||||
if (param_info->has_lower_limit && v < param_info->lower_limit.rvalue) {
|
||||
fprintf(stderr,
|
||||
"Value %g below limit %g for parameter '%s' of model '%s'.\n",
|
||||
v, param_info->lower_limit.rvalue,
|
||||
param_info->name, name);
|
||||
v = param_info->lower_limit.rvalue;
|
||||
} else if (param_info->has_upper_limit &&
|
||||
v > param_info->upper_limit.rvalue) {
|
||||
fprintf(stderr,
|
||||
"Value %g exceeds limit %g for parameter '%s' of "
|
||||
"model '%s'.\n",
|
||||
v, param_info->upper_limit.rvalue,
|
||||
param_info->name, name);
|
||||
v = param_info->upper_limit.rvalue;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
MIFmParam
|
||||
|
|
@ -76,139 +112,152 @@ int MIFmParam(
|
|||
GENmodel *inModel) /* The model structure on which to set the value */
|
||||
{
|
||||
|
||||
MIFmodel *model;
|
||||
int mod_type;
|
||||
int value_type;
|
||||
int i;
|
||||
MIFmodel *model;
|
||||
Mif_Value_t *target;
|
||||
Mif_Param_Info_t *param_info;
|
||||
int mod_type;
|
||||
int value_type;
|
||||
int size, i;
|
||||
|
||||
Mif_Boolean_t is_array;
|
||||
Mif_Boolean_t is_array;
|
||||
|
||||
|
||||
/* Arrange for access to MIF specific data in the model */
|
||||
model = (MIFmodel *) inModel;
|
||||
|
||||
/* Check parameter index for validity */
|
||||
if ((param_index < 0) || (param_index >= model->num_param))
|
||||
return(E_BADPARM);
|
||||
|
||||
/* Get model type */
|
||||
/* Get model type and XSPICE parameter info. */
|
||||
mod_type = model->MIFmodType;
|
||||
if((mod_type < 0) || (mod_type >= DEVmaxnum))
|
||||
return(E_BADPARM);
|
||||
|
||||
|
||||
/* Check parameter index for validity */
|
||||
if((param_index < 0) || (param_index >= model->num_param))
|
||||
return(E_BADPARM);
|
||||
param_info = DEVices[mod_type]->DEVpublic.param + param_index;
|
||||
|
||||
/* get value type to know which members of unions to access */
|
||||
|
||||
value_type = DEVices[mod_type]->DEVpublic.modelParms[param_index].dataType;
|
||||
value_type &= IF_VARTYPES;
|
||||
|
||||
|
||||
/* determine if the parameter is an array or not */
|
||||
is_array = value_type & IF_VECTOR;
|
||||
|
||||
/* initialize the parameter is_null and size elements and allocate elements */
|
||||
/* Initialize the parameter is_null. */
|
||||
|
||||
model->param[param_index]->is_null = MIF_FALSE;
|
||||
|
||||
/* element may exist already, if called from 'altermod' */
|
||||
FREE(model->param[param_index]->element);
|
||||
if(is_array) {
|
||||
model->param[param_index]->size = value->v.numValue;
|
||||
model->param[param_index]->element = TMALLOC(Mif_Value_t, value->v.numValue);
|
||||
}
|
||||
else {
|
||||
model->param[param_index]->size = 1;
|
||||
model->param[param_index]->element = TMALLOC(Mif_Value_t, 1);
|
||||
target = model->param[param_index]->element;
|
||||
|
||||
if (is_array) {
|
||||
size = value->v.numValue;
|
||||
if (param_info->has_lower_bound && size < param_info->lower_bound) {
|
||||
fprintf(stderr,
|
||||
"Too few values for parameter '%s' of model '%s': %s.\n",
|
||||
param_info->name,
|
||||
inModel->GENmodName,
|
||||
target ? "overwriting" : "fatal");
|
||||
if (!target)
|
||||
return E_BADPARM;
|
||||
} else if (param_info->has_upper_bound &&
|
||||
size > param_info->upper_bound) {
|
||||
fprintf(stderr,
|
||||
"Too many values for parameter '%s' of model '%s': "
|
||||
"truncating.\n",
|
||||
param_info->name,
|
||||
inModel->GENmodName);
|
||||
size = param_info->upper_bound;
|
||||
}
|
||||
} else {
|
||||
size = 1;
|
||||
}
|
||||
|
||||
if (size > model->param[param_index]->size) {
|
||||
/* Update element count and allocate. */
|
||||
|
||||
/* Transfer the values from the SPICE3C1 value union to the param elements */
|
||||
model->param[param_index]->size = size;
|
||||
FREE(target);
|
||||
target = TMALLOC(Mif_Value_t, size);
|
||||
model->param[param_index]->element = target;
|
||||
}
|
||||
|
||||
/* Copy the values from the SPICE3C1 value union to the param elements */
|
||||
/* This is analagous to what SPICE3 does with other device types */
|
||||
|
||||
if (!is_array) {
|
||||
switch(value_type) {
|
||||
case IF_FLAG:
|
||||
target[0].bvalue = value->iValue;
|
||||
break;
|
||||
|
||||
if(! is_array) {
|
||||
case IF_INTEGER:
|
||||
target[0].ivalue = check_int(value->iValue,
|
||||
param_info, inModel->GENmodName);
|
||||
break;
|
||||
|
||||
switch(value_type) {
|
||||
case IF_REAL:
|
||||
target[0].rvalue = check_double(value->rValue,
|
||||
param_info, inModel->GENmodName);
|
||||
break;
|
||||
|
||||
case IF_FLAG:
|
||||
model->param[param_index]->element[0].bvalue = value->iValue;
|
||||
model->param[param_index]->eltype = IF_FLAG;
|
||||
break;
|
||||
case IF_STRING:
|
||||
/* we don't trust the caller to keep the string alive, so copy it */
|
||||
target[0].svalue =
|
||||
TMALLOC(char, 1 + strlen(value->sValue));
|
||||
strcpy(target[0].svalue, value->sValue);
|
||||
break;
|
||||
|
||||
case IF_INTEGER:
|
||||
model->param[param_index]->element[0].ivalue = value->iValue;
|
||||
model->param[param_index]->eltype = IF_INTEGER;
|
||||
break;
|
||||
case IF_COMPLEX:
|
||||
/* we don't trust the caller to have a parallel complex structure */
|
||||
/* so copy the real and imaginary parts explicitly */
|
||||
|
||||
case IF_REAL:
|
||||
model->param[param_index]->element[0].rvalue = value->rValue;
|
||||
model->param[param_index]->eltype = IF_REAL;
|
||||
break;
|
||||
|
||||
case IF_STRING:
|
||||
/* we don't trust the caller to keep the string alive, so copy it */
|
||||
model->param[param_index]->element[0].svalue =
|
||||
TMALLOC(char, 1 + strlen(value->sValue));
|
||||
strcpy(model->param[param_index]->element[0].svalue, value->sValue);
|
||||
model->param[param_index]->eltype = IF_STRING;
|
||||
break;
|
||||
|
||||
case IF_COMPLEX:
|
||||
/* we don't trust the caller to have a parallel complex structure */
|
||||
/* so copy the real and imaginary parts explicitly */
|
||||
model->param[param_index]->element[0].cvalue.real = value->cValue.real;
|
||||
model->param[param_index]->element[0].cvalue.imag = value->cValue.imag;
|
||||
model->param[param_index]->eltype = IF_COMPLEX;
|
||||
break;
|
||||
target[0].cvalue.real = value->cValue.real;
|
||||
target[0].cvalue.imag = value->cValue.imag;
|
||||
break;
|
||||
|
||||
default:
|
||||
return(E_BADPARM);
|
||||
|
||||
}
|
||||
}
|
||||
else { /* it is an array */
|
||||
|
||||
for(i = 0; i < value->v.numValue; i++) {
|
||||
return E_BADPARM;
|
||||
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < size; i++) {
|
||||
switch(value_type) {
|
||||
|
||||
case IF_FLAGVEC:
|
||||
model->param[param_index]->element[i].bvalue = value->v.vec.iVec[i];
|
||||
model->param[param_index]->eltype = IF_FLAGVEC;
|
||||
target[i].ivalue = value->v.vec.iVec[i];
|
||||
break;
|
||||
|
||||
case IF_INTVEC:
|
||||
model->param[param_index]->element[i].ivalue = value->v.vec.iVec[i];
|
||||
model->param[param_index]->eltype = IF_INTVEC;
|
||||
target[i].bvalue = check_int(value->v.vec.iVec[i],
|
||||
param_info, inModel->GENmodName);
|
||||
break;
|
||||
|
||||
case IF_REALVEC:
|
||||
model->param[param_index]->element[i].rvalue = value->v.vec.rVec[i];
|
||||
model->param[param_index]->eltype = IF_REALVEC;
|
||||
target[i].rvalue = check_double(value->v.vec.rVec[i],
|
||||
param_info,
|
||||
inModel->GENmodName);
|
||||
break;
|
||||
|
||||
case IF_STRINGVEC:
|
||||
/* we don't trust the caller to keep the string alive, so copy it */
|
||||
model->param[param_index]->element[i].svalue =
|
||||
TMALLOC(char, 1 + strlen(value->v.vec.sVec[i]));
|
||||
strcpy(model->param[param_index]->element[i].svalue, value->v.vec.sVec[i]);
|
||||
model->param[param_index]->eltype = IF_STRINGVEC;
|
||||
/* Don't trust the caller to keep the string alive, copy it */
|
||||
target[i].svalue =
|
||||
TMALLOC(char, 1 + strlen(value->v.vec.sVec[i]));
|
||||
strcpy(target[i].svalue, value->v.vec.sVec[i]);
|
||||
break;
|
||||
|
||||
case IF_CPLXVEC:
|
||||
/* we don't trust the caller to have a parallel complex structure */
|
||||
/* so copy the real and imaginary parts explicitly */
|
||||
model->param[param_index]->element[i].cvalue.real = value->v.vec.cVec[i].real;
|
||||
model->param[param_index]->element[i].cvalue.imag = value->v.vec.cVec[i].imag;
|
||||
model->param[param_index]->eltype = IF_CPLXVEC;
|
||||
/* Don't trust the caller to have a parallel complex structure,
|
||||
* so copy the real and imaginary parts explicitly.
|
||||
*/
|
||||
target[i].cvalue.real = value->v.vec.cVec[i].real;
|
||||
target[i].cvalue.imag = value->v.vec.cVec[i].imag;
|
||||
break;
|
||||
|
||||
default:
|
||||
return(E_BADPARM);
|
||||
|
||||
} /* end switch */
|
||||
|
||||
} /* end for number of elements of vector */
|
||||
|
||||
} /* end else */
|
||||
|
||||
return(OK);
|
||||
return E_BADPARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
model->param[param_index]->eltype = value_type;
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,11 +47,6 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/miftypes.h"
|
||||
#include "ngspice/mifproto.h"
|
||||
|
||||
/* #include "suffix.h" */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
MIFgettok
|
||||
|
|
@ -67,8 +62,7 @@ MIFgettok treats ( and ) like whitespace.
|
|||
|
||||
char *MIFgettok(char **s)
|
||||
{
|
||||
|
||||
char *ret_str; /* storage for returned string */
|
||||
char *ret_str; /* storage for returned string */
|
||||
char *end;
|
||||
char *beg;
|
||||
|
||||
|
|
@ -122,14 +116,12 @@ char *MIFgettok(char **s)
|
|||
/* else, read until the next delimiter */
|
||||
else {
|
||||
beg = *s;
|
||||
while ((**s != '\0') &&
|
||||
(!(isspace_c(**s) || (**s == '=') || (**s == '%') ||
|
||||
(**s == '(') || (**s == ')') || (**s == ',') ||
|
||||
(**s == '[') || (**s == ']') ||
|
||||
(**s == '<') || (**s == '>') || (**s == '~')
|
||||
))) {
|
||||
while (**s != '\0' &&
|
||||
!(isspace_c(**s) || **s == '=' || **s == '%' ||
|
||||
**s == '(' || **s == ')' || **s == ',' ||
|
||||
**s == '[' || **s == ']' ||
|
||||
**s == '<' || **s == '>' || **s == '~'))
|
||||
(*s)++;
|
||||
}
|
||||
end = *s;
|
||||
|
||||
/* skip over white spaces, '=', '(', ')', and ',' up to next token */
|
||||
|
|
@ -143,94 +135,6 @@ char *MIFgettok(char **s)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* preliminary fix */
|
||||
char *MIFgettok(char **s)
|
||||
{
|
||||
|
||||
char *buf; /* temporary storage to copy token into */
|
||||
char *ret_str; /* storage for returned string */
|
||||
|
||||
int i;
|
||||
|
||||
/* allocate space big enough for the whole string */
|
||||
|
||||
buf = TMALLOC(char, strlen(*s) + 2);
|
||||
/* FIXME, not yet understood why +1 leads to spurious crash in tfree, if optimized code for Windows*/
|
||||
|
||||
/* skip over any white space */
|
||||
|
||||
while(isspace_c(**s) || (**s == '=') ||
|
||||
(**s == '(') || (**s == ')') || (**s == ','))
|
||||
(*s)++;
|
||||
|
||||
/* isolate the next token */
|
||||
|
||||
switch(**s) {
|
||||
|
||||
case '\0':
|
||||
FREE(buf);
|
||||
return(NULL);
|
||||
|
||||
case '<':
|
||||
case '>':
|
||||
case '[':
|
||||
case ']':
|
||||
case '~':
|
||||
case '%':
|
||||
buf[0] = **s;
|
||||
buf[1] = '\0';
|
||||
(*s)++;
|
||||
break;
|
||||
|
||||
default:
|
||||
i = 0;
|
||||
/* if first character is a quote, read until the closing */
|
||||
/* quote, or the end of string, discarding the quotes */
|
||||
if(**s == '"') {
|
||||
(*s)++;
|
||||
while( (**s != '\0') && (**s != '"') ) {
|
||||
buf[i] = **s;
|
||||
i++;
|
||||
(*s)++;
|
||||
}
|
||||
if(**s == '"')
|
||||
(*s)++;
|
||||
}
|
||||
/* else, read until the next delimiter */
|
||||
else {
|
||||
while( (**s != '\0') &&
|
||||
(! ( isspace_c(**s) || (**s == '=') || (**s == '%') ||
|
||||
(**s == '(') || (**s == ')') || (**s == ',') ||
|
||||
(**s == '[') || (**s == ']') ||
|
||||
(**s == '<') || (**s == '>') || (**s == '~')
|
||||
) ) ) {
|
||||
buf[i] = **s;
|
||||
i++;
|
||||
(*s)++;
|
||||
}
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip over white space up to next token */
|
||||
|
||||
while(isspace_c(**s) || (**s == '=') ||
|
||||
(**s == '(') || (**s == ')') || (**s == ','))
|
||||
(*s)++;
|
||||
|
||||
/* make a copy using only the space needed by the string length */
|
||||
/* Changed from copy to MIFcopy by SDB on 6.22.2003 */
|
||||
ret_str = MIFcopy(buf);
|
||||
FREE(buf);
|
||||
|
||||
return(ret_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
|
@ -255,7 +159,6 @@ char *MIFget_token(
|
|||
|
||||
ret_str = MIFgettok(s);
|
||||
|
||||
|
||||
/* if no next token, return */
|
||||
|
||||
if(ret_str == NULL) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
# Libs for Ngspice are irrelevant here.
|
||||
|
||||
LIBS =
|
||||
|
||||
# Verilator support: files installed to script directory and below.
|
||||
|
||||
initdatadir = $(pkgdatadir)/scripts
|
||||
|
|
@ -13,7 +17,8 @@ initdata1_DATA = verilator_shim.cpp verilator_main.cpp
|
|||
initdata2dir = $(pkgdatadir)/scripts/src/ngspice
|
||||
initdata2_DATA = ../../include/ngspice/cosim.h \
|
||||
../../include/ngspice/miftypes.h \
|
||||
../../include/ngspice/cmtypes.h
|
||||
../../include/ngspice/cmtypes.h \
|
||||
./coroutine.h ./coroutine_cosim.h ./coroutine_shim.h
|
||||
|
||||
# Icarus Verilog support: build two shared libraries.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
# GHDL support: files installed to script directory and below.
|
||||
|
||||
initdatadir = $(pkgdatadir)/scripts
|
||||
initdata_DATA = ghnggen
|
||||
|
||||
initdata1dir = $(pkgdatadir)/scripts/src
|
||||
initdata1_DATA = ghdl_shim.h ghdl_shim.c ghdl_vpi.c
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
/* Main file to be linked with code generated by GHDL to make a shared library
|
||||
* to be loaded by ngspice's d_cosim code model to connect an instance of a
|
||||
* VHDL simulation into a Ngspice netlist.
|
||||
* Licensed on the same terms as Ngspice.
|
||||
*
|
||||
* Copyright (c) 2024 Giles Atkinson
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* The GHDL code runs on its own stack, handled by cr_xxx() functions. */
|
||||
|
||||
#include "ngspice/coroutine_shim.h"
|
||||
|
||||
#include "ngspice/cmtypes.h" // For Digital_t
|
||||
#include "ngspice/cosim.h"
|
||||
|
||||
/* This header file defines the external (d_cosim) interface. It also contains
|
||||
* an initial comment that describes how this shared library is used.
|
||||
*/
|
||||
|
||||
#include "ghdl_shim.h"
|
||||
|
||||
extern int ghdl_main(int argc, char **argv); // Not in any header.
|
||||
|
||||
/* Report fatal errors. */
|
||||
|
||||
static void fail(const char *what, int why)
|
||||
{
|
||||
fprintf(stderr, "Icarus shim failed in function %s: %s.\n",
|
||||
what, strerror(why));
|
||||
abort();
|
||||
}
|
||||
|
||||
static void input(struct co_info *pinfo, unsigned int bit, Digital_t *val)
|
||||
{
|
||||
struct ng_ghdl *ctx = (struct ng_ghdl *)pinfo->handle;
|
||||
struct ngvp_port *pp;
|
||||
int count, a, b, dirty;
|
||||
|
||||
/* Convert the value. */
|
||||
|
||||
if (val->strength <= HI_IMPEDANCE && val->state != UNKNOWN) {
|
||||
a = val->state; // Normal - '0'/'1'.
|
||||
b = 0;
|
||||
} else if (val->strength == HI_IMPEDANCE) {
|
||||
a = 0; // High impedance - 'z'.
|
||||
b = 1;
|
||||
} else {
|
||||
a = 1; // Undefined - 'x'.
|
||||
b = 1;
|
||||
}
|
||||
|
||||
/* Find the port. */
|
||||
|
||||
if (bit >= pinfo->in_count) {
|
||||
bit -= pinfo->in_count;
|
||||
if (bit >= pinfo->inout_count)
|
||||
return;
|
||||
pp = ctx->ports + ctx->ins + ctx->outs; // Point at inouts.
|
||||
count = ctx->inouts;
|
||||
} else {
|
||||
pp = ctx->ports;
|
||||
count = ctx->ins;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
if (pp[count].position <= bit)
|
||||
break;
|
||||
}
|
||||
pp = pp + count;
|
||||
bit -= pp->position;
|
||||
|
||||
/* Check and update. */
|
||||
|
||||
dirty = 0;
|
||||
bit = pp->bits - bit - 1; // Bit position for big-endian.
|
||||
a <<= bit;
|
||||
if (a ^ pp->previous.aval) {
|
||||
if (a)
|
||||
pp->previous.aval |= a;
|
||||
else
|
||||
pp->previous.aval &= ~(1 << bit);
|
||||
dirty = 1;
|
||||
}
|
||||
b <<= bit;
|
||||
if (b ^ pp->previous.bval) {
|
||||
if (b)
|
||||
pp->previous.bval |= b;
|
||||
else
|
||||
pp->previous.bval &= ~(1 << bit);
|
||||
dirty = 1;
|
||||
}
|
||||
|
||||
if (dirty && !(pp->flags & IN_PENDING)) {
|
||||
pp->flags |= IN_PENDING;
|
||||
++ctx->in_pending;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move the GHDL simulation forward. */
|
||||
|
||||
static void step(struct co_info *pinfo)
|
||||
{
|
||||
struct ng_ghdl *ctx = (struct ng_ghdl *)pinfo->handle;
|
||||
int i;
|
||||
|
||||
/* Let GHDL run. It will stop when it has caught up with SPICE time
|
||||
* (pinfo->vtime) or produced output.
|
||||
*/
|
||||
|
||||
cr_yield_to_sim(&ctx->cr_ctx);
|
||||
|
||||
/* Check for output. */
|
||||
|
||||
if (ctx->out_pending) {
|
||||
struct ngvp_port *pp;
|
||||
uint32_t changed, mask;
|
||||
int limit, i, bit;
|
||||
|
||||
limit = ctx->outs + ctx->inouts;
|
||||
for (i = 0, pp = ctx->ports + ctx->ins; i < limit; ++i, ++pp) {
|
||||
if (!(pp->flags & OUT_PENDING))
|
||||
continue;
|
||||
|
||||
pp->flags &= ~OUT_PENDING;
|
||||
changed = (pp->new.aval ^ pp->previous.aval) |
|
||||
(pp->new.bval ^ pp->previous.bval);
|
||||
if (changed) {
|
||||
bit = pp->position;
|
||||
mask = 1 << (pp->bits - 1);
|
||||
while (changed) {
|
||||
if (mask & changed) {
|
||||
const Digital_t lv_vals[] =
|
||||
{ {ZERO, STRONG}, {ONE, STRONG},
|
||||
{ZERO, HI_IMPEDANCE}, {UNKNOWN, STRONG} };
|
||||
int a, b;
|
||||
|
||||
a = (pp->new.aval & mask) != 0;
|
||||
b = (pp->new.bval & mask) != 0;
|
||||
a += (b << 1);
|
||||
pinfo->out_fn(pinfo, bit, (Digital_t *)lv_vals + a);
|
||||
changed &= ~mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
++bit;
|
||||
}
|
||||
pp->previous.aval = pp->new.aval;
|
||||
pp->previous.bval = pp->new.bval;
|
||||
}
|
||||
if (--ctx->out_pending == 0)
|
||||
break;
|
||||
}
|
||||
if (ctx->out_pending)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup(struct co_info *pinfo)
|
||||
{
|
||||
struct ng_ghdl *ctx = (struct ng_ghdl *)pinfo->handle;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
/* Tell GHDL to exit. */
|
||||
|
||||
ctx->stop = 1;
|
||||
cr_yield_to_sim(&ctx->cr_ctx);
|
||||
cr_cleanup(&ctx->cr_ctx);
|
||||
free(ctx->ports);
|
||||
free(ctx);
|
||||
pinfo->handle = NULL;
|
||||
}
|
||||
|
||||
/* Thread start function runs the VHDL simulation. */
|
||||
|
||||
void *run_ghdl(void *arg)
|
||||
{
|
||||
struct co_info *pinfo = (struct co_info *)arg;
|
||||
struct ng_ghdl *ctx, **ctx_ptr;
|
||||
const char *file;
|
||||
void *vpi_handle;
|
||||
const char *new_argv[pinfo->sim_argc + 2];
|
||||
int new_argc;
|
||||
char vpi_buf[256];
|
||||
|
||||
cr_safety(); // Make safe with signals.
|
||||
|
||||
if (pinfo->sim_argc == 0) {
|
||||
new_argc = 1;
|
||||
new_argv[0] = "dummy_arg_0";
|
||||
} else {
|
||||
/* Copy the simulation arguments to the extended array. */
|
||||
|
||||
for (new_argc = 0; new_argc < pinfo->sim_argc; new_argc++)
|
||||
new_argv[new_argc] = pinfo->sim_argv[new_argc];
|
||||
}
|
||||
|
||||
/* Determing the file name for our VPI module. */
|
||||
|
||||
if (pinfo->lib_argc >= 1 && pinfo->lib_argv[0][0]) // Explicit VPI file.
|
||||
file = pinfo->lib_argv[0];
|
||||
else
|
||||
file = "./ghdlng.vpi";
|
||||
|
||||
/* Normally, GHDL would load the VPI module. Here it is preloaded and
|
||||
* an internal variable is set to point to the shared co_info struct.
|
||||
*/
|
||||
|
||||
ctx_ptr = NULL;
|
||||
vpi_handle = dlopen(file, RTLD_GLOBAL | RTLD_NOW);
|
||||
if (vpi_handle)
|
||||
ctx_ptr = dlsym(vpi_handle, CTX_VAR_NAME);
|
||||
if (!ctx_ptr) {
|
||||
fprintf(stderr,
|
||||
"The GHDL shim can not initialise VPI module %s: %s.\n",
|
||||
file, dlerror());
|
||||
return NULL;
|
||||
}
|
||||
ctx = (struct ng_ghdl *)pinfo->handle;
|
||||
*ctx_ptr = ctx;
|
||||
|
||||
/* The GHDL code is passed the VPI module name in a command argument. */
|
||||
|
||||
snprintf(vpi_buf, sizeof vpi_buf, "--vpi=%s", file);
|
||||
new_argv[new_argc++] = vpi_buf;
|
||||
new_argv[new_argc] = NULL;
|
||||
ghdl_main(new_argc, (char **)new_argv);
|
||||
|
||||
/* The simulation has finished. Do nothing until destroyed. */
|
||||
|
||||
dlclose(vpi_handle);
|
||||
ctx->stop = 1;
|
||||
for (;;)
|
||||
cr_yield_to_spice(&ctx->cr_ctx);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Entry point to this shared library. Called by d_cosim. */
|
||||
|
||||
void Cosim_setup(struct co_info *pinfo)
|
||||
{
|
||||
struct ng_ghdl *context;
|
||||
struct ngvp_port *last_port;
|
||||
|
||||
/* It is assumed that there is no parallel access to this function
|
||||
* as ngspice initialisation is single-threaded.
|
||||
*/
|
||||
|
||||
context = calloc(1, sizeof (struct ng_ghdl));
|
||||
if (!context)
|
||||
fail("malloc", errno);
|
||||
context->cosim_context = pinfo;
|
||||
pinfo->handle = context;
|
||||
|
||||
/* Set-up the execution stack for the GHDL-generated code and start it. */
|
||||
|
||||
cr_init(&context->cr_ctx, run_ghdl, pinfo);
|
||||
|
||||
/* Return required values in *pinfo. */
|
||||
|
||||
last_port = context->ports + context->ins - 1;
|
||||
pinfo->in_count = context->ins ? last_port->position + last_port->bits : 0;
|
||||
last_port += context->outs;
|
||||
pinfo->out_count =
|
||||
context->outs ? last_port->position + last_port->bits : 0;
|
||||
last_port += context->inouts;
|
||||
pinfo->inout_count =
|
||||
context->inouts ? last_port->position + last_port->bits : 0;
|
||||
pinfo->cleanup = cleanup;
|
||||
pinfo->step = step;
|
||||
pinfo->in_fn = input;
|
||||
pinfo->method = Normal;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef _GHDL_SHIM_H_
|
||||
#define _GHDL_SHIM_H_
|
||||
|
||||
/* This is the interface definition file for the shim code (ghdl_shim.c)
|
||||
* and associated Verilog VPI module (ghdl_shim.vpi).
|
||||
*
|
||||
* This software allows execution of VHDL code generated by the GHDL compiler
|
||||
* inside a SPICE simulation performed by ngspice.
|
||||
*
|
||||
* Use of these components starts with a SPICE netlist containing an A-device
|
||||
* (XSPICE device) whose model card specifies the d_cosim code model and
|
||||
* parameter 'simulation="some_path/entity_name.so"', where "entity_name"
|
||||
* represents a top-level entity defined in VHDL. The shared library
|
||||
* (or DLL) named is built by the "ghdl -e" command using output from
|
||||
* a VHDL compilation ("ghdl -a") and the provided ghdl_shim.c file.
|
||||
*
|
||||
* The VPI module ghdl_vpi.c is called on loading: its first task is to obtain
|
||||
* the list of ports for the top-level VHDL entity. After that the VPI code
|
||||
* controls the execution of the VHDL code by blocking execution until
|
||||
* commanded to proceed by the d_cosim instance, always regaining control
|
||||
* via a VPI callback before the VHDL code moves ahead of the SPICE simulation.
|
||||
*/
|
||||
|
||||
typedef uint32_t __vpiHandle; // Compatible with GHDL's vpi_user.h
|
||||
|
||||
/* Data stored for each port. */
|
||||
|
||||
struct ngvp_port {
|
||||
uint16_t bits; // How many bits?
|
||||
uint16_t flags; // I/O pending.
|
||||
uint32_t position; // Number of bits before this port.
|
||||
struct { // Like struct t_vpi_vecval.
|
||||
int32_t aval;
|
||||
int32_t bval;
|
||||
} previous, new; // Previous and new values.
|
||||
__vpiHandle *handle; // Handle to the port's variable.
|
||||
struct ng_ghdl *ctx; // Pointer back to parent.
|
||||
};
|
||||
|
||||
#define IN_PENDING 1
|
||||
#define OUT_PENDING 2
|
||||
|
||||
/* Data strucure used to share context between the ngspice and GHDL threads. */
|
||||
|
||||
struct ng_ghdl {
|
||||
struct cr_ctx cr_ctx; // Coroutine context.
|
||||
int stop; // Indicates simulation is over.
|
||||
struct co_info *cosim_context;
|
||||
uint32_t ins; // Port counts by type.
|
||||
uint32_t outs;
|
||||
uint32_t inouts;
|
||||
double base_time; // SPICE time on entry.
|
||||
double tick_length; // GHDL's time unit.
|
||||
__vpiHandle *stop_cb; // Handle to end-of-tick callback.
|
||||
volatile uint32_t in_pending; // Counts of changed ports.
|
||||
volatile uint32_t out_pending;
|
||||
struct ngvp_port *ports; // Port information array.
|
||||
};
|
||||
|
||||
/* The VPI module, ghdlng.vpi, contains a global variable with this name,
|
||||
* used during initialisation.
|
||||
*/
|
||||
|
||||
#define CTX_VAR GHDLNG_VPI_context
|
||||
#define STR(s) #s
|
||||
#define XSTR(s) STR(s) // Puts quotes on its argument.
|
||||
#define CTX_VAR_NAME XSTR(CTX_VAR)
|
||||
#endif // _GHDL_SHIM_H_
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2023 Giles Atkinson
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <vpi_user.h>
|
||||
|
||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||
#include <windows.h> // Windows has a simple co-routine library - "Fibers"
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* The VVP code runs on its own stack, handled by cr_xxx() functions. */
|
||||
|
||||
#include "ngspice/coroutine_cosim.h"
|
||||
|
||||
#include "ngspice/cmtypes.h" // For Digital_t
|
||||
#include "ngspice/cosim.h"
|
||||
|
||||
/* This header file defines external interfaces. It also contains an initial
|
||||
* comment that describes how this VPI module is used.
|
||||
*/
|
||||
|
||||
#include "ghdl_shim.h"
|
||||
|
||||
/* Debugging printfs(). */
|
||||
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
#define DBG(...) vpi_printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DBG(...)
|
||||
#endif
|
||||
|
||||
/* This global variable is used only during initialisation and safe
|
||||
* so long as XSPICE instance initialisation is single-threaded. Ugly!
|
||||
*/
|
||||
|
||||
__declspec(dllexport) struct ng_ghdl *CTX_VAR; // Name is a macro.
|
||||
|
||||
|
||||
static PLI_INT32 next_advance_cb(struct t_cb_data *cb);
|
||||
|
||||
/* Get current simulation time: no module-specific values. */
|
||||
|
||||
static double get_time(struct ng_ghdl *ctx)
|
||||
{
|
||||
static struct t_vpi_time now = { .type = vpiSimTime };
|
||||
uint64_t ticks;
|
||||
|
||||
vpi_get_time(NULL, &now);
|
||||
ticks = ((uint64_t)now.high << 32) + now.low;
|
||||
return ticks * ctx->tick_length;
|
||||
}
|
||||
|
||||
/* Arrange for end_advance_cb() to be called in the future. */
|
||||
|
||||
static vpiHandle set_stop(uint64_t length, struct ng_ghdl *ctx)
|
||||
{
|
||||
static struct t_vpi_time now;
|
||||
static struct t_cb_data cbd = { .cb_rtn = next_advance_cb, .time = &now };
|
||||
|
||||
now.type = vpiSimTime;
|
||||
now.low = length;
|
||||
now.high = length >> 32;
|
||||
if (length == 0)
|
||||
cbd.reason = cbReadWriteSynch;
|
||||
else
|
||||
cbd.reason = cbAfterDelay;
|
||||
|
||||
/* Callback after delay. */
|
||||
|
||||
cbd.user_data = (PLI_BYTE8 *)ctx;
|
||||
return vpi_register_cb(&cbd);
|
||||
}
|
||||
|
||||
/* Timed callback at end of simulation advance: wait for a command
|
||||
* from the main thread, and schedule the next callback.
|
||||
* On return, VHDL runs some more.
|
||||
*/
|
||||
|
||||
static PLI_INT32 next_advance_cb(struct t_cb_data *cb)
|
||||
{
|
||||
struct ng_ghdl *ctx = (struct ng_ghdl *)cb->user_data;
|
||||
struct t_vpi_value val;
|
||||
double vl_time;
|
||||
uint64_t ticks;
|
||||
unsigned int i;
|
||||
|
||||
for (;;) {
|
||||
/* Still wanted? */
|
||||
|
||||
if (ctx->stop) {
|
||||
vpi_control(vpiFinish, 0); // Returns after scheduling $finish.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save base time for next slice. */
|
||||
|
||||
ctx->base_time = ctx->cosim_context->vtime;
|
||||
|
||||
/* Repeatedly wait for instructions from the main thread
|
||||
* until GHDL can advance at least one time unit.
|
||||
*/
|
||||
|
||||
cr_yield_to_spice(&ctx->cr_ctx);
|
||||
|
||||
/* Check for input. */
|
||||
|
||||
val.format = vpiVectorVal;
|
||||
i = ctx->ins ? 0 : ctx->outs;
|
||||
while (ctx->in_pending) {
|
||||
if (ctx->ports[i].flags & IN_PENDING) {
|
||||
ctx->ports[i].flags ^= IN_PENDING;
|
||||
val.value.vector =
|
||||
(struct t_vpi_vecval *)&ctx->ports[i].previous;
|
||||
vpi_put_value(ctx->ports[i].handle, &val, NULL, vpiNoDelay);
|
||||
ctx->in_pending--;
|
||||
DBG("VPI input %d/%d on %s\n",
|
||||
val.value.vector->aval, val.value.vector->bval,
|
||||
vpi_get_str(vpiName, ctx->ports[i].handle));
|
||||
} else if (++i == ctx->ins) {
|
||||
i = ctx->ins + ctx->outs; // Now scan inouts
|
||||
}
|
||||
}
|
||||
|
||||
/* How many GHDL ticks to advance? */
|
||||
|
||||
vl_time = get_time(ctx);
|
||||
if (ctx->cosim_context->vtime < vl_time) {
|
||||
/* This can occur legitimately as the two times need not
|
||||
* align exactly. But it should be less than one SPICE timestep.
|
||||
*/
|
||||
|
||||
DBG("VHDL time %.16g ahead of SPICE target %.16g\n",
|
||||
vl_time, ctx->cosim_context->vtime);
|
||||
if (ctx->cosim_context->vtime + ctx->tick_length < vl_time) {
|
||||
fprintf(stderr,
|
||||
"Error: time reversal (%.10g->%.10g) in "
|
||||
"GHDL shim VPI!\n",
|
||||
vl_time, ctx->cosim_context->vtime);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ticks = (ctx->cosim_context->vtime - vl_time) / ctx->tick_length;
|
||||
if (ticks > 0) {
|
||||
DBG("Advancing from %g (VHDL) to %g (SPICE): %lu ticks\n",
|
||||
vl_time, ctx->cosim_context->vtime, ticks);
|
||||
ctx->stop_cb = set_stop(ticks, ctx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback function - new output value. */
|
||||
|
||||
static PLI_INT32 output_cb(struct t_cb_data *cb)
|
||||
{
|
||||
struct ngvp_port *pp = (struct ngvp_port *)cb->user_data;
|
||||
struct ng_ghdl *ctx = pp->ctx;
|
||||
|
||||
DBG("Output: %s is %d now %g (VHDL) %g (SPICE)\n",
|
||||
vpi_get_str(vpiName, cb->obj),
|
||||
cb->value->value.vector->aval,
|
||||
get_time(ctx), ctx->cosim_context->vtime);
|
||||
|
||||
if (ctx->stop_cb) {
|
||||
/* First call in the current VHDL cycle: cancel the current
|
||||
* stop CB and request a new one at the next GHDL time point.
|
||||
* That allows all output events in the current timestep
|
||||
* to be gathered before stopping.
|
||||
*/
|
||||
|
||||
vpi_remove_cb(ctx->stop_cb);
|
||||
ctx->stop_cb = NULL;
|
||||
set_stop(0, ctx);
|
||||
|
||||
/* Set the output time in SPICE format.
|
||||
* It must not be earlier than entry time.
|
||||
*/
|
||||
|
||||
ctx->cosim_context->vtime = get_time(ctx);
|
||||
if (ctx->cosim_context->vtime < ctx->base_time)
|
||||
ctx->cosim_context->vtime = ctx->base_time;
|
||||
}
|
||||
|
||||
/* Record the value. */
|
||||
|
||||
pp->new.aval = cb->value->value.vector->aval;
|
||||
pp->new.bval = cb->value->value.vector->bval;
|
||||
if (!(pp->flags & OUT_PENDING)) {
|
||||
pp->flags |= OUT_PENDING;
|
||||
++ctx->out_pending;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Utilty functions for start_cb() - initialise or set watch on a variable.*/
|
||||
|
||||
static void init(vpiHandle handle)
|
||||
{
|
||||
static struct t_vpi_value val = { .format = vpiIntVal };
|
||||
|
||||
DBG("Initialising %s to 0\n", vpi_get_str(vpiName, handle));
|
||||
|
||||
vpi_put_value(handle, &val, NULL, vpiNoDelay);
|
||||
}
|
||||
|
||||
static void watch(vpiHandle handle, void *pp)
|
||||
{
|
||||
static struct t_vpi_time time = { .type = vpiSimTime };
|
||||
static struct t_vpi_value val = { .format = vpiVectorVal };
|
||||
static struct t_cb_data cb = {
|
||||
.reason = cbValueChange, .cb_rtn = output_cb,
|
||||
.time = &time, .value = &val
|
||||
};
|
||||
|
||||
cb.obj = handle;
|
||||
cb.user_data = pp;
|
||||
vpi_register_cb(&cb);
|
||||
}
|
||||
|
||||
/* Callback function - simulation is starting. */
|
||||
|
||||
static PLI_INT32 start_cb(struct t_cb_data *cb)
|
||||
{
|
||||
struct ng_ghdl *ctx = (struct ng_ghdl *)cb->user_data;
|
||||
vpiHandle iter, top, item;
|
||||
PLI_INT32 direction;
|
||||
char *name;
|
||||
int ii, oi, ioi;
|
||||
|
||||
DBG("Precision %d\n", vpi_get(vpiTimePrecision, NULL));
|
||||
ctx->tick_length = pow(10.0, vpi_get(vpiTimePrecision, NULL));
|
||||
|
||||
/* Find the (unique?) top-level module. */
|
||||
|
||||
iter = vpi_iterate(vpiModule, NULL);
|
||||
top = vpi_scan(iter);
|
||||
vpi_free_object(iter);
|
||||
DBG("Top %s\n", vpi_get_str(vpiName, top));
|
||||
|
||||
/* Count the ports. */
|
||||
|
||||
iter = vpi_iterate(vpiPort, top);
|
||||
if (!iter)
|
||||
vpi_printf("Top module has no ports!\n"); // vpi_scan() aborts.
|
||||
ctx->ins = ctx->outs = ctx->inouts = 0;
|
||||
while ((item = vpi_scan(iter))) {
|
||||
direction = vpi_get(vpiDirection, item);
|
||||
switch (direction) {
|
||||
case vpiInput:
|
||||
++ctx->ins;
|
||||
break;
|
||||
case vpiOutput:
|
||||
++ctx->outs;
|
||||
break;
|
||||
case vpiInout:
|
||||
++ctx->inouts;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->ports = (struct ngvp_port *)malloc(
|
||||
(ctx->ins + ctx->outs + ctx->inouts) *
|
||||
sizeof (struct ngvp_port));
|
||||
if (!ctx->ports) {
|
||||
vpi_printf("No memory for ports at " __FILE__ ":%d\n", __LINE__);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Get the ports. */
|
||||
|
||||
iter = vpi_iterate(vpiPort, top);
|
||||
ii = oi = ioi = 0;
|
||||
while ((item = vpi_scan(iter))) {
|
||||
struct ngvp_port *pp;
|
||||
int first;
|
||||
|
||||
direction = vpi_get(vpiDirection, item);
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
/* It seems that in GHDL, a port and the underlying net are the
|
||||
* same object.
|
||||
*/
|
||||
|
||||
DBG("Port %s direction %d size %d, type %d\n",
|
||||
name, direction, vpi_get(vpiSize, item),
|
||||
vpi_get(vpiType, item));
|
||||
|
||||
switch (direction) {
|
||||
case vpiInput:
|
||||
first = !ii;
|
||||
pp = ctx->ports + ii++;
|
||||
init(item);
|
||||
break;
|
||||
case vpiOutput:
|
||||
first = !oi;
|
||||
pp = ctx->ports + ctx->ins + oi++;
|
||||
watch(item, pp);
|
||||
break;
|
||||
case vpiInout:
|
||||
first = !ioi;
|
||||
init(item);
|
||||
pp = ctx->ports + ctx->ins + ctx->outs + ioi++;
|
||||
watch(item, pp);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
pp->bits = vpi_get(vpiSize, item);
|
||||
pp->flags = 0;
|
||||
pp->position = first ? 0 : pp[-1].position + pp[-1].bits;
|
||||
pp->previous.aval = pp->previous.bval = 0;
|
||||
pp->handle = item;
|
||||
pp->ctx = ctx;
|
||||
}
|
||||
|
||||
/* Make a direct call to the "end-of-advance" callback to start running. */
|
||||
|
||||
cr_init(&ctx->cr_ctx);
|
||||
cb->user_data = (PLI_BYTE8 *)ctx;
|
||||
next_advance_cb(cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VPI initialisation. */
|
||||
|
||||
static void start(void)
|
||||
{
|
||||
static struct t_vpi_time now = { .type = vpiSimTime };
|
||||
static struct t_cb_data cbd = { .reason = cbStartOfSimulation,
|
||||
.time = &now, .cb_rtn = start_cb };
|
||||
#ifdef DEBUG
|
||||
struct t_vpi_vlog_info info;
|
||||
|
||||
/* Get the program name. */
|
||||
|
||||
if (vpi_get_vlog_info(&info)) {
|
||||
vpi_printf("Starting vhdlng.vpi in %s\n", info.argv[0]);
|
||||
for (int i = 0; i < info.argc; ++i)
|
||||
vpi_printf("%d: %s\n", i, info.argv[i]);
|
||||
vpi_printf("P: %s V: %s\n", info.product, info.version);
|
||||
} else {
|
||||
vpi_printf("Failed to get invocation information.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The first step is to find the top-level module and query its ports.
|
||||
* At this point they do not exist, so request a callback once they do.
|
||||
*/
|
||||
|
||||
cbd.user_data = (PLI_BYTE8 *)CTX_VAR;
|
||||
vpi_register_cb(&cbd);
|
||||
}
|
||||
|
||||
/* This is a table of registration functions. It is the external symbol
|
||||
* that the GHDL simulator looks for when loading this .vpi module.
|
||||
*/
|
||||
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
start,
|
||||
0
|
||||
};
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
*ng_script_with_params
|
||||
// This Ngspice interpreter script accepts arbitrary arguments to
|
||||
// the GHDL compiler (VHDL to LLVM) 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 GHDL are required.
|
||||
quit
|
||||
end
|
||||
|
||||
// Disable special processing of '{'.
|
||||
|
||||
set noglob
|
||||
|
||||
if $oscompiled = 2 | $oscompiled = 3 | $oscompiled = 8 // Windows
|
||||
set windows=1
|
||||
set dirsep1="\\"
|
||||
set dirsep2="/"
|
||||
else
|
||||
set windows=0
|
||||
set dirsep1="/"
|
||||
if $oscompiled = 7 // MacOS needs an option to allow undefined symbols.
|
||||
setcs ld_magic="-Wl,-undefined,dynamic_lookup"
|
||||
else
|
||||
set ld_magic=""
|
||||
end
|
||||
end
|
||||
|
||||
// Is there a "-top" option first?
|
||||
|
||||
strcmp top "$argv[1]" "-top"
|
||||
if $top = 0
|
||||
if $argc < 3
|
||||
echo There must be at least one source file!
|
||||
quit
|
||||
end
|
||||
set base = "$argv[2]" // The top entity name for "ghdl -e".
|
||||
shift
|
||||
shift
|
||||
else
|
||||
// Loop through the arguments to find GHDL source: some_path/xxxx.vhd
|
||||
// or similar. 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" "-" // Is it an option?
|
||||
if $l = 0
|
||||
continue
|
||||
end
|
||||
|
||||
strstr l "$base" "" // Get string length
|
||||
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 off "$base" "." // Strip any file type suffix.
|
||||
if $off >= 0
|
||||
strslice base "$base" 0 $off
|
||||
end
|
||||
|
||||
strstr l "$base" "" // Check for zero-length string
|
||||
if $l > 0
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if index - 1 > $argc
|
||||
echo No file for top-level entity was found.
|
||||
quit
|
||||
end
|
||||
end
|
||||
|
||||
// Default base name of output file.
|
||||
|
||||
if $windows
|
||||
setcs tail=".DLL"
|
||||
else
|
||||
setcs tail=".so"
|
||||
end
|
||||
setcs soname="$base$tail"
|
||||
|
||||
// The shared library/DLL contains some ngspice source code as
|
||||
// well as that created by GHDL. Find it by scanning $sourcepath.
|
||||
|
||||
set shimfile=ghdl_shim.c
|
||||
set shimobj=ghdl_shim.o
|
||||
set srcdir=src
|
||||
set hfile="cmtypes.h"
|
||||
set hpath="ngspice$dirsep1$hfile"
|
||||
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
|
||||
// Look in any "src" subdirectory (probably in installed tree).
|
||||
set stem="$stem$dirsep1$srcdir"
|
||||
set fn="$stem$dirsep1$shimfile"
|
||||
fopen fh $fn
|
||||
end
|
||||
if $fh > 0
|
||||
// Found ghdl_shim.c, but it needs header files on relative path.
|
||||
fclose $fh
|
||||
set hn="$stem$dirsep1$hpath"
|
||||
fopen fh "$hn"
|
||||
if $fh > 0
|
||||
break
|
||||
end
|
||||
echo Ignoring source file "$fn" as "$hn" was not found.
|
||||
end
|
||||
end
|
||||
|
||||
if $fh > 0
|
||||
fclose $fh
|
||||
else
|
||||
echo Can not find C source file $shimfile
|
||||
quit
|
||||
end
|
||||
|
||||
// Some header files are with the source.
|
||||
|
||||
strstr off "$stem" "."
|
||||
if $off <> 0
|
||||
setcs include="-I$stem"
|
||||
else
|
||||
setcs include="-I..$dirsep1$stem" // Relative path
|
||||
end
|
||||
|
||||
// Check for ghdl_shim.o in the current directory. If not present, build it.
|
||||
|
||||
set silent_fileio
|
||||
fopen fh ghdl_shim.o
|
||||
if $fh < 0
|
||||
shell clang -c -g -fPIC $include -o ghdl_shim.o $stem/ghdl_shim.c
|
||||
else
|
||||
fclose $fh
|
||||
end
|
||||
unset silent_fileio
|
||||
|
||||
// Compile the VHDL code.
|
||||
|
||||
shell ghdl -a $argv
|
||||
strcmp bad "$shellstatus" "0"
|
||||
if $bad = 0
|
||||
shell ghdl -e -shared "-Wl,ghdl_shim.o" $base
|
||||
else
|
||||
quit
|
||||
end
|
||||
|
||||
// Check for ghdlng.vpi in the current directory. If not present, build it.
|
||||
|
||||
set silent_fileio
|
||||
fopen fh ghdlng.vpi
|
||||
if $fh < 0
|
||||
shell ghdl --vpi-compile clang -g -c -fdeclspec -Wno-ignored-attributes $include $stem/ghdl_vpi.c -o ghdl_vpi.o
|
||||
shell ghdl --vpi-link clang $ld_magic ghdl_vpi.o -o ghdlng.vpi -lm -lpthread
|
||||
else
|
||||
fclose $fh
|
||||
end
|
||||
unset silent_fileio
|
||||
|
||||
quit
|
||||
|
|
@ -79,3 +79,7 @@ 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
|
||||
copy xspice\verilog\coroutine*.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy xspice\vhdl\ghnggen %dst%\share\ngspice\scripts
|
||||
copy xspice\vhdl\ghdl_shim.* %dst%\share\ngspice\scripts\src
|
||||
copy xspice\vhdl\ghdl_vpi.c %dst%\share\ngspice\scripts\src
|
||||
|
|
|
|||
|
|
@ -80,3 +80,7 @@ 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
|
||||
copy xspice\verilog\coroutine*.h %dst%\share\ngspice\scripts\src\ngspice
|
||||
copy xspice\vhdl\ghnggen %dst%\share\ngspice\scripts
|
||||
copy xspice\vhdl\ghdl_shim.* %dst%\share\ngspice\scripts\src
|
||||
copy xspice\vhdl\ghdl_vpi.c %dst%\share\ngspice\scripts\src
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@
|
|||
#define CIDER 1
|
||||
/* don't undef CIDER, otherwise compilation will fail */
|
||||
|
||||
/* Support for Verilog-A(MS) models */
|
||||
/* #undef ADMS */
|
||||
/* ADMS compilation is not supported with MS Visual Studio */
|
||||
|
||||
/* Define if we want debug sensitivity analysis */
|
||||
/* #undef ASDEBUG */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue