// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2009-2020 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 Verilator: DPI implementation code
///
///     This file must be compiled and linked against all objects
///     created from Verilator or called by Verilator that use the DPI.
///
/// Code available from: https://verilator.org
///
//=========================================================================

#define _VERILATED_DPI_CPP_

#include "verilatedos.h"
#include "verilated_dpi.h"
#include "verilated_imp.h"

// On MSVC++ we need svdpi.h to declare exports, not imports
#define DPI_PROTOTYPES
#undef XXTERN
#define XXTERN DPI_EXTERN DPI_DLLESPEC
#undef EETERN
#define EETERN DPI_EXTERN DPI_DLLESPEC

#include "vltstd/svdpi.h"

//======================================================================
// Internal macros

// Not supported yet
#define _VL_SVDPI_UNIMP() \
    VL_FATAL_MT(__FILE__, __LINE__, "", \
                (std::string("%%Error: Unsupported DPI function: ") + VL_FUNC).c_str())

#define _VL_SVDPI_WARN(...) VL_PRINTF_MT(__VA_ARGS__)

// Function requires a "context" in the import declaration
#define _VL_SVDPI_CONTEXT_WARN() \
    _VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
                   "'context' keyword.\n")

//======================================================================
//======================================================================
//======================================================================
// DPI ROUTINES

const char* svDpiVersion() { return "1800-2005"; }

//======================================================================
// Bit-select utility functions.

svBit svGetBitselBit(const svBitVecVal* sp, int bit) { return VL_BITRSHIFT_W(sp, bit) & 1; }
svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
    // Not VL_BITRSHIFT_W as sp is a different structure type
    // Verilator doesn't support X/Z so only aval
    return (((sp[VL_BITWORD_I(bit)].aval >> VL_BITBIT_I(bit)) & 1)
            | (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1));
}

void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); }
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
    // Verilator doesn't support X/Z so only aval
    dp[VL_BITWORD_I(bit)].aval = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
                                  | ((s & 1) << VL_BITBIT_I(bit)));
    dp[VL_BITWORD_I(bit)].bval = ((dp[VL_BITWORD_I(bit)].bval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
                                  | ((s & 2) >> 1 << VL_BITBIT_I(bit)));
}

