CedarEDA / CedarSim.jl

Analog Circuit Simulator
Other
13 stars 0 forks source link

Bad macro expansion in JUNCAP #7

Closed Keno closed 2 months ago

Keno commented 2 months ago

Standalone example


@macroexpand va"""
// Mathematical constants
`define PI                    3.1415926535897931
`define SQRTPI                1.77245385090551603

// Physical constants
`define KELVINCONVERSION      273.15
`define KBOL                  1.3806505E-23
`define QELE                  1.6021918E-19
`define HBAR                  1.05457168E-34
`define MELE                  9.1093826E-31
`define EPSO                  8.8541878176E-12
`define EPSRSI                11.8

// Other constants
`define MINTEMP          -2.5e2
`define vbilow            5.0e-2
`define a                 2.0
`define epsch             0.1
`define dvbi              5.0e-2
`define epsav             1.0e-6
`define vbrmax            1.0e3
`define vmaxlarge         1.0e8
`define aerfc             0.29214664
`define twothirds         0.666666666666667

`define mypower(x,power,result) \
    if (power == 0.5) begin \
        result       =  sqrt(x); \
    end else begin \
        result       =  pow(x, power); \
    end

`define mypower2(x,power,result) \
    if (power == -1.0) begin \
        result       =  1.0 / (x); \
    end else begin \
        result       =  pow(x, power); \
    end

`define mypower3(x,power,result) \
    if (power == 4.0) begin \
        result       =  (x) * (x) * (x) * (x); \
    end else begin \
        result       =  pow(abs(x), power); \
    end

// Other constants
`define oneThird              3.3333333333333333e-01
`define twoThirds             6.6666666666666667e-01

`define se                    4.6051701859880916e+02
`define se05                  2.3025850929940458e+02
`define ke                    1.0e-200
`define ke05                  1.0e-100
`define keinv                 1.0e200
`define ke05inv               1.0e100

`define P3(u) (1.0 + (u) * (1.0 + 0.5 * ((u) * (1.0 + (u) * `oneThird))))

`define expl(x, res) \
    if (abs(x) < `se05) begin \
        res       = exp(x); \
    end else begin \
        if ((x) < 0.0) begin \
            res       = `ke05 / `P3(-`se05 - (x)); \
        end else begin \
            res       =  `ke05inv * `P3((x) - `se05); \
        end \
    end

`define expl_low(x, res) \
    if ((x) > -`se05) begin \
        res       =  exp(x); \
    end else begin \
        res       = `ke05 / `P3(-`se05 - (x)); \
    end

`define expl_high(x, res) \
    if ((x) < `se05) begin \
        res       = exp(x); \
    end else begin \
        res       =  `ke05inv * `P3((x) - `se05); \
    end

`define calcerfcexpmtat(y,m,result) \
    ysq          =  y * y; \
    if (y > 0.0) begin \
        terfc        =  1.0 / (1.0 + perfc * y); \
    end else begin \
        terfc        =  1.0 / (1.0 - perfc * y); \
    end \
    `expl_low(-ysq + m, tmp) \
    erfcpos = (`aerfc * terfc + berfc * (terfc * terfc) + cerfc * (terfc * terfc * terfc)) * tmp; \
    if (y > 0.0) begin \
        result       =  erfcpos; \
    end else begin \
        `expl_low(m, tmp) \
        result       =  2.0 * tmp - erfcpos; \
    end

`define hypfunction2(x,x0,eps,hyp2) \
    hyp2         =  0.5 * ((x) + (x0) - sqrt(((x) - (x0)) * ((x) - (x0)) + 4.0 * (eps) * (eps)));

`define hypfunction5(x,x0,eps,hyp5) \
    h1           =  4.0 * (eps) * (eps); \
    h2           =  (eps) / (x0); \
    h2d          =  (x) + (eps) * h2; \
    h3           =  (x0) + h2d; \
    h4           =  (x0) - h2d; \
    h5           =  sqrt(h4 * h4 + h1); \
    hyp5         =  2.0 * ((x) * (x0) / (h3 + h5));

`define juncapfunction(VAK,qpref,qpref2,vbiinv,one_minus_P,idsat,CSRH,CTAT,vbi,wdepnulr,VBIRinv,P,ftd,btatpart,atat,one_over_one_minus_P,CBBT,VBIR,wdepnulrinv,fbbt,VBR,VBRinv,PBR,fstop,slope,Ijprime,Qjprime) \
    `mypower((1.0 - vj * vbiinv), one_minus_P, tmp) \
    Qjprime      =  CFACTOR * (qpref * (1.0 - tmp) + qpref2 * (VAK - vj)); \
    id           =  idsat * idmult; \
    if ((CSRH == 0.0) && (CTAT == 0.0)) begin \
        isrh         =  0.0; \
    end else begin \
        vbi_minus_vjsrh =  vbi-vjsrh; \
        wsrhstep     =  1.0 - sqrt(1.0 - two_psistar / vbi_minus_vjsrh); \
        if (P == 0.5) begin \
            dwsrh        =  0.0; \
        end else begin \
            dwsrh        =  ((wsrhstep * wsrhstep * ln(wsrhstep) / (1.0 - wsrhstep)) + wsrhstep) * (1.0 - 2.0 * P); \
        end \
        wsrh         =  wsrhstep + dwsrh; \
        `mypower(vbi_minus_vjsrh * VBIRinv, P, tmp) \
        wdep         =  wdepnulr * tmp; \
        asrh         =  ftd * ((zinv - 1.0) * wdep); \
        isrh         =  CSRH * (asrh * wsrh); \
    end \
    if (CTAT == 0.0) begin \
        itat         =  0.0; \
    end else begin \
        btat         =  btatpart * ((wdep * one_minus_P) / vbi_minus_vjsrh); \
        twoatatoverthreebtat = (`twothirds * atat) / btat; \
        umaxbeforelimiting = twoatatoverthreebtat * twoatatoverthreebtat; \
        umax         =  sqrt(umaxbeforelimiting * umaxbeforelimiting / (umaxbeforelimiting * umaxbeforelimiting + 1.0)); \
        sqrtumax     =  sqrt(umax); \
        umaxpoweronepointfive = umax * sqrtumax; \
        `mypower2((1.0 + btat * umaxpoweronepointfive), (-P * one_over_one_minus_P), wgamma) \
        wtat         =  wsrh * wgamma / (wsrh + wgamma); \
        ktat         =  sqrt(0.375 * (btat / sqrtumax)); \
        ltat         =  2.0 * (twoatatoverthreebtat * sqrtumax) - umax; \
        mtat         =  atat * twoatatoverthreebtat * sqrtumax - atat * umax + 0.5 * (btat * umaxpoweronepointfive); \
        xerfc        =  (ltat - 1.0) * ktat; \
        `calcerfcexpmtat(xerfc, mtat, erfctimesexpmtat) \
        gammamax     = `SQRTPI * 0.5 * (atat * erfctimesexpmtat  / ktat); \
        itat         =  CTAT * (asrh * gammamax * wtat); \
    end \
    if (CBBT == 0.0) begin \
        ibbt         =  0.0; \
    end else begin \
        `mypower(((VBIR - vbbt) * VBIRinv), P, tmp) \
        Fmaxr        =  one_over_one_minus_P * ((VBIR - vbbt) * wdepnulrinv / tmp); \
        `expl(-fbbt / Fmaxr, tmp) \
        ibbt         =  CBBT * (VAK * Fmaxr * Fmaxr * tmp); \
    end \
    if (VBR > `vbrmax) begin \
        fbreakdown   =  1.0; \
    end else begin \
        if (vav > -alphaav * VBR) begin \
            `mypower3(vav * VBRinv, PBR, tmp) \
            fbreakdown    =  1.0 / (1.0 - tmp); \
        end else begin \
            fbreakdown    =  fstop + (vav + alphaav * VBR) * slope; \
        end \
    end \
    Ijprime      =  IFACTOR * (id + isrh + itat + ibbt) * fbreakdown;

`define juncapcommon(V, AB_i, LS_i, LG_i, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT_i, CTATBOT_i, vbibot, wdepnulrbot, VBIRBOTinv, PBOT_i, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT_i, VBIRBOT_i, wdepnulrinvbot, fbbtbot, VBRBOT_i, VBRinvbot, PBRBOT_i, fstopbot, slopebot, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI_i, CTATSTI_i, vbisti, wdepnulrsti, VBIRSTIinv, PSTI_i, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI_i, VBIRSTI_i, wdepnulrinvsti, fbbtsti, VBRSTI_i, VBRinvsti, PBRSTI_i, fstopsti, slopesti, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT_i, CTATGAT_i, vbigat, wdepnulrgat, VBIRGATinv, PGAT_i, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT_i, VBIRGAT_i, wdepnulrinvgat, fbbtgat, VBRGAT_i, VBRinvgat, PBRGAT_i, fstopgat, slopegat, VMAX, exp_VMAX_over_phitd, vbimin, vch, vfmin, vbbtlim, ijunbot, qjunbot, ijunsti, qjunsti, ijungat, qjungat) \
    vbbt         =  0.0; \
    two_psistar  =  0.0; \
    if ( !( ((AB_i) == 0.0) && ((LS_i) == 0.0) && ((LG_i) == 0.0) ) ) begin \
        `hypfunction5(V, vfmin, vch, vj) \
        if (V < VMAX)  begin \
            `expl(0.5 * (V * phitdinv), zinv) \
            idmult       =  zinv * zinv; \
        end else begin \
            idmult       =  (1.0 + (V - VMAX) * phitdinv) * exp_VMAX_over_phitd; \
            zinv         =  sqrt(idmult); \
        end \
        idmult       =  idmult - 1.0; \
        z            =  1.0 / zinv; \
        if (V > 0.0) begin \
            two_psistar    =  2.0 * (phitd * ln(2.0 + z + sqrt((z + 1.0) * (z + 3.0)))); \
        end else begin \
            two_psistar    = -V + 2.0 * (phitd * ln(2.0 * zinv + 1.0 + sqrt((1.0 + zinv) * (1.0 + 3.0 * zinv)))); \
        end \
        vjlim        =  vbimin - two_psistar; \
        `hypfunction2(V, vjlim, phitd, vjsrh) \
        `hypfunction2(V, vbbtlim, phitr, vbbt) \
        `hypfunction2(V, 0.0, `epsav, vav) \
    end \
    if ((AB_i) == 0.0) begin \
        ijunbot      =  0.0; \
        qjunbot      =  0.0; \
    end else begin \
        `juncapfunction(V, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT_i, CTATBOT_i, vbibot, wdepnulrbot, VBIRBOTinv, PBOT_i, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT_i, VBIRBOT_i, wdepnulrinvbot, fbbtbot, VBRBOT_i, VBRinvbot, PBRBOT_i, fstopbot, slopebot, ijunbot, qjunbot) \
    end \
    if ((LS_i) == 0.0) begin \
        ijunsti      =  0.0; \
        qjunsti      =  0.0; \
    end else begin \
        `juncapfunction(V, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI_i, CTATSTI_i, vbisti, wdepnulrsti, VBIRSTIinv, PSTI_i, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI_i, VBIRSTI_i, wdepnulrinvsti, fbbtsti, VBRSTI_i, VBRinvsti, PBRSTI_i, fstopsti, slopesti, ijunsti, qjunsti) \
    end \
    if ((LG_i) == 0.0) begin \
        ijungat      =  0.0; \
        qjungat      =  0.0; \
    end else begin \
        `juncapfunction(V, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT_i, CTATGAT_i, vbigat, wdepnulrgat, VBIRGATinv, PGAT_i, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT_i, VBIRGAT_i, wdepnulrinvgat, fbbtgat, VBRGAT_i, VBRinvgat, PBRGAT_i, fstopgat, slopegat, ijungat, qjungat) \
    end

// Part 1
`define JuncapExpressInit1(AB_i, LS_i, LG_i, VJUNREF_i, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT_i, CTATBOT_i, vbibot, wdepnulrbot, VBIRBOTinv, PBOT_i, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT_i, VBIRBOT_i, wdepnulrinvbot, fbbtbot, VBRBOT_i, VBRinvbot, PBRBOT_i, fstopbot, slopebot, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI_i, CTATSTI_i, vbisti, wdepnulrsti, VBIRSTIinv, PSTI_i, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI_i, VBIRSTI_i, wdepnulrinvsti, fbbtsti, VBRSTI_i, VBRinvsti, PBRSTI_i, fstopsti, slopesti, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT_i, CTATGAT_i, vbigat, wdepnulrgat, VBIRGATinv, PGAT_i, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT_i, VBIRGAT_i, wdepnulrinvgat, fbbtgat, VBRGAT_i, VBRinvgat, PBRGAT_i, fstopgat, slopegat, VMAX, exp_VMAX_over_phitd, vbimin, vch, vfmin, vbbtlim) \
    FRACNA       =  0.4; \
    FRACNB       =  0.65; \
    FRACI        =  0.8; \
    /* Sample voltages */ \
    V1           = -FRACNA * VJUNREF_i; \
    V2           = -FRACNB * VJUNREF_i; \
    V3           = -FRACI * VJUNREF_i; \
    V4           =  0.1; \
    V5           =  0.2; \
    /*  Evaluate full JUNCAP-model at five voltages */ \
    `juncapcommon(V1, AB_i, LS_i, LG_i, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT_i, CTATBOT_i, vbibot, wdepnulrbot, VBIRBOTinv, PBOT_i, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT_i, VBIRBOT_i, wdepnulrinvbot, fbbtbot, VBRBOT_i, VBRinvbot, PBRBOT_i, fstopbot, slopebot, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI_i, CTATSTI_i, vbisti, wdepnulrsti, VBIRSTIinv, PSTI_i, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI_i, VBIRSTI_i, wdepnulrinvsti, fbbtsti, VBRSTI_i, VBRinvsti, PBRSTI_i, fstopsti, slopesti, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT_i, CTATGAT_i, vbigat, wdepnulrgat, VBIRGATinv, PGAT_i, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT_i, VBIRGAT_i, wdepnulrinvgat, fbbtgat, VBRGAT_i, VBRinvgat, PBRGAT_i, fstopgat, slopegat, VMAX, exp_VMAX_over_phitd, vbimin, vch, vfmin, vbbtlim, ijunbot, qjunbot, ijunsti, qjunsti, ijungat, qjungat) \
    I1           =  AB_i * ijunbot + LS_i * ijunsti + LG_i * ijungat; \
    `juncapcommon(V2, AB_i, LS_i, LG_i, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT_i, CTATBOT_i, vbibot, wdepnulrbot, VBIRBOTinv, PBOT_i, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT_i, VBIRBOT_i, wdepnulrinvbot, fbbtbot, VBRBOT_i, VBRinvbot, PBRBOT_i, fstopbot, slopebot, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI_i, CTATSTI_i, vbisti, wdepnulrsti, VBIRSTIinv, PSTI_i, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI_i, VBIRSTI_i, wdepnulrinvsti, fbbtsti, VBRSTI_i, VBRinvsti, PBRSTI_i, fstopsti, slopesti, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT_i, CTATGAT_i, vbigat, wdepnulrgat, VBIRGATinv, PGAT_i, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT_i, VBIRGAT_i, wdepnulrinvgat, fbbtgat, VBRGAT_i, VBRinvgat, PBRGAT_i, fstopgat, slopegat, VMAX, exp_VMAX_over_phitd, vbimin, vch, vfmin, vbbtlim, ijunbot, qjunbot, ijunsti, qjunsti, ijungat, qjungat) \
    I2           =  AB_i * ijunbot + LS_i * ijunsti + LG_i * ijungat; \
    `juncapcommon(V3, AB_i, LS_i, LG_i, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT_i, CTATBOT_i, vbibot, wdepnulrbot, VBIRBOTinv, PBOT_i, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT_i, VBIRBOT_i, wdepnulrinvbot, fbbtbot, VBRBOT_i, VBRinvbot, PBRBOT_i, fstopbot, slopebot, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI_i, CTATSTI_i, vbisti, wdepnulrsti, VBIRSTIinv, PSTI_i, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI_i, VBIRSTI_i, wdepnulrinvsti, fbbtsti, VBRSTI_i, VBRinvsti, PBRSTI_i, fstopsti, slopesti, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT_i, CTATGAT_i, vbigat, wdepnulrgat, VBIRGATinv, PGAT_i, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT_i, VBIRGAT_i, wdepnulrinvgat, fbbtgat, VBRGAT_i, VBRinvgat, PBRGAT_i, fstopgat, slopegat, VMAX, exp_VMAX_over_phitd, vbimin, vch, vfmin, vbbtlim, ijunbot, qjunbot, ijunsti, qjunsti, ijungat, qjungat) \
    I3           =  AB_i * ijunbot + LS_i * ijunsti + LG_i * ijungat;

module test(x);
analog begin
    `JuncapExpressInit1(ABSOURCE_i, LSSOURCE_i, LGSOURCE_i, VJUNREF, qprefbot, qpref2bot, vbiinvbot, one_minus_PBOT, idsatbot, CSRHBOT, CTATBOT, vbibot, wdepnulrbot, VBIRBOTinv, PBOT, ftdbot, btatpartbot, atatbot, one_over_one_minus_PBOT, CBBTBOT, VBIRBOT, wdepnulrinvbot, fbbtbot, VBRBOT, VBRinvbot, PBRBOT, fstopbot, slopebot, qprefsti, qpref2sti, vbiinvsti, one_minus_PSTI, idsatsti, CSRHSTI, CTATSTI, vbisti, wdepnulrsti, VBIRSTIinv, PSTI, ftdsti, btatpartsti, atatsti, one_over_one_minus_PSTI, CBBTSTI, VBIRSTI, wdepnulrinvsti, fbbtsti, VBRSTI, VBRinvsti, PBRSTI, fstopsti, slopesti, qprefgat, qpref2gat, vbiinvgat, one_minus_PGAT, idsatgat, CSRHGAT, CTATGAT, vbigat, wdepnulrgat, VBIRGATinv, PGAT, ftdgat, btatpartgat, atatgat, one_over_one_minus_PGAT, CBBTGAT, VBIRGAT, wdepnulrinvgat, fbbtgat, VBRGAT, VBRinvgat, PBRGAT, fstopgat, slopegat, VMAX_s, exp_VMAX_over_phitd_s, vbimin_s, vch_s, vfmin_s, vbbtlim_s)

end
endmodule
"""

