From ea1b141d133b9a3b4d3c9d1820c8d5315f982f82 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 4 Dec 2022 17:30:51 -0500 Subject: [PATCH] Support probablity distribution functions. --- include/verilated_funcs.h | 11 ++ include/verilated_probdist.cpp | 240 +++++++++++++++++++++++++++++ src/V3AstNodeExpr.h | 102 ++++++++++++ src/V3EmitCInlines.cpp | 8 + src/V3EmitCMake.cpp | 3 + src/V3EmitMk.cpp | 1 + src/V3Global.h | 3 + src/V3LinkLValue.cpp | 15 ++ src/V3Width.cpp | 15 ++ src/verilog.l | 7 + src/verilog.y | 14 ++ test_regress/t/t_probdist.pl | 4 +- test_regress/t/t_probdist.v | 35 ++++- test_regress/t/t_probdist_bad.out | 19 --- test_regress/t/t_probdist_bad.pl | 4 +- test_regress/t/t_probdist_cmake.pl | 25 +++ test_regress/t/t_verilated_all.v | 9 +- 17 files changed, 486 insertions(+), 29 deletions(-) create mode 100644 include/verilated_probdist.cpp delete mode 100644 test_regress/t/t_probdist_bad.out create mode 100755 test_regress/t/t_probdist_cmake.pl diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 7cf7604f6..fe6e98574 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -2155,6 +2155,17 @@ extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE; extern IData VL_FGETS_NI(std::string& dest, IData fpi); +//====================================================================== +// Dist functions + +extern IData VL_DIST_CHI_SQUARE(IData& seedr, IData udeg_of_free) VL_MT_SAFE; +extern IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE; +extern IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE; +extern IData VL_DIST_NORMAL(IData& seedr, IData umean, IData udeviation) VL_MT_SAFE; +extern IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE; +extern IData VL_DIST_T(IData& seedr, IData udeg_of_free) VL_MT_SAFE; +extern IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE; + //====================================================================== // Conversion functions diff --git a/include/verilated_probdist.cpp b/include/verilated_probdist.cpp new file mode 100644 index 000000000..d0b5f39ed --- /dev/null +++ b/include/verilated_probdist.cpp @@ -0,0 +1,240 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Code available from: https://verilator.org +// +// Copyright 2003-2022 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//========================================================================= +/// +/// \file +/// \brief Verilated probability distribution implementation code +/// +/// Verilator always adds this file to the Makefile for the linker. +/// +/// Those macro/function/variable starting or ending in _ are internal, +/// however many of the other function/macros here are also internal. +/// +//========================================================================= + +#include "verilated_config.h" +#include "verilatedos.h" + +#include "verilated.h" + +//=========================================================================== +// Dist + +static double _vl_dbase_uniform(IData& seedr, int32_t start, int32_t end) VL_MT_SAFE { + union u_s { + float s; + unsigned stemp; + } u; + + const double d = 0.00000011920928955078125; + if (VL_UNLIKELY(seedr == 0)) seedr = 259341593; + + double a; + double b; + if (VL_UNCOVERABLE(start >= end)) { // With current usage shound't occur + a = 0.0; // LCOV_EXCL_LINE + b = 2147483647.0; // LCOV_EXCL_LINE + } else { + a = static_cast(start); + b = static_cast(end); + } + seedr = 69069 * seedr + 1; + u.stemp = seedr; + u.stemp = (u.stemp >> 9) | 0x3f800000; + + double c = static_cast(u.s); + c = c + (c * d); + c = ((b - a) * (c - 1.0)) + a; + return c; +} + +static double _vl_dbase_normal(IData& seedr, int32_t mean, int32_t deviation) VL_MT_SAFE { + double v1 = 0.0; + double v2 = 0.0; + double s = 1.0; + while ((s >= 1.0) || (s == 0.0)) { + v1 = _vl_dbase_uniform(seedr, -1, 1); + v2 = _vl_dbase_uniform(seedr, -1, 1); + s = v1 * v1 + v2 * v2; + } + s = v1 * std::sqrt(-2.0 * log(s) / s); + v1 = static_cast(deviation); + v2 = static_cast(mean); + return (s * v1 + v2); +} + +static double _vl_dbase_exponential(IData& seedr, int32_t mean) VL_MT_SAFE { + double n = _vl_dbase_uniform(seedr, 0, 1); + if (n != 0) n = -log(n) * mean; + return n; +} + +static double _vl_dbase_chi_square(IData& seedr, int32_t deg_of_free) VL_MT_SAFE { + double x; + if (deg_of_free % 2) { + x = _vl_dbase_normal(seedr, 0, 1); + x = x * x; + } else { + x = 0.0; + } + for (int32_t k = 2; k <= deg_of_free; k += 2) x = x + 2 * _vl_dbase_exponential(seedr, 1); + return x; +} + +IData VL_DIST_CHI_SQUARE(IData& seedr, IData udf) VL_MT_SAFE { + const int32_t df = static_cast(udf); + if (VL_UNLIKELY(df <= 0)) { + // Chi_square distribution must have positive degree of freedom + return 0; + } + double r = _vl_dbase_chi_square(seedr, df); + int32_t i; + if (r >= 0) { + i = static_cast(r + 0.5); + } else { + r = -r; // LCOV_EXCL_LINE + i = static_cast(r + 0.5); // LCOV_EXCL_LINE + i = -i; // LCOV_EXCL_LINE + } + return static_cast(i); +} + +IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE { + const int32_t k = static_cast(uk); + const int32_t mean = static_cast(umean); + if (VL_UNLIKELY(k <= 0)) { + // k-stage erlangian distribution must have positive k + return 0; + } + double x = 1.0; + for (int32_t i = 1; i <= k; i++) { x = x * _vl_dbase_uniform(seedr, 0, 1); } + const double a = static_cast(mean); + const double b = static_cast(k); + double r = -a * log(x) / b; + int32_t i; + if (r >= 0) { + i = static_cast(r + 0.5); + } else { + r = -r; + i = static_cast(r + 0.5); + i = -i; + } + return static_cast(i); +} + +IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE { + const int32_t mean = static_cast(umean); + if (VL_UNLIKELY(mean <= 0)) { + // Exponential distribution must have a positive mean + return 0; + } + int32_t i; + double r = _vl_dbase_exponential(seedr, mean); + if (r >= 0) { + i = static_cast(r + 0.5); + } else { + r = -r; // LCOV_EXCL_LINE + i = static_cast(r + 0.5); // LCOV_EXCL_LINE + i = -i; // LCOV_EXCL_LINE + } + return static_cast(i); +} + +IData VL_DIST_NORMAL(IData& seedr, IData umean, IData usd) VL_MT_SAFE { + const int32_t mean = static_cast(umean); + const int32_t sd = static_cast(usd); + double r = _vl_dbase_normal(seedr, mean, sd); + int32_t i; + if (r >= 0) { + i = static_cast(r + 0.5); + } else { + r = -r; + i = static_cast(r + 0.5); + i = -i; + } + return static_cast(i); +} + +IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE { + const int32_t mean = static_cast(umean); + if (VL_UNLIKELY(mean <= 0)) { + // Poisson distribution must have a positive mean + return 0; + } + int32_t i = 0; + double q = -static_cast(mean); + double p = exp(q); + q = _vl_dbase_uniform(seedr, 0, 1); + while (p < q) { + ++i; + q = _vl_dbase_uniform(seedr, 0, 1) * q; + } + return static_cast(i); +} + +IData VL_DIST_T(IData& seedr, IData udf) VL_MT_SAFE { + const int32_t df = static_cast(udf); + if (VL_UNLIKELY(df <= 0)) { + // t distribution must have positive degree of freedom + return 0; + } + const double chi2 = _vl_dbase_chi_square(seedr, df); + const double div = chi2 / static_cast(df); + const double root = std::sqrt(div); + double r = _vl_dbase_normal(seedr, 0, 1) / root; + int32_t i; + if (r >= 0) { + i = static_cast(r + 0.5); + } else { + r = -r; + i = static_cast(r + 0.5); + i = -i; + } + return static_cast(i); +} + +IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE { + int32_t start = static_cast(ustart); + int32_t end = static_cast(uend); + if (VL_UNLIKELY(start >= end)) return start; + int32_t i; + if (end != std::numeric_limits::max()) { + ++end; + const double r = _vl_dbase_uniform(seedr, start, end); + if (r >= 0) { + i = static_cast(r); + } else { + i = static_cast(r - 1); + } + if (i < start) i = start; + if (i >= end) i = end - 1; + } else if (start != std::numeric_limits::min()) { + --start; + const double r = _vl_dbase_uniform(seedr, start, end) + 1.0; + if (r >= 0) { + i = static_cast(r); + } else { + i = static_cast(r - 1); // LCOV_EXCL_LINE + } + if (i <= start) i = start + 1; + if (i > end) i = end; + } else { + double r = (_vl_dbase_uniform(seedr, start, end) + 2147483648.0) / 4294967295.0; + r = r * 4294967296.0 - 2147483648.0; + if (r >= 0) { + i = static_cast(r); + } else { + i = static_cast(r - 1); + } + } + return static_cast(i); +} diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index c67a4335a..da8683b5c 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -112,6 +112,27 @@ protected: public: ASTGEN_MEMBERS_AstNodeBiComAsv; }; +class AstNodeDistBiop VL_NOT_FINAL : public AstNodeBiop { +public: + AstNodeDistBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : AstNodeBiop{t, fl, lhsp, rhsp} { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_AstNodeDistBiop; + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } + AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override { + V3ERROR_NA; + return nullptr; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } +}; class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { // Single bit range extraction, perhaps with non-constant selection or array selection // @astgen alias op1 := fromp // Expression we are indexing into @@ -363,6 +384,27 @@ public: int instrCount() const override { return INSTR_COUNT_BRANCH; } virtual AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) = 0; }; +class AstNodeDistTriop VL_NOT_FINAL : public AstNodeTriop { +public: + AstNodeDistTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, + AstNodeExpr* thsp) + : AstNodeTriop{t, fl, lhsp, rhsp, thsp} { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_AstNodeDistTriop; + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool cleanThs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; + } +}; class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr { // Unary expression // @astgen op1 := lhsp : AstNodeExpr @@ -3532,6 +3574,40 @@ public: bool sizeMattersRhs() const override { return false; } }; +// === AstNodeDistBiop === +class AstDistChiSquare final : public AstNodeDistBiop { +public: + AstDistChiSquare(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_DistChiSquare(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AstDistChiSquare; + string emitVerilog() override { return "%f$dist_chi_square(%l, %r)"; } + string emitC() override { return "VL_DIST_CHI_SQUARE(%li, %ri)"; } +}; +class AstDistExponential final : public AstNodeDistBiop { +public: + AstDistExponential(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_DistExponential(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AstDistExponential; + string emitVerilog() override { return "%f$dist_exponential(%l, %r)"; } + string emitC() override { return "VL_DIST_EXPONENTIAL(%li, %ri)"; } +}; +class AstDistPoisson final : public AstNodeDistBiop { +public: + AstDistPoisson(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_DistPoisson(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AstDistPoisson; + string emitVerilog() override { return "%f$dist_poisson(%l, %r)"; } + string emitC() override { return "VL_DIST_POISSON(%li, %ri)"; } +}; +class AstDistT final : public AstNodeDistBiop { +public: + AstDistT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_DistT(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AstDistT; + string emitVerilog() override { return "%f$dist_t(%l, %r)"; } + string emitC() override { return "VL_DIST_T(%li, %ri)"; } +}; + // === AstNodeSel === class AstArraySel final : public AstNodeSel { void init(AstNode* fromp) { @@ -4198,6 +4274,32 @@ public: } }; +// === AstNodeDistTriop === +class AstDistErlang final : public AstNodeDistTriop { +public: + AstDistErlang(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp) + : ASTGEN_SUPER_DistErlang(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_AstDistErlang; + string emitVerilog() override { return "%f$dist_erlang(%l, %r, %t)"; } + string emitC() override { return "VL_DIST_ERLANG(%li, %ri, %ti)"; } +}; +class AstDistNormal final : public AstNodeDistTriop { +public: + AstDistNormal(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp) + : ASTGEN_SUPER_DistNormal(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_AstDistNormal; + string emitVerilog() override { return "%f$dist_normal(%l, %r, %t)"; } + string emitC() override { return "VL_DIST_NORMAL(%li, %ri, %ti)"; } +}; +class AstDistUniform final : public AstNodeDistTriop { +public: + AstDistUniform(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp) + : ASTGEN_SUPER_DistUniform(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_AstDistUniform; + string emitVerilog() override { return "%f$dist_uniform(%l, %r, %t)"; } + string emitC() override { return "VL_DIST_UNIFORM(%li, %ri, %ti)"; } +}; + // === AstNodeUniop === class AstAtoN final : public AstNodeUniop { // string.atoi(), atobin(), atohex(), atooct(), atoireal() diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 24556fd5f..58cae781a 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -43,6 +43,14 @@ class EmitCInlines final : EmitCBaseVisitor { if (v3Global.opt.trace()) v3Global.needTraceDumper(true); iterateChildren(nodep); } + void visit(AstNodeDistBiop* nodep) override { + v3Global.setUsesProbDist(); + iterateChildren(nodep); + } + void visit(AstNodeDistTriop* nodep) override { + v3Global.setUsesProbDist(); + iterateChildren(nodep); + } //--------------------------------------- void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index f6845df70..ca3a3d3ef 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -159,6 +159,9 @@ class CMakeEmitter final { global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase() + "_c.cpp"); } + if (v3Global.usesProbDist()) { + global.emplace_back("${VERILATOR_ROOT}/include/verilated_probdist.cpp"); + } if (v3Global.usesTiming()) { global.emplace_back("${VERILATOR_ROOT}/include/verilated_timing.cpp"); } diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 26083c2f0..2964f0bc3 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -106,6 +106,7 @@ public: if (v3Global.opt.trace()) { putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp"); } + if (v3Global.usesProbDist()) putMakeClassEntry(of, "verilated_probdist.cpp"); if (v3Global.usesTiming()) putMakeClassEntry(of, "verilated_timing.cpp"); if (v3Global.opt.threads()) putMakeClassEntry(of, "verilated_threads.cpp"); if (v3Global.opt.usesProfiler()) { diff --git a/src/V3Global.h b/src/V3Global.h index bcbdc172f..7807d6f2b 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -107,6 +107,7 @@ class V3Global final { bool m_dpi = false; // Need __Dpi include files bool m_hasEvents = false; // Design uses SystemVerilog named events bool m_hasClasses = false; // Design uses SystemVerilog classes + bool m_usesProbDist = false; // Uses $dist_* bool m_usesStdPackage = false; // Design uses the std package bool m_usesTiming = false; // Design uses timing constructs bool m_hasForceableSignals = false; // Need to apply V3Force pass @@ -153,6 +154,8 @@ public: void setHasEvents() { m_hasEvents = true; } bool hasClasses() const { return m_hasClasses; } void setHasClasses() { m_hasClasses = true; } + bool usesProbDist() const { return m_usesProbDist; } + void setUsesProbDist() { m_usesProbDist = true; } bool usesStdPackage() const { return m_usesStdPackage; } void setUsesStdPackage() { m_usesStdPackage = true; } bool usesTiming() const { return m_usesTiming; } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 903f0a90c..692339ed3 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -250,6 +250,21 @@ private: iterateAndNextNull(nodep->fmtp()); } } + void visit(AstNodeDistBiop* nodep) override { + VL_RESTORER(m_setRefLvalue); + m_setRefLvalue = VAccess::WRITE; + iterateAndNextNull(nodep->lhsp()); + m_setRefLvalue = VAccess::NOCHANGE; + iterateAndNextNull(nodep->rhsp()); + } + void visit(AstNodeDistTriop* nodep) override { + VL_RESTORER(m_setRefLvalue); + m_setRefLvalue = VAccess::WRITE; + iterateAndNextNull(nodep->lhsp()); + m_setRefLvalue = VAccess::NOCHANGE; + iterateAndNextNull(nodep->rhsp()); + iterateAndNextNull(nodep->thsp()); + } void prepost_visit(AstNodeTriop* nodep) { VL_RESTORER(m_setRefLvalue); { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1c9ab3a85..a766baca8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -773,6 +773,21 @@ private: } } } + void visit(AstNodeDistBiop* nodep) override { + if (m_vup->prelim()) { // First stage evaluation + iterateCheckSigned32(nodep, "seed", nodep->lhsp(), BOTH); + iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH); + nodep->dtypeSetSigned32(); + } + } + void visit(AstNodeDistTriop* nodep) override { + if (m_vup->prelim()) { // First stage evaluation + iterateCheckSigned32(nodep, "seed", nodep->lhsp(), BOTH); + iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH); + iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH); + nodep->dtypeSetSigned32(); + } + } void visit(AstNodeStream* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); diff --git a/src/verilog.l b/src/verilog.l index 96e1d5718..b4b42635c 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -183,6 +183,13 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$displayb" { FL; return yD_DISPLAYB; } "$displayh" { FL; return yD_DISPLAYH; } "$displayo" { FL; return yD_DISPLAYO; } + "$dist_chi_square" { FL; return yD_DIST_CHI_SQUARE; } + "$dist_erlang" { FL; return yD_DIST_ERLANG; } + "$dist_exponential" { FL; return yD_DIST_EXPONENTIAL; } + "$dist_normal" { FL; return yD_DIST_NORMAL; } + "$dist_poisson" { FL; return yD_DIST_POISSON; } + "$dist_t" { FL; return yD_DIST_T; } + "$dist_uniform" { FL; return yD_DIST_UNIFORM; } "$dumpall" { FL; return yD_DUMPALL; } "$dumpfile" { FL; return yD_DUMPFILE; } "$dumpflush" { FL; return yD_DUMPFLUSH; } diff --git a/src/verilog.y b/src/verilog.y index 5b4c9cb96..8621e4e6b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -776,6 +776,13 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_DISPLAYB "$displayb" %token yD_DISPLAYH "$displayh" %token yD_DISPLAYO "$displayo" +%token yD_DIST_CHI_SQUARE "$dist_chi_square" +%token yD_DIST_ERLANG "$dist_erlang" +%token yD_DIST_EXPONENTIAL "$dist_exponential" +%token yD_DIST_NORMAL "$dist_normal" +%token yD_DIST_POISSON "$dist_poisson" +%token yD_DIST_T "$dist_t" +%token yD_DIST_UNIFORM "$dist_uniform" %token yD_DUMPALL "$dumpall" %token yD_DUMPFILE "$dumpfile" %token yD_DUMPFLUSH "$dumpflush" @@ -4038,6 +4045,13 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task BBUNSUP($11, "Unsupported: $countbits with more than 3 control fields"); } | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes{$1, $3}; } | yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_DIMENSIONS, $3}; } + | yD_DIST_CHI_SQUARE '(' expr ',' expr ')' { $$ = new AstDistChiSquare{$1, $3, $5}; } + | yD_DIST_ERLANG '(' expr ',' expr ',' expr ')' { $$ = new AstDistErlang{$1, $3, $5, $7}; } + | yD_DIST_EXPONENTIAL '(' expr ',' expr ')' { $$ = new AstDistExponential{$1, $3, $5}; } + | yD_DIST_NORMAL '(' expr ',' expr ',' expr ')' { $$ = new AstDistNormal{$1, $3, $5, $7}; } + | yD_DIST_POISSON '(' expr ',' expr ')' { $$ = new AstDistPoisson{$1, $3, $5}; } + | yD_DIST_T '(' expr ',' expr ')' { $$ = new AstDistT{$1, $3, $5}; } + | yD_DIST_UNIFORM '(' expr ',' expr ',' expr ')' { $$ = new AstDistUniform{$1, $3, $5, $7}; } | yD_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; } | yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3}; } | yD_FELL '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $fell and clock arguments"); } diff --git a/test_regress/t/t_probdist.pl b/test_regress/t/t_probdist.pl index 43720dd0f..1aa73f80a 100755 --- a/test_regress/t/t_probdist.pl +++ b/test_regress/t/t_probdist.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_probdist.v b/test_regress/t/t_probdist.v index ae5a62a6f..af8ef0ecf 100644 --- a/test_regress/t/t_probdist.v +++ b/test_regress/t/t_probdist.v @@ -13,7 +13,7 @@ module t(/*AUTOARG*/); integer sum; initial begin - // Illegal values + //======= seed = 1234; r = $dist_chi_square(seed, 5); `checkd(seed, 923940542); @@ -21,7 +21,14 @@ module t(/*AUTOARG*/); sum = 1; repeat(20) sum += $dist_chi_square(seed, 5); `checkd(sum, 130); + sum = 1; + repeat(20) sum += $dist_chi_square(seed, -5); + `checkd(sum, 1); + sum = 1; + repeat(20) sum += $dist_chi_square(seed, 2); + `checkd(sum, 30); + //======= seed = 1234; r = $dist_erlang(seed, 5, 10); `checkd(seed, 1025211431); @@ -29,7 +36,11 @@ module t(/*AUTOARG*/); sum = 1; repeat(20) sum += $dist_erlang(seed, 5, 10); `checkd(sum, 173); + sum = 1; + repeat(20) sum += $dist_erlang(seed, 5, -10); + `checkd(sum, -241); + //======= seed = 1234; r = $dist_exponential(seed, 5); `checkd(seed, 85231147); @@ -38,6 +49,7 @@ module t(/*AUTOARG*/); repeat(20) sum += $dist_exponential(seed, 5); `checkd(sum, 104); + //======= seed = 1234; r = $dist_normal(seed, 5, 10); `checkd(seed, -1570070672); @@ -46,6 +58,7 @@ module t(/*AUTOARG*/); repeat(20) sum += $dist_normal(seed, 5, 10); `checkd(sum, 114); + //======= seed = 1234; r = $dist_poisson(seed, 5); `checkd(seed, 418012337); @@ -54,6 +67,7 @@ module t(/*AUTOARG*/); repeat(20) sum += $dist_poisson(seed, 5); `checkd(sum, 111); + //======= seed = 1234; r = $dist_t(seed, 5); `checkd(seed, -797481412); @@ -62,6 +76,7 @@ module t(/*AUTOARG*/); repeat(20) sum += $dist_t(seed, 5); `checkd(sum, -2); + //======= seed = 1234; r = $dist_uniform(seed, 5, 10); `checkd(seed, 85231147); @@ -70,6 +85,24 @@ module t(/*AUTOARG*/); repeat(20) sum += $dist_uniform(seed, 5, 10); `checkd(sum, 147); + seed = 1234; + r = $dist_uniform(seed, 10, 5); + `checkd(r, 10); + sum = 1; + repeat(20) sum += $dist_uniform(seed, -2147483648, -20); + `checkd(sum, 1768955681); + sum = 1; + repeat(20) sum += $dist_uniform(seed, 20, 2147483647); + `checkd(sum, 1534326415); + sum = 1; + repeat(20) sum += $dist_uniform(seed, -2147483648, 2147483647); + `checkd(sum, 1394525852); + seed = 0; + sum = 1; + repeat(20) sum += $dist_uniform(seed, -10, 100); + `checkd(seed, 1003647461); + `checkd(sum, 896); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_probdist_bad.out b/test_regress/t/t_probdist_bad.out deleted file mode 100644 index 9d7008ac9..000000000 --- a/test_regress/t/t_probdist_bad.out +++ /dev/null @@ -1,19 +0,0 @@ -%Error: t/t_probdist_bad.v:16:11: Unsupported or unknown PLI call: '$dist_chi_square' - 16 | r = $dist_chi_square(seed, 0); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_probdist_bad.v:18:11: Unsupported or unknown PLI call: '$dist_erlang' - 18 | r = $dist_erlang(seed, 0, 0); - | ^~~~~~~~~~~~ -%Error: t/t_probdist_bad.v:20:11: Unsupported or unknown PLI call: '$dist_exponential' - 20 | r = $dist_exponential(seed, 0); - | ^~~~~~~~~~~~~~~~~ -%Error: t/t_probdist_bad.v:23:11: Unsupported or unknown PLI call: '$dist_poisson' - 23 | r = $dist_poisson(seed, 0); - | ^~~~~~~~~~~~~ -%Error: t/t_probdist_bad.v:25:11: Unsupported or unknown PLI call: '$dist_t' - 25 | r = $dist_t(seed, 0); - | ^~~~~~~ -%Error: t/t_probdist_bad.v:27:11: Unsupported or unknown PLI call: '$dist_uniform' - 27 | r = $dist_uniform(seed, 10, 0); - | ^~~~~~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_probdist_bad.pl b/test_regress/t/t_probdist_bad.pl index 43720dd0f..1aa73f80a 100755 --- a/test_regress/t/t_probdist_bad.pl +++ b/test_regress/t/t_probdist_bad.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_probdist_cmake.pl b/test_regress/t/t_probdist_cmake.pl new file mode 100755 index 000000000..f9854219c --- /dev/null +++ b/test_regress/t/t_probdist_cmake.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_probdist.v"); + +compile( + verilator_make_gmake => 0, + verilator_make_cmake => 1, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_verilated_all.v b/test_regress/t/t_verilated_all.v index 2030b8ba8..14b2fab87 100644 --- a/test_regress/t/t_verilated_all.v +++ b/test_regress/t/t_verilated_all.v @@ -12,12 +12,15 @@ module t (/*AUTOARG*/ input clk; integer cyc; + integer seed = 123; always @ (posedge clk) begin cyc <= cyc + 1; - if (cyc!=0) begin - if (cyc==10) begin - #5 $write("*-* All Finished *-*\n"); + if (cyc != 0) begin + if (cyc == 10) begin + #5; + $display("dist: %f ", $dist_poisson(seed, 12)); // Get verilated_probdist.cpp + $write("*-* All Finished *-*\n"); $finish; end end