void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int lsb, int width) {
    // See also VL_SEL_WWI
    int msb = lsb + width - 1;
    int word_shift = VL_BITWORD_I(lsb);
    if (VL_BITBIT_I(lsb) == 0) {
        // Just a word extract
        for (int i = 0; i < VL_WORDS_I(width); ++i) dp[i] = sp[i + word_shift];
    } else {
        int loffset = lsb & VL_SIZEBITS_I;
        int nbitsfromlow = 32 - loffset;  // bits that end up in lword (know loffset!=0)
        // Middle words
        int words = VL_WORDS_I(msb - lsb + 1);
        for (int i = 0; i < words; ++i) {
            dp[i] = sp[i + word_shift] >> loffset;
            int upperword = i + word_shift + 1;
            if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
                dp[i] |= sp[upperword] << nbitsfromlow;
            }
        }
    }
    // Clean result
    dp[VL_WORDS_I(width) - 1] &= VL_MASK_I(width);
}
void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int width) {
    int msb = lsb + width - 1;
    int word_shift = VL_BITWORD_I(lsb);
    if (VL_BITBIT_I(lsb) == 0) {
        // Just a word extract
        for (int i = 0; i < VL_WORDS_I(width); ++i) dp[i] = sp[i + word_shift];
    } else {
        int loffset = lsb & VL_SIZEBITS_I;
        int nbitsfromlow = 32 - loffset;  // bits that end up in lword (know loffset!=0)
        // Middle words
        int words = VL_WORDS_I(msb - lsb + 1);
        for (int i = 0; i < words; ++i) {
            dp[i].aval = sp[i + word_shift].aval >> loffset;
            dp[i].bval = sp[i + word_shift].bval >> loffset;
            int upperword = i + word_shift + 1;
            if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
                dp[i].aval |= sp[upperword].aval << nbitsfromlow;
                dp[i].bval |= sp[upperword].bval << nbitsfromlow;
            }
        }
    }
    // Clean result
    dp[VL_WORDS_I(width) - 1].aval &= VL_MASK_I(width);
    dp[VL_WORDS_I(width) - 1].bval &= VL_MASK_I(width);
}
void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int lbit, int width) {
    // See also _VL_INSERT_WI
    int hbit = lbit + width - 1;
    int hoffset = VL_BITBIT_I(hbit);
    int loffset = VL_BITBIT_I(lbit);
    if (hoffset == VL_SIZEBITS_I && loffset == 0) {
        // Fast and common case, word based insertion
        dp[VL_BITWORD_I(lbit)] = s;
    } else {
        int hword = VL_BITWORD_I(hbit);
        int lword = VL_BITWORD_I(lbit);
        if (hword == lword) {  // know < 32 bits because above checks it
            IData insmask = (VL_MASK_I(hoffset - loffset + 1)) << loffset;
            dp[lword] = (dp[lword] & ~insmask) | ((s << loffset) & insmask);
        } else {
            IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0;
            IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset;
            int nbitsonright = 32 - loffset;  // bits that end up in lword
            dp[lword] = (dp[lword] & ~linsmask) | ((s << loffset) & linsmask);
            dp[hword] = (dp[hword] & ~hinsmask) | ((s >> nbitsonright) & hinsmask);
        }
    }
}
// cppcheck-suppress passedByValue
void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int width) {
    int hbit = lbit + width - 1;
    int hoffset = VL_BITBIT_I(hbit);
    int loffset = VL_BITBIT_I(lbit);
    if (hoffset == VL_SIZEBITS_I && loffset == 0) {
        // Fast and common case, word based insertion
        dp[VL_BITWORD_I(lbit)].aval = s.aval;
        dp[VL_BITWORD_I(lbit)].bval = s.bval;
    } else {
        int hword = VL_BITWORD_I(hbit);
        int lword = VL_BITWORD_I(lbit);
        if (hword == lword) {  // know < 32 bits because above checks it
            IData insmask = (VL_MASK_I(hoffset - loffset + 1)) << loffset;
            dp[lword].aval = (dp[lword].aval & ~insmask) | ((s.aval << loffset) & insmask);
            dp[lword].bval = (dp[lword].bval & ~insmask) | ((s.bval << loffset) & insmask);
        } else {
            IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0;
            IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset;
            int nbitsonright = 32 - loffset;  // bits that end up in lword
            dp[lword].aval = (dp[lword].aval & ~linsmask) | ((s.aval << loffset) & linsmask);
            dp[lword].bval = (dp[lword].bval & ~linsmask) | ((s.bval << loffset) & linsmask);
            dp[hword].aval = (dp[hword].aval & ~hinsmask) | ((s.aval >> nbitsonright) & hinsmask);
            dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval >> nbitsonright) & hinsmask);
        }
    }
}

//======================================================================
// Open array internals

static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
    if (VL_UNLIKELY(!h)) {
        VL_FATAL_MT(__FILE__, __LINE__, "",
                    "%%Error: DPI svOpenArrayHandle function called with NULL handle");
    }
    const VerilatedDpiOpenVar* varp = reinterpret_cast<const VerilatedDpiOpenVar*>(h);
    if (VL_UNLIKELY(!varp->magicOk())) {
        VL_FATAL_MT(__FILE__, __LINE__, "",
                    "%%Error: DPI svOpenArrayHandle function called with non-Verilator handle");
    }
    return varp;
}

//======================================================================
// Open array querying functions

int svLeft(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->left(d); }
int svRight(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->right(d); }
int svLow(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->low(d); }
int svHigh(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->high(d); }
int svIncrement(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->increment(d); }
int svSize(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->elements(d); }
int svDimensions(const svOpenArrayHandle h) { return _vl_openhandle_varp(h)->udims(); }

/// Return pointer to open array data, or NULL if not in IEEE standard C layout
void* svGetArrayPtr(const svOpenArrayHandle h) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
    if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
    return varp->datap();
}
/// Return size of open array, or 0 if not in IEEE standard C layout
int svSizeOfArray(const svOpenArrayHandle h) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
    if (VL_UNLIKELY(!varp->isDpiStdLayout())) return 0;
    // Truncate 64 bits to int; DPI is limited to 4GB
    return static_cast<int>(varp->totalSize());
}