VMAX_s is not subsituted for VMAX in the inner macro expansion.

Keno commented 2 months ago

Reduced:

va"""
`define f(arg) arg
`define g(arg) `f(arg)

module test(x);
    analog begin
        `g(VMAX_s) = 1;
    end
endmodule
"""
Keno commented 2 months ago

Fixing the reduction alone doesn't fix the full testcase. There's a similar issue with the expansion of one_over_one_minus_P.

Keno commented 2 months ago

Reduced to just that part:

@macroexpand va"""
`define mypower2(x,power,result) \
    if (power == -1.0) begin \
        result       =  1.0 / (x); \
    end else begin \
        result       =  pow(x, power); \
    end

`define juncapfunction(P,one_over_one_minus_P) \
    `mypower2(abc, (-P * one_over_one_minus_P), wgamma)

`define juncapcommon(PBOT_i, one_over_one_minus_PBOT) \
        `juncapfunction(PBOT_i, one_over_one_minus_PBOT)

`define JuncapExpressInit1(PBOT_i, one_over_one_minus_PBOT) \
    `juncapcommon(PBOT_i, one_over_one_minus_PBOT)

module test(x);
analog begin
    `JuncapExpressInit1(PBOT, one_over_one_minus_PBOT)
end
endmodule
"""

and fully minimized:

@macroexpand va"""
`define f(a) a
`define g(b,c) `f((b * c))

module test(x);
real foo;
analog begin
    foo = `g(PBOT, one_over_one_minus_PBOT);
end
endmodule
"""
Keno commented 2 months ago

Fixed internally, will be pushed with next rebase.