diff --git a/integration_tests/VAMS2023_TRANSITION_TOL/vams2023_transition_tol.va b/integration_tests/VAMS2023_TRANSITION_TOL/vams2023_transition_tol.va new file mode 100644 index 00000000..32d44ea9 --- /dev/null +++ b/integration_tests/VAMS2023_TRANSITION_TOL/vams2023_transition_tol.va @@ -0,0 +1,33 @@ +// VAMS-2023 4.5.9 / Table 4-20 (Mantis 7810): every argument of +// +// transition ( expr [ , td [ , rise_time [ , fall_time [ , time_tol ] ] ] ] ) +// +// is a dynamic expression. Earlier revisions required `time_tol` to be a +// constant expression. +`include "disciplines.vams" + +module vams2023_transition_tol(a, c); + inout a, c; + electrical a, c; + + parameter real r = 1000.0 from (0.0:inf); + parameter real base = 1e-9 from (0.0:inf); + parameter real thresh = 0.5; + + real level; + real speed; + real tol; + real drive; + + analog begin + level = (V(a, c) > thresh) ? 1.0 : 0.0; + + // rise time, fall time and time tolerance are all computed at run time + speed = base * (1.0 + r / 1000.0); + tol = speed / 100.0; + + drive = transition(level, 0.0, speed, 2.0 * speed, tol); + + I(a, c) <+ drive * V(a, c) / r; + end +endmodule diff --git a/openvaf/hir_lower/src/expr.rs b/openvaf/hir_lower/src/expr.rs index 5ceb8be0..14780cc4 100644 --- a/openvaf/hir_lower/src/expr.rs +++ b/openvaf/hir_lower/src/expr.rs @@ -916,6 +916,12 @@ impl BodyLoweringCtx<'_, '_, '_> { // time constant is the rise time when the target is increasing and // the fall time when decreasing — a continuous output the solver // integrates through, with the requested transition speed. + // + // `transition(expr, td, rise_time, fall_time, time_tol)`: the + // delay and the (dynamic, VAMS-2023 Table 4-20) `time_tol` do not + // affect this continuous realization and are ignored - `time_tol` + // bounds how precisely a simulator places the time point of the + // transition, which a lag has no notion of. let eps = self.ctx.fconst(1e-12); let rise = if args.len() > 2 { self.lower_expr(args[2]) } else { eps }; let fall = if args.len() > 3 { self.lower_expr(args[3]) } else { rise }; diff --git a/openvaf/hir_ty/src/builtin.rs b/openvaf/hir_ty/src/builtin.rs index 0d668d31..c099cc16 100644 --- a/openvaf/hir_ty/src/builtin.rs +++ b/openvaf/hir_ty/src/builtin.rs @@ -266,12 +266,15 @@ bultins! { } + // VAMS-2023 4.5.9: + // transition ( expr [ , td [ , rise_time [ , fall_time [ , time_tol ] ] ] ] ) + // Every argument is a dynamic expression (Table 4-20, Mantis 7810). TRANSITION = const { fn TRANSITION_NO_ARGS(Val(Real)) -> Real; fn TRANSITION_DELAY(Val(Real),Val(Real)) -> Real; - fn TRANSITION_DELAY_RISET(Val(Real),Val(Real)) -> Real; - fn TRANSITION_DELAY_RISET_FALLT(Val(Real),Val(Real),Val(Real)) -> Real; - fn TRANSITION_DELAY_RISET_FALLT_TOL(Val(Real),Val(Real),Val(Real), Val(Real)) -> Real; + fn TRANSITION_DELAY_RISET(Val(Real),Val(Real),Val(Real)) -> Real; + fn TRANSITION_DELAY_RISET_FALLT(Val(Real),Val(Real),Val(Real),Val(Real)) -> Real; + fn TRANSITION_DELAY_RISET_FALLT_TOL(Val(Real),Val(Real),Val(Real),Val(Real),Val(Real)) -> Real; } diff --git a/openvaf/hir_ty/src/inference.rs b/openvaf/hir_ty/src/inference.rs index 4c16cb44..c49ee14e 100755 --- a/openvaf/hir_ty/src/inference.rs +++ b/openvaf/hir_ty/src/inference.rs @@ -665,9 +665,12 @@ impl Ctx<'_> { return (default_return_ty(info.signatures), false); } - if info.max_args.map_or(false, |max_args| max_args < args.len()) { + if let Some(max_args) = info.max_args.filter(|&max_args| max_args < args.len()) { + // the "too many arguments" message has to report the maximum, not the + // minimum (which produced "expected at most 1 arguments" for every + // over-long call to an operator with optional arguments) self.result.diagnostics.push(InferenceDiagnostic::ArgCntMismatch { - expected: info.min_args, + expected: max_args, found: args.len(), expr, exact, diff --git a/openvaf/hir_ty/src/validation/body.rs b/openvaf/hir_ty/src/validation/body.rs index a24a4603..cc89d3c0 100644 --- a/openvaf/hir_ty/src/validation/body.rs +++ b/openvaf/hir_ty/src/validation/body.rs @@ -13,7 +13,6 @@ use syntax::name::{AsIdent, Name}; use crate::builtin::{ ABSDELAY_MAX, DDT_TOL, IDT_IC_ASSERT_TOL, NATURE_ACCESS_BRANCH, NATURE_ACCESS_NODES, NATURE_ACCESS_NODE_GND, NATURE_ACCESS_PORT_FLOW, NOISE_TABLE_INLINE, NOISE_TABLE_INLINE_NAME, - TRANSITION_DELAY_RISET_FALLT_TOL, }; use crate::db::HirTyDB; use crate::inference::{BranchWrite, InferenceResult, ResolvedFun}; @@ -816,8 +815,11 @@ impl ExprValidator<'_, '_> { } } + // NOTE: `transition` is deliberately absent. VAMS-2023 Table 4-20 + // (Mantis 7810) lists all of its arguments - including `time_tol` - + // as dynamic expressions; only `absdelay`'s `maxdelay`, `ddt`'s and + // `idt`/`idtmod`'s `abstol` are still constant expressions. (BuiltIn::absdelay, Some(ABSDELAY_MAX)) - | (BuiltIn::transition, Some(TRANSITION_DELAY_RISET_FALLT_TOL)) | (BuiltIn::ddt, Some(DDT_TOL)) | (BuiltIn::idt | BuiltIn::idtmod, Some(IDT_IC_ASSERT_TOL)) => { if let [other_args @ .., const_expr] = args { diff --git a/openvaf/test_data/osdi/vams2023_transition_tol.snap b/openvaf/test_data/osdi/vams2023_transition_tol.snap new file mode 100644 index 00000000..20b8f257 --- /dev/null +++ b/openvaf/test_data/osdi/vams2023_transition_tol.snap @@ -0,0 +1,22 @@ +param "$mfactor" +units = "", desc = "Multiplier (Verilog-A $mfactor)", flags = ParameterFlags(PARA_KIND_INST) +param "r" +units = "", desc = "", flags = ParameterFlags(0x0) +param "base" +units = "", desc = "", flags = ParameterFlags(0x0) +param "thresh" +units = "", desc = "", flags = ParameterFlags(0x0) + +2 terminals +node "a" units = "V", runits = "A" +node "c" units = "V", runits = "A" +node "implicit_equation_0" units = "", runits = "" +jacobian (a, a) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT_CONST) +jacobian (a, c) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT_CONST) +jacobian (a, implicit_equation_0) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT_CONST) +jacobian (c, a) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT_CONST) +jacobian (c, c) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT_CONST) +jacobian (c, implicit_equation_0) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT_CONST) +jacobian (implicit_equation_0, implicit_equation_0) JacobianFlags(JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT | JACOBIAN_ENTRY_REACT_CONST) +0 states +has bound_step false diff --git a/openvaf/test_data/ui/transition_tolerance.va b/openvaf/test_data/ui/transition_tolerance.va new file mode 100644 index 00000000..44d9dcd6 --- /dev/null +++ b/openvaf/test_data/ui/transition_tolerance.va @@ -0,0 +1,36 @@ +// VAMS-2023 4.5.9 / Table 4-20 (Mantis 7810): +// +// transition ( expr [ , td [ , rise_time [ , fall_time [ , time_tol ] ] ] ] ) +// +// All five arguments are dynamic expressions, so none of them has to be a +// constant expression. +module transition_tolerance; + parameter real tr = 1e-9; + parameter real tf = 2e-9; + + real level; + real speed; + real tol; + real y1; + real y2; + real y3; + real y4; + real y5; + + analog begin + level = 1.0; + speed = tr; + tol = tf / 100.0; + + // all argument counts from one to five are accepted + y1 = transition(level); + y2 = transition(level, 0.0); + y3 = transition(level, 0.0, tr); + y4 = transition(level, 0.0, tr, tf); + y5 = transition(level, 0.0, tr, tf, tol); + + // and every argument may be a run-time expression, including the + // fall time and the time tolerance + y1 = transition(level, 0.0, speed, speed * 2.0, speed / 100.0); + end +endmodule diff --git a/openvaf/test_data/ui/transition_tolerance_err.log b/openvaf/test_data/ui/transition_tolerance_err.log new file mode 100644 index 00000000..50bd5cec --- /dev/null +++ b/openvaf/test_data/ui/transition_tolerance_err.log @@ -0,0 +1,24 @@ +error: invalid argument count: expected at most 5 arguments but found 6 + --> /transition_tolerance_err.va:14:13 + | +14 | y = transition(level, 0.0, 1e-9, 2e-9, 1e-12, 1.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 5 arguments + +error: constant expressions must not contain variable references + --> /transition_tolerance_err.va:17:24 + | + 6 | real dyn_tol; + | ------- help: 'dyn_tol' was declared here + . +17 | y = ddt(level, dyn_tol); + | ^^^^^^^ not allowed here + +error: constant expressions must not contain variable references + --> /transition_tolerance_err.va:20:35 + | + 6 | real dyn_tol; + | ------- help: 'dyn_tol' was declared here + . +20 | y = absdelay(level, 1e-9, dyn_tol); + | ^^^^^^^ not allowed here + diff --git a/openvaf/test_data/ui/transition_tolerance_err.va b/openvaf/test_data/ui/transition_tolerance_err.va new file mode 100644 index 00000000..e2621376 --- /dev/null +++ b/openvaf/test_data/ui/transition_tolerance_err.va @@ -0,0 +1,22 @@ +// `transition` still takes at most five arguments, and the analog operators +// whose tolerance VAMS-2023 Table 4-20 keeps as a *constant* expression are +// unaffected by Mantis 7810. +module transition_tolerance_err; + real level; + real dyn_tol; + real y; + + analog begin + level = 1.0; + dyn_tol = 1e-12 * level; + + // one argument too many + y = transition(level, 0.0, 1e-9, 2e-9, 1e-12, 1.0); + + // `ddt`'s abstol is still a constant expression argument + y = ddt(level, dyn_tol); + + // ... and so is `absdelay`'s maxdelay + y = absdelay(level, 1e-9, dyn_tol); + end +endmodule