//======================================================================
// Open array access internals

static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, int indx1,
                                   int indx2, int indx3) {
    void* datap = varp->datap();
    if (VL_UNLIKELY(nargs != varp->udims())) {
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
                       " %d dimensional array using %d dimensional function.\n",
                       varp->udims(), nargs);
        return NULL;
    }
    if (nargs >= 1) {
        datap = varp->datapAdjustIndex(datap, 1, indx1);
        if (VL_UNLIKELY(!datap)) {
            _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 "
                           "out of bounds; %d outside [%d:%d].\n",
                           indx1, varp->left(1), varp->right(1));
            return NULL;
        }
    }
    if (nargs >= 2) {
        datap = varp->datapAdjustIndex(datap, 2, indx2);
        if (VL_UNLIKELY(!datap)) {
            _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 "
                           "out of bounds; %d outside [%d:%d].\n",
                           indx2, varp->left(2), varp->right(2));
            return NULL;
        }
    }
    if (nargs >= 3) {
        datap = varp->datapAdjustIndex(datap, 3, indx3);
        if (VL_UNLIKELY(!datap)) {
            _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 "
                           "out of bounds; %d outside [%d:%d].\n",
                           indx1, varp->left(3), varp->right(3));
            return NULL;
        }
    }
    return datap;
}

static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
    if (VL_UNLIKELY(indx < varp->low(0) || indx > varp->high(0))) {
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d "
                       "outside [%d:%d].\n",
                       indx, varp->left(0), varp->right(0));
        return 0;
    }
    return indx - varp->low(0);
}

/// Return pointer to simulator open array element, or NULL if outside range
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, int nargs, int indx1, int indx2,
                                 int indx3) VL_MT_SAFE {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
    if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
    void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
    return datap;
}

/// Copy to user bit array from simulator open array
static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int nargs,
                                      int indx1, int indx2, int indx3) VL_MT_SAFE {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
    if (VL_UNLIKELY(!datap)) return;
    switch (varp->vltype()) {
    case VLVT_UINT8: d[0] = *(reinterpret_cast<CData*>(datap)); return;
    case VLVT_UINT16: d[0] = *(reinterpret_cast<SData*>(datap)); return;
    case VLVT_UINT32: d[0] = *(reinterpret_cast<IData*>(datap)); return;
    case VLVT_UINT64: {
        WData lwp[2];
        VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
        d[0] = lwp[0];
        d[1] = lwp[1];
        break;
    }
    case VLVT_WDATA: {
        WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
        for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
        return;
    }
    default:
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
                       varp->vltype());
        return;
    }
}
/// Copy to user logic array from simulator open array
static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int nargs,
                                        int indx1, int indx2, int indx3) VL_MT_SAFE {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
    if (VL_UNLIKELY(!datap)) return;
    switch (varp->vltype()) {
    case VLVT_UINT8:
        d[0].aval = *(reinterpret_cast<CData*>(datap));
        d[0].bval = 0;
        return;
    case VLVT_UINT16:
        d[0].aval = *(reinterpret_cast<SData*>(datap));
        d[0].bval = 0;
        return;
    case VLVT_UINT32:
        d[0].aval = *(reinterpret_cast<IData*>(datap));
        d[0].bval = 0;
        return;
    case VLVT_UINT64: {
        WData lwp[2];
        VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
        d[0].aval = lwp[0];
        d[0].bval = 0;
        d[1].aval = lwp[1];
        d[0].bval = 0;
        break;
    }
    case VLVT_WDATA: {
        WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
        for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) {
            d[i].aval = wdatap[i];
            d[i].bval = 0;
        }
        return;
    }
    default:
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
                       varp->vltype());
        return;
    }
}

