diff --git a/configure.ac b/configure.ac index ee6ae707e..668a1e749 100644 --- a/configure.ac +++ b/configure.ac @@ -1228,6 +1228,32 @@ if test "x$enable_modsimd" = xyes; then ]) fi +# now adjust compiler flags +if test "x$enable_modsimd" = xyes; then + SIMD_CPPFLAGS="" + SIMD_LDFLAGS="" + + AC_MSG_CHECKING(whether compiler understands -fopenmp-simd) + old_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fopenmp-simd -Werror" + AC_TRY_COMPILE([],[], [ + AC_MSG_RESULT(yes) + SIMD_CFLAGS="-fopenmp-simd" + ],[ + AC_MSG_RESULT(no) + AC_MSG_WARN([Compiler might not understand pragma omp simd]) + SIMD_CFLAGS="" + ]) + CFLAGS="$old_CFLAGS" + + #add -ffast-math, might need to be adjusted depending on your compiler + SIMD_CFLAGS="$SIMD_CFLAGS -ffast-math" + + AC_SUBST(SIMD_CPPFLAGS) + AC_SUBST(SIMD_LDFLAGS) + AC_SUBST(SIMD_CFLAGS) +fi + if test "x$enable_modsimd" = xyes; then AC_DEFINE([BSIM3v32SIMD], [1], [simd acceleration for BSIM3V32 device]) @@ -1252,6 +1278,7 @@ AC_CONFIG_FILES([Makefile src/Makefile src/spicelib/Makefile src/spicelib/analysis/Makefile + src/spicelib/analysis/SIMD/Makefile src/spicelib/devices/Makefile src/spicelib/devices/asrc/Makefile src/spicelib/devices/bjt/Makefile diff --git a/examples/digital/adder32b_mos.cir b/examples/digital/adder32b_mos.cir index 28421b520..cf9d4a4bb 100644 --- a/examples/digital/adder32b_mos.cir +++ b/examples/digital/adder32b_mos.cir @@ -71,8 +71,8 @@ Xadd a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 .save V(a1) V(a2) V(a3) V(a4) V(b1) V(b2) V(b3) V(b4) * use BSIM3 model with default parameters -.model n1 nmos level=49 version=3.2.4 -.model p1 pmos level=49 version=3.2.4 +.model n1 nmos level=49 version=3.2.4simd +.model p1 pmos level=49 version=3.2.4simd *.include ./Modelcards/modelcard32.nmos *.include ./Modelcards/modelcard32.pmos diff --git a/src/Makefile.am b/src/Makefile.am index bb0f790b3..a4f8e480f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -151,6 +151,11 @@ ngspice_LDADD += \ spicelib/analysis/libckt.la \ spicelib/devices/libdev.la +if WANT_MODSIMD +ngspice_LDADD += \ + spicelib/analysis/SIMD/libcktsimd.la +endif + if SENSE2_WANTED ngspice_LDADD += unsupported/libunsupported.la endif @@ -435,6 +440,11 @@ libspice_la_LIBADD += \ spicelib/analysis/libckt.la \ spicelib/devices/libdev.la +if WANT_MODSIMD +libspice_la_LIBADD += \ + spicelib/analysis/SIMD/libcktsimd.la +endif + if XSPICE_WANTED libspice_la_LIBADD += \ xspice/evt/libevtxsp.la \ @@ -555,6 +565,11 @@ libngspice_la_LIBADD += \ spicelib/analysis/libckt.la \ spicelib/devices/libdev.la +if WANT_MODSIMD +libngspice_la_LIBADD += \ + spicelib/analysis/SIMD/libcktsimd.la +endif + if XSPICE_WANTED libngspice_la_LIBADD += \ xspice/evt/libevtxsp.la \ diff --git a/src/include/ngspice/SIMD/simdckt.h b/src/include/ngspice/SIMD/simdckt.h new file mode 100644 index 000000000..734d2f7bd --- /dev/null +++ b/src/include/ngspice/SIMD/simdckt.h @@ -0,0 +1,8 @@ +#ifndef ngspice_CKT_SIMD_H +#define ngspice_CKT_SIMD_H + +#include "ngspice/SIMD/simdvector.h" + +extern void vecN_CKTterr(VecNi , CKTcircuit *, double *); + +#endif diff --git a/src/include/ngspice/SIMD/simddef.h b/src/include/ngspice/SIMD/simddef.h new file mode 100644 index 000000000..42862d050 --- /dev/null +++ b/src/include/ngspice/SIMD/simddef.h @@ -0,0 +1,6 @@ +#ifndef NG_SIMD_DEF_H +#define NG_SIMD_DEF_H + +#define NSIMD 4 + +#endif diff --git a/src/include/ngspice/SIMD/simdop.h b/src/include/ngspice/SIMD/simdop.h new file mode 100644 index 000000000..6743a40b7 --- /dev/null +++ b/src/include/ngspice/SIMD/simdop.h @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright 2020 Florian Ballenegger, Anamosic Ballenegger Design + ******************************************************************************* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef NG_SIMD_OP_H +#define NG_SIMD_OP_H + +#include "ngspice/SIMD/simdvector.h" + +inline VecNd vecN_broadcast(double x) +{ + VecNd res; + for(int i=0;i b[i]) ? a[i] : b[i]; + return res; +} + +inline VecNd vecN_fabs(VecNd x) +{ + VecNd res; + for(int i=0;iCKTabstol + ckt->CKTreltol * + vecN_MAX( vecN_fabs(vecN_lu(ckt->CKTstate0,ccap)), vecN_fabs(vecN_lu(ckt->CKTstate1,ccap))); + + chargetol = vecN_MAX(vecN_fabs(vecN_lu(ckt->CKTstate0,qcap)),vecN_fabs(vecN_lu(ckt->CKTstate1,qcap))); + chargetol = ckt->CKTreltol * vecN_MAX(chargetol,vecN_broadcast(ckt->CKTchgtol))/ckt->CKTdelta; + tol = vecN_MAX(volttol,chargetol); + + /* now divided differences */ + for(i=ckt->CKTorder+1;i>=0;i--) { + diff[i] = vecN_lu(ckt->CKTstates[i],qcap); + } + for(i=0 ; i <= ckt->CKTorder ; i++) { + deltmp[i] = ckt->CKTdeltaOld[i]; + } + j = ckt->CKTorder; + for (;;) { + for(i=0;i <= j;i++) { + diff[i] = (diff[i] - diff[i+1])/deltmp[i]; + } + if (--j < 0) break; + for(i=0;i <= j;i++) { + deltmp[i] = deltmp[i+1] + ckt->CKTdeltaOld[i]; + } + } + switch(ckt->CKTintegrateMethod) { + case GEAR: + factor = gearCoeff[ckt->CKTorder-1]; + break; + + case TRAPEZOIDAL: + factor = trapCoeff[ckt->CKTorder - 1] ; + break; + } + del = ckt->CKTtrtol * tol/vecN_MAX(vecN_broadcast(ckt->CKTabstol),factor * vecN_fabs(diff[0])); + if(ckt->CKTorder == 2) { + del = vecN_sqrt(del); + } else if (ckt->CKTorder > 2) { + del = vecN_exp(vecN_log(del)/ckt->CKTorder); + } + /* now reduce with minimum */ + for(k=0;kBSIM3v32InstCount; idx++) { BSIM3v32instance *here = InstArray[idx]; - int local_error = BSIM3v32LoadOMP(here, ckt); + int local_error = BSIM3v32SIMDLoadOMP(here, ckt); if (local_error) error = local_error; } - BSIM3v32LoadRhsMat(inModel, ckt); + BSIM3v32SIMDLoadRhsMat(inModel, ckt); return error; } -int BSIM3v32LoadOMP(BSIM3v32instance *here, CKTcircuit *ckt) { +int BSIM3v32SIMDLoadOMP(BSIM3v32instance *here, CKTcircuit *ckt) { BSIM3v32model *model = BSIM3v32modPtr(here); #else BSIM3v32model *model = (BSIM3v32model*)inModel; @@ -3479,7 +3479,7 @@ return(OK); } #ifdef USE_OMP -void BSIM3v32LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt) +void BSIM3v32SIMDLoadRhsMat(GENmodel *inModel, CKTcircuit *ckt) { int InstCount, idx; BSIM3v32instance **InstArray; diff --git a/src/spicelib/devices/bsim3v32simd/b3v32ldsel.c b/src/spicelib/devices/bsim3v32simd/b3v32ldsel.c index ab6d8e42c..a4eaab0d1 100644 --- a/src/spicelib/devices/bsim3v32simd/b3v32ldsel.c +++ b/src/spicelib/devices/bsim3v32simd/b3v32ldsel.c @@ -40,7 +40,7 @@ extern int BSIM3v32LoadSeq(BSIM3v32instance *here, CKTcircuit *ckt, double* data, int stride); extern int BSIM3v32LoadSIMD(BSIM3v32instance **heres, CKTcircuit *ckt, double data[7][NSIMD]); #else -extern void BSIM3v32LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt); +extern void BSIM3v32SIMDLoadRhsMat(GENmodel *inModel, CKTcircuit *ckt); extern int BSIM3v32LoadSeq(BSIM3v32instance *here, CKTcircuit *ckt, int); extern int BSIM3v32LoadSIMD(BSIM3v32instance **heres, CKTcircuit *ckt); #endif @@ -147,7 +147,7 @@ BSIM3v32SIMDloadSel (GENmodel *inModel, CKTcircuit *ckt) } } - BSIM3v32LoadRhsMat(inModel, ckt); + BSIM3v32SIMDLoadRhsMat(inModel, ckt); return error; } @@ -251,7 +251,7 @@ BSIM3v32loadSelVrai (GENmodel *inModel, CKTcircuit *ckt) } if(DEBUG) printf("Now write the matrix\n"); /* Write in matrix sequentially */ - BSIM3v32LoadRhsMat(inModel, ckt); + BSIM3v32SIMDLoadRhsMat(inModel, ckt); return error; } diff --git a/src/spicelib/devices/bsim3v32simd/b3v32ldsimd.c b/src/spicelib/devices/bsim3v32simd/b3v32ldsimd.c index 1252f2cb5..f05ce9f42 100644 --- a/src/spicelib/devices/bsim3v32simd/b3v32ldsimd.c +++ b/src/spicelib/devices/bsim3v32simd/b3v32ldsimd.c @@ -40,6 +40,8 @@ #include "ngspice/devdefs.h" #include "ngspice/suffix.h" +#include "ngspice/SIMD/simdvector.h" + #if USEX86INTRINSICS==1 #include #endif diff --git a/src/spicelib/devices/bsim3v32simd/b3v32ldsimd4d.c b/src/spicelib/devices/bsim3v32simd/b3v32ldsimd4d.c index 80a43ae4b..4ca1fec6a 100644 --- a/src/spicelib/devices/bsim3v32simd/b3v32ldsimd4d.c +++ b/src/spicelib/devices/bsim3v32simd/b3v32ldsimd4d.c @@ -28,9 +28,6 @@ * POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -typedef double Vec4d __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4))); -typedef int64_t Vec4m __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4))); - #if USEX86INTRINSICS==1 static inline Vec4d vec4_blend(Vec4d fa, Vec4d tr, Vec4m mask) diff --git a/src/spicelib/devices/bsim3v32simd/b3v32ldsimd8d.c b/src/spicelib/devices/bsim3v32simd/b3v32ldsimd8d.c index edbcf4726..4c8fec468 100644 --- a/src/spicelib/devices/bsim3v32simd/b3v32ldsimd8d.c +++ b/src/spicelib/devices/bsim3v32simd/b3v32ldsimd8d.c @@ -28,9 +28,6 @@ * POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -typedef double Vec8d __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8))); -typedef int64_t Vec8m __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8))); - static inline Vec8d vec8_blend(Vec8d fa, Vec8d tr, Vec8m mask) { Vec8d r; diff --git a/src/spicelib/devices/bsim3v32simd/b3v32set.c b/src/spicelib/devices/bsim3v32simd/b3v32set.c index 2fb28befd..ee76d188f 100644 --- a/src/spicelib/devices/bsim3v32simd/b3v32set.c +++ b/src/spicelib/devices/bsim3v32simd/b3v32set.c @@ -1211,7 +1211,7 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ } } } - printf("BSIM3v32/SIMD has %d groups\n",ngroups); + printf("BSIM3v32/SIMD has %d groups and %d instances total\n",ngroups, InstCount); if (cp_getvar("no_modsimd", CP_BOOL, NULL, 0)) { printf("BSIM3v32 simd disabled at runtime\n"); diff --git a/src/spicelib/devices/bsim3v32simd/b3v32trunc.c b/src/spicelib/devices/bsim3v32simd/b3v32trunc.c index dd28e7219..055fb622c 100644 --- a/src/spicelib/devices/bsim3v32simd/b3v32trunc.c +++ b/src/spicelib/devices/bsim3v32simd/b3v32trunc.c @@ -14,10 +14,12 @@ #include "bsim3v32def.h" #include "ngspice/sperror.h" #include "ngspice/suffix.h" - +#include "ngspice/SIMD/simdvector.h" +#include "ngspice/SIMD/simdckt.h" +#include int -BSIM3v32SIMDtrunc (GENmodel *inModel, CKTcircuit *ckt, double *timeStep) +BSIM3v32SIMDtruncSeq (GENmodel *inModel, CKTcircuit *ckt, double *timeStep) { BSIM3v32model *model = (BSIM3v32model*)inModel; BSIM3v32instance *here; @@ -46,3 +48,60 @@ BSIM3v32instance *here; } return(OK); } + +/* omp multiprocessing is found to be counter-productive here, probably due to +overhead, so we disable it for the BSIM3v32SIMDtrunc function */ +#undef USE_OMP + +int +BSIM3v32SIMDtrunc (GENmodel *inModel, CKTcircuit *ckt, double *timeStep) +{ +BSIM3v32model *model = (BSIM3v32model*)inModel; +BSIM3v32instance *here; + +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + int i; + #ifndef USE_OMP + #define TIMESTEPptr timeStep + #else + double reduTimeStep = *timeStep; + #define TIMESTEPptr &locTimeStep + #pragma omp parallel for reduction(min:reduTimeStep) + #endif + for(i=0;iBSIM3v32InstCount;i+=NSIMD) + { + VecNi indexes; + #ifdef USE_OMP + double locTimeStep = *timeStep; + #endif + for(int k=0;kBSIM3v32InstanceArray[i+k]->BSIM3v32qb; + vecN_CKTterr(indexes,ckt,TIMESTEPptr); + for(int k=0;kBSIM3v32InstanceArray[i+k]->BSIM3v32qg; + vecN_CKTterr(indexes,ckt,TIMESTEPptr); + for(int k=0;kBSIM3v32InstanceArray[i+k]->BSIM3v32qd; + vecN_CKTterr(indexes,ckt,TIMESTEPptr); + #ifdef USE_OMP + reduTimeStep = fmin(reduTimeStep,locTimeStep); + #endif + } + #ifdef USE_OMP + *timeStep = reduTimeStep; + i=model->BSIM3v32InstCount & (NSIMD-1); + #endif + + /* less than NSIMD devices left: not worth to use openMP ? */ + for(;iBSIM3v32InstCount;i++) + { + CKTterr(model->BSIM3v32InstanceArray[i]->BSIM3v32qb,ckt,timeStep); + CKTterr(model->BSIM3v32InstanceArray[i]->BSIM3v32qg,ckt,timeStep); + CKTterr(model->BSIM3v32InstanceArray[i]->BSIM3v32qd,ckt,timeStep); + + } + + return(OK); +} diff --git a/src/spicelib/devices/bsim3v32simd/bsim3v32def.h b/src/spicelib/devices/bsim3v32simd/bsim3v32def.h index c15c3abbe..d1ff1067d 100644 --- a/src/spicelib/devices/bsim3v32simd/bsim3v32def.h +++ b/src/spicelib/devices/bsim3v32simd/bsim3v32def.h @@ -18,7 +18,7 @@ File: bsim3v32def.h #include "ngspice/noisedef.h" #ifdef BSIM3v32SIMD -#define NSIMD 4 +#include "ngspice/SIMD/simddef.h" #endif #define OMP_EFFMEM