/// Copy to simulator open array from from user bit array
static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int nargs,
                                      int indx1, int indx2, int indx3) VL_MT_SAFE {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
    if (VL_UNLIKELY(!datap)) return;
    switch (varp->vltype()) {
    case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0]; return;
    case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0]; return;
    case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0]; return;
    case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1], s[0]); break;
    case VLVT_WDATA: {
        WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
        for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
        return;
    }
    default:
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
                       varp->vltype());
        return;
    }
}
/// Copy to simulator open array from from user logic array
static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
                                        int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
    if (VL_UNLIKELY(!datap)) return;
    switch (varp->vltype()) {
    case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0].aval; return;
    case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0].aval; return;
    case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0].aval; return;
    case VLVT_UINT64:
        *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1].aval, s[0].aval);
        break;
    case VLVT_WDATA: {
        WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
        for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
        return;
    }
    default:
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
                       varp->vltype());
        return;
    }
}

/// Return bit from simulator open array
static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1, int indx2,
                                 int indx3, int indx4) VL_MT_SAFE {
    // One extra index supported, as need bit number
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    void* datap;
    int lsb;
    if (varp->packed().elements()) {
        datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3);
        lsb = _vl_sv_adjusted_bit(
            varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4));
    } else {
        datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
        lsb = 0;
    }
    if (VL_UNLIKELY(!datap)) return 0;
    switch (varp->vltype()) {
    case VLVT_UINT8: return (*(reinterpret_cast<CData*>(datap)) >> lsb) & 1;
    case VLVT_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1;
    case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
    case VLVT_UINT64:
        return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & 1ULL;
    case VLVT_WDATA: {
        WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
        return VL_BITRSHIFT_W(wdatap, lsb) & 1;
    }
    default:
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
                       varp->vltype());
        return 0;
    }
}
/// Update simulator open array from bit
static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, int nargs, int indx1,
                                int indx2, int indx3, int indx4) VL_MT_SAFE {
    // One extra index supported, as need bit number
    value &= 1;  // Make sure clean
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    void* datap;
    int lsb;
    if (varp->packed().elements()) {
        datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3);
        lsb = _vl_sv_adjusted_bit(
            varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4));
    } else {
        datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
        lsb = 0;
    }
    if (VL_UNLIKELY(!datap)) return;
    switch (varp->vltype()) {
    case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<CData*>(datap)), value); return;
    case VLVT_UINT16: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<SData*>(datap)), value); return;
    case VLVT_UINT32: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<IData*>(datap)), value); return;
    case VLVT_UINT64: VL_ASSIGNBIT_QI(-1, lsb, *(reinterpret_cast<QData*>(datap)), value); return;
    case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast<WDataOutP>(datap)), value); return;
    default:
        _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
                       varp->vltype());
        return;
    }
}

//======================================================================
// DPI accessors that simply call above functions

void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
    void* datap;
    va_list ap;
    va_start(ap, indx1);
    // va_arg is a macro, so need temporaries as used below
    switch (varp->udims()) {
    case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
        break;
    }
    default: datap = _vl_svGetArrElemPtr(h, -1, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
    return datap;
}
void* svGetArrElemPtr1(const svOpenArrayHandle h, int indx1) {
    return _vl_svGetArrElemPtr(h, 1, indx1, 0, 0);
}
void* svGetArrElemPtr2(const svOpenArrayHandle h, int indx1, int indx2) {
    return _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
}
void* svGetArrElemPtr3(const svOpenArrayHandle h, int indx1, int indx2, int indx3) {
    return _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
}

void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
        break;
    }
    default: _vl_svPutBitArrElemVecVal(d, s, -1, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
}
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1) {
    _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0);
}
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1,
                            int indx2) {
    _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
}
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2,
                            int indx3) {
    _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
}
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
        break;
    }
    default: _vl_svPutLogicArrElemVecVal(d, s, -1, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
}
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1) {
    _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
}
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1,
                              int indx2) {
    _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
}
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1,
                              int indx2, int indx3) {
    _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
}

//======================================================================
// From simulator storage into user space

void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
        break;
    }
    default: _vl_svGetBitArrElemVecVal(d, s, -1, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
}
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1) {
    _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0);
}
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) {
    _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
}
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2,
                            int indx3) {
    _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
}
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
        break;
    }
    default: _vl_svGetLogicArrElemVecVal(d, s, -1, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
}
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1) {
    _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
}
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) {
    _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
}
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2,
                              int indx3) {
    _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
}

svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    svBit out;
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
        break;
    }
    case 4: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        int indx4 = va_arg(ap, int);
        out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4);
        break;
    }
    default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
    return out;
}
svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1) {
    return _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0);
}
svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
    return _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
}
svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
    return _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
}
svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
    // Verilator doesn't support X/Z so can just call Bit version
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
    svBit out;
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
        break;
    }
    case 4: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        int indx4 = va_arg(ap, int);
        out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4);
        break;
    }
    default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
    return out;
}
svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1) {
    // Verilator doesn't support X/Z so can just call Bit version
    return svGetBitArrElem1(s, indx1);
}
svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
    // Verilator doesn't support X/Z so can just call Bit version
    return svGetBitArrElem2(s, indx1, indx2);
}
svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
    // Verilator doesn't support X/Z so can just call Bit version
    return svGetBitArrElem3(s, indx1, indx2, indx3);
}

void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
        break;
    }
    case 4: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        int indx4 = va_arg(ap, int);
        _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4);
        break;
    }
    default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
}
void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1) {
    _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0);
}
void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2) {
    _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
}
void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3) {
    _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
}
void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) {
    // Verilator doesn't support X/Z so can just call Bit version
    const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
    va_list ap;
    va_start(ap, indx1);
    switch (varp->udims()) {
    case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
    case 2: {
        int indx2 = va_arg(ap, int);
        _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
        break;
    }
    case 3: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
        break;
    }
    case 4: {
        int indx2 = va_arg(ap, int);
        int indx3 = va_arg(ap, int);
        int indx4 = va_arg(ap, int);
        _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4);
        break;
    }
    default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break;  // Will error
    }
    va_end(ap);
}
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
    // Verilator doesn't support X/Z so can just call Bit version
    svPutBitArrElem1(d, value, indx1);
}
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
    // Verilator doesn't support X/Z so can just call Bit version
    svPutBitArrElem2(d, value, indx1, indx2);
}
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2,
                        int indx3) {
    // Verilator doesn't support X/Z so can just call Bit version
    svPutBitArrElem3(d, value, indx1, indx2, indx3);
}

//======================================================================
// Functions for working with DPI context

svScope svGetScope() {
    if (VL_UNLIKELY(!Verilated::dpiInContext())) {
        _VL_SVDPI_CONTEXT_WARN();
        return NULL;
    }
    // NOLINTNEXTLINE(google-readability-casting)
    return (svScope)(Verilated::dpiScope());
}

svScope svSetScope(const svScope scope) {
    const VerilatedScope* prevScopep = Verilated::dpiScope();
    const VerilatedScope* vscopep = reinterpret_cast<const VerilatedScope*>(scope);
    Verilated::dpiScope(vscopep);
    // NOLINTNEXTLINE(google-readability-casting)
    return (svScope)(prevScopep);
}

const char* svGetNameFromScope(const svScope scope) {
    const VerilatedScope* vscopep = reinterpret_cast<const VerilatedScope*>(scope);
    return vscopep->name();
}

svScope svGetScopeFromName(const char* scopeName) {
    // NOLINTNEXTLINE(google-readability-casting)
    return (svScope)(VerilatedImp::scopeFind(scopeName));
}

int svPutUserData(const svScope scope, void* userKey, void* userData) {
    VerilatedImp::userInsert(scope, userKey, userData);
    return 0;
}

void* svGetUserData(const svScope scope, void* userKey) {
    return VerilatedImp::userFind(scope, userKey);
}

int svGetCallerInfo(const char** fileNamepp, int* lineNumberp) {
    if (VL_UNLIKELY(!Verilated::dpiInContext())) {
        _VL_SVDPI_CONTEXT_WARN();
        return false;
    }
    if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep();  // thread local
    if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno();  // thread local
    return true;
}

//======================================================================
// Disables

int svIsDisabledState() {
    return 0;  // Disables not implemented
}

void svAckDisabledState() {
    // Disables not implemented
}
