2012-04-13 01:08:20 +00:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2010-12-25 19:39:41 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2017-01-15 17:09:59 +00:00
|
|
|
|
// Copyright 2009-2017 by Wilson Snyder. This program is free software; you can
|
2010-12-25 19:39:41 +00:00
|
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
//=========================================================================
|
|
|
|
|
///
|
|
|
|
|
/// \file
|
|
|
|
|
/// \brief Verilator: VPI implementation code
|
|
|
|
|
///
|
|
|
|
|
/// This file must be compiled and linked against all objects
|
|
|
|
|
/// created from Verilator or called by Verilator that use the VPI.
|
|
|
|
|
///
|
2015-09-26 02:57:28 +00:00
|
|
|
|
/// Use "verilator --vpi" to add this to the Makefile for the linker.
|
|
|
|
|
///
|
2010-12-25 19:39:41 +00:00
|
|
|
|
/// Code available from: http://www.veripool.org/verilator
|
|
|
|
|
///
|
|
|
|
|
//=========================================================================
|
|
|
|
|
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
2016-08-23 22:05:29 +00:00
|
|
|
|
#if VM_SC
|
|
|
|
|
# include "verilated_sc.h"
|
|
|
|
|
#endif
|
2015-09-26 02:57:28 +00:00
|
|
|
|
#include "verilated.h"
|
2010-12-25 19:39:41 +00:00
|
|
|
|
#include "verilated_vpi.h"
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
VerilatedVpi VerilatedVpi::s_s; // Singleton
|
|
|
|
|
vluint8_t* VerilatedVpio::s_freeHead = NULL;
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
2015-09-26 02:57:28 +00:00
|
|
|
|
// VerilatedVpi Methods
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VerilatedVpiError* VerilatedVpi::error_info() {
|
|
|
|
|
if (s_s.m_errorInfop == NULL) {
|
|
|
|
|
s_s.m_errorInfop = new VerilatedVpiError();
|
|
|
|
|
}
|
|
|
|
|
return s_s.m_errorInfop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// VerilatedVpiError Methods
|
2013-01-18 02:40:37 +00:00
|
|
|
|
|
|
|
|
|
const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) {
|
|
|
|
|
static const char *names[] = {
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiBinStrVal",
|
|
|
|
|
"vpiOctStrVal",
|
|
|
|
|
"vpiDecStrVal",
|
|
|
|
|
"vpiHexStrVal",
|
|
|
|
|
"vpiScalarVal",
|
|
|
|
|
"vpiIntVal",
|
|
|
|
|
"vpiRealVal",
|
|
|
|
|
"vpiStringVal",
|
|
|
|
|
"vpiVectorVal",
|
|
|
|
|
"vpiStrengthVal",
|
|
|
|
|
"vpiTimeVal",
|
|
|
|
|
"vpiObjTypeVal",
|
|
|
|
|
"vpiSuppressVal",
|
|
|
|
|
"vpiShortIntVal",
|
|
|
|
|
"vpiLongIntVal",
|
|
|
|
|
"vpiShortRealVal",
|
|
|
|
|
"vpiRawTwoStateVal",
|
|
|
|
|
"vpiRawFourStateVal",
|
|
|
|
|
};
|
|
|
|
|
if (vpiVal < 0) return names[0];
|
|
|
|
|
return names[(vpiVal<=vpiRawFourStateVal)?vpiVal:0];
|
|
|
|
|
}
|
|
|
|
|
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) {
|
|
|
|
|
static const char *names[] = {
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiAlways",
|
|
|
|
|
"vpiAssignStmt",
|
|
|
|
|
"vpiAssignment",
|
|
|
|
|
"vpiBegin",
|
|
|
|
|
"vpiCase",
|
|
|
|
|
"vpiCaseItem",
|
|
|
|
|
"vpiConstant",
|
|
|
|
|
"vpiContAssign",
|
|
|
|
|
"vpiDeassign",
|
|
|
|
|
"vpiDefParam",
|
|
|
|
|
"vpiDelayControl",
|
|
|
|
|
"vpiDisable",
|
|
|
|
|
"vpiEventControl",
|
|
|
|
|
"vpiEventStmt",
|
|
|
|
|
"vpiFor",
|
|
|
|
|
"vpiForce",
|
|
|
|
|
"vpiForever",
|
|
|
|
|
"vpiFork",
|
|
|
|
|
"vpiFuncCall",
|
|
|
|
|
"vpiFunction",
|
|
|
|
|
"vpiGate",
|
|
|
|
|
"vpiIf",
|
|
|
|
|
"vpiIfElse",
|
|
|
|
|
"vpiInitial",
|
|
|
|
|
"vpiIntegerVar",
|
|
|
|
|
"vpiInterModPath",
|
|
|
|
|
"vpiIterator",
|
|
|
|
|
"vpiIODecl",
|
|
|
|
|
"vpiMemory",
|
|
|
|
|
"vpiMemoryWord",
|
|
|
|
|
"vpiModPath",
|
|
|
|
|
"vpiModule",
|
|
|
|
|
"vpiNamedBegin",
|
|
|
|
|
"vpiNamedEvent",
|
|
|
|
|
"vpiNamedFork",
|
|
|
|
|
"vpiNet",
|
|
|
|
|
"vpiNetBit",
|
|
|
|
|
"vpiNullStmt",
|
|
|
|
|
"vpiOperation",
|
|
|
|
|
"vpiParamAssign",
|
|
|
|
|
"vpiParameter",
|
|
|
|
|
"vpiPartSelect",
|
|
|
|
|
"vpiPathTerm",
|
|
|
|
|
"vpiPort",
|
|
|
|
|
"vpiPortBit",
|
|
|
|
|
"vpiPrimTerm",
|
|
|
|
|
"vpiRealVar",
|
|
|
|
|
"vpiReg",
|
|
|
|
|
"vpiRegBit",
|
|
|
|
|
"vpiRelease",
|
|
|
|
|
"vpiRepeat",
|
|
|
|
|
"vpiRepeatControl",
|
|
|
|
|
"vpiSchedEvent",
|
|
|
|
|
"vpiSpecParam",
|
|
|
|
|
"vpiSwitch",
|
|
|
|
|
"vpiSysFuncCall",
|
|
|
|
|
"vpiSysTaskCall",
|
|
|
|
|
"vpiTableEntry",
|
|
|
|
|
"vpiTask",
|
|
|
|
|
"vpiTaskCall",
|
|
|
|
|
"vpiTchk",
|
|
|
|
|
"vpiTchkTerm",
|
|
|
|
|
"vpiTimeVar",
|
|
|
|
|
"vpiTimeQueue",
|
|
|
|
|
"vpiUdp",
|
|
|
|
|
"vpiUdpDefn",
|
|
|
|
|
"vpiUserSystf",
|
|
|
|
|
"vpiVarSelect",
|
|
|
|
|
"vpiWait",
|
|
|
|
|
"vpiWhile",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiAttribute",
|
|
|
|
|
"vpiBitSelect",
|
|
|
|
|
"vpiCallback",
|
|
|
|
|
"vpiDelayTerm",
|
|
|
|
|
"vpiDelayDevice",
|
|
|
|
|
"vpiFrame",
|
|
|
|
|
"vpiGateArray",
|
|
|
|
|
"vpiModuleArray",
|
|
|
|
|
"vpiPrimitiveArray",
|
|
|
|
|
"vpiNetArray",
|
|
|
|
|
"vpiRange",
|
|
|
|
|
"vpiRegArray",
|
|
|
|
|
"vpiSwitchArray",
|
|
|
|
|
"vpiUdpArray",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiContAssignBit",
|
|
|
|
|
"vpiNamedEventArray",
|
|
|
|
|
"vpiIndexedPartSelect",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiGenScopeArray",
|
|
|
|
|
"vpiGenScope",
|
|
|
|
|
"vpiGenVar"
|
|
|
|
|
};
|
|
|
|
|
if (vpiVal < 0) return names[0];
|
|
|
|
|
return names[(vpiVal<=vpiGenVar)?vpiVal:0];
|
|
|
|
|
}
|
|
|
|
|
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) {
|
|
|
|
|
static const char *names[] = {
|
|
|
|
|
"vpiCondition",
|
|
|
|
|
"vpiDelay",
|
|
|
|
|
"vpiElseStmt",
|
|
|
|
|
"vpiForIncStmt",
|
|
|
|
|
"vpiForInitStmt",
|
|
|
|
|
"vpiHighConn",
|
|
|
|
|
"vpiLhs",
|
|
|
|
|
"vpiIndex",
|
|
|
|
|
"vpiLeftRange",
|
|
|
|
|
"vpiLowConn",
|
|
|
|
|
"vpiParent",
|
|
|
|
|
"vpiRhs",
|
|
|
|
|
"vpiRightRange",
|
|
|
|
|
"vpiScope",
|
|
|
|
|
"vpiSysTfCall",
|
|
|
|
|
"vpiTchkDataTerm",
|
|
|
|
|
"vpiTchkNotifier",
|
|
|
|
|
"vpiTchkRefTerm",
|
|
|
|
|
"vpiArgument",
|
|
|
|
|
"vpiBit",
|
|
|
|
|
"vpiDriver",
|
|
|
|
|
"vpiInternalScope",
|
|
|
|
|
"vpiLoad",
|
|
|
|
|
"vpiModDataPathIn",
|
|
|
|
|
"vpiModPathIn",
|
|
|
|
|
"vpiModPathOut",
|
|
|
|
|
"vpiOperand",
|
|
|
|
|
"vpiPortInst",
|
|
|
|
|
"vpiProcess",
|
|
|
|
|
"vpiVariables",
|
|
|
|
|
"vpiUse",
|
|
|
|
|
"vpiExpr",
|
|
|
|
|
"vpiPrimitive",
|
|
|
|
|
"vpiStmt"
|
|
|
|
|
};
|
|
|
|
|
if (vpiVal>vpiStmt || vpiVal<vpiCondition) {
|
|
|
|
|
return "*undefined*";
|
|
|
|
|
}
|
|
|
|
|
return names[vpiVal-vpiCondition];
|
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
2013-01-18 02:40:37 +00:00
|
|
|
|
const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) {
|
|
|
|
|
static const char *names[] = {
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"cbValueChange",
|
|
|
|
|
"cbStmt",
|
|
|
|
|
"cbForce",
|
|
|
|
|
"cbRelease",
|
|
|
|
|
"cbAtStartOfSimTime",
|
|
|
|
|
"cbReadWriteSynch",
|
|
|
|
|
"cbReadOnlySynch",
|
|
|
|
|
"cbNextSimTime",
|
|
|
|
|
"cbAfterDelay",
|
|
|
|
|
"cbEndOfCompile",
|
|
|
|
|
"cbStartOfSimulation",
|
|
|
|
|
"cbEndOfSimulation",
|
|
|
|
|
"cbError",
|
|
|
|
|
"cbTchkViolation",
|
|
|
|
|
"cbStartOfSave",
|
|
|
|
|
"cbEndOfSave",
|
|
|
|
|
"cbStartOfRestart",
|
|
|
|
|
"cbEndOfRestart",
|
|
|
|
|
"cbStartOfReset",
|
|
|
|
|
"cbEndOfReset",
|
|
|
|
|
"cbEnterInteractive",
|
|
|
|
|
"cbExitInteractive",
|
|
|
|
|
"cbInteractiveScopeChange",
|
|
|
|
|
"cbUnresolvedSystf",
|
|
|
|
|
"cbAssign",
|
|
|
|
|
"cbDeassign",
|
|
|
|
|
"cbDisable",
|
|
|
|
|
"cbPLIError",
|
|
|
|
|
"cbSignal",
|
|
|
|
|
"cbNBASynch",
|
|
|
|
|
"cbAtEndOfSimTime"
|
|
|
|
|
};
|
|
|
|
|
if (vpiVal < 0) return names[0];
|
|
|
|
|
return names[(vpiVal<=cbAtEndOfSimTime)?vpiVal:0];
|
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
2013-01-18 02:40:37 +00:00
|
|
|
|
const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) {
|
|
|
|
|
static const char *names[] = {
|
|
|
|
|
"*undefined or other*",
|
|
|
|
|
"vpiType",
|
|
|
|
|
"vpiName",
|
|
|
|
|
"vpiFullName",
|
|
|
|
|
"vpiSize",
|
|
|
|
|
"vpiFile",
|
|
|
|
|
"vpiLineNo",
|
|
|
|
|
"vpiTopModule",
|
|
|
|
|
"vpiCellInstance",
|
|
|
|
|
"vpiDefName",
|
|
|
|
|
"vpiProtected",
|
|
|
|
|
"vpiTimeUnit",
|
|
|
|
|
"vpiTimePrecision",
|
|
|
|
|
"vpiDefNetType",
|
|
|
|
|
"vpiUnconnDrive",
|
|
|
|
|
"vpiDefFile",
|
|
|
|
|
"vpiDefLineNo",
|
|
|
|
|
"vpiScalar",
|
|
|
|
|
"vpiVector",
|
|
|
|
|
"vpiExplicitName",
|
|
|
|
|
"vpiDirection",
|
|
|
|
|
"vpiConnByName",
|
|
|
|
|
"vpiNetType",
|
|
|
|
|
"vpiExplicitScalared",
|
|
|
|
|
"vpiExplicitVectored",
|
|
|
|
|
"vpiExpanded",
|
|
|
|
|
"vpiImplicitDecl",
|
|
|
|
|
"vpiChargeStrength",
|
|
|
|
|
"vpiArray",
|
|
|
|
|
"vpiPortIndex",
|
|
|
|
|
"vpiTermIndex",
|
|
|
|
|
"vpiStrength0",
|
|
|
|
|
"vpiStrength1",
|
|
|
|
|
"vpiPrimType",
|
|
|
|
|
"vpiPolarity",
|
|
|
|
|
"vpiDataPolarity",
|
|
|
|
|
"vpiEdge",
|
|
|
|
|
"vpiPathType",
|
|
|
|
|
"vpiTchkType",
|
|
|
|
|
"vpiOpType",
|
|
|
|
|
"vpiConstType",
|
|
|
|
|
"vpiBlocking",
|
|
|
|
|
"vpiCaseType",
|
|
|
|
|
"vpiFuncType",
|
|
|
|
|
"vpiNetDeclAssign",
|
|
|
|
|
"vpiUserDefn",
|
|
|
|
|
"vpiScheduled",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiActive",
|
|
|
|
|
"vpiAutomatic",
|
|
|
|
|
"vpiCell",
|
|
|
|
|
"vpiConfig",
|
|
|
|
|
"vpiConstantSelect",
|
|
|
|
|
"vpiDecompile",
|
|
|
|
|
"vpiDefAttribute",
|
|
|
|
|
"vpiDelayType",
|
|
|
|
|
"vpiIteratorType",
|
|
|
|
|
"vpiLibrary",
|
|
|
|
|
"*undefined*",
|
|
|
|
|
"vpiOffset",
|
|
|
|
|
"vpiResolvedNetType",
|
|
|
|
|
"vpiSaveRestartID",
|
|
|
|
|
"vpiSaveRestartLocation",
|
|
|
|
|
"vpiValid",
|
|
|
|
|
"vpiSigned",
|
|
|
|
|
"vpiStop",
|
|
|
|
|
"vpiFinish",
|
|
|
|
|
"vpiReset",
|
|
|
|
|
"vpiSetInteractiveScope",
|
|
|
|
|
"vpiLocalParam",
|
|
|
|
|
"vpiModPathHasIfNone",
|
|
|
|
|
"vpiIndexedPartSelectType",
|
|
|
|
|
"vpiIsMemory",
|
|
|
|
|
"vpiIsProtected"
|
|
|
|
|
};
|
|
|
|
|
if (vpiVal == vpiUndefined) {
|
|
|
|
|
return "vpiUndefined";
|
|
|
|
|
}
|
|
|
|
|
return names[(vpiVal<=vpiIsProtected)?vpiVal:0];
|
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
|
|
|
|
#define CHECK_RESULT_CSTR(got, exp) \
|
|
|
|
|
if (strcmp((got),(exp))) { \
|
2017-09-23 11:32:37 +00:00
|
|
|
|
std::string msg = std::string("%Error: ") \
|
2015-09-26 02:57:28 +00:00
|
|
|
|
+ "GOT = '"+((got)?(got):"<null>")+"'" \
|
|
|
|
|
+ " EXP = '"+((exp)?(exp):"<null>")+"'"; \
|
|
|
|
|
vl_fatal(__FILE__,__LINE__,"",msg.c_str()); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define CHECK_ENUM_STR(fn, enum) \
|
|
|
|
|
do { \
|
|
|
|
|
const char* strVal = VerilatedVpiError::fn(enum); \
|
|
|
|
|
CHECK_RESULT_CSTR(strVal, #enum); \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
void VerilatedVpiError::selfTest() {
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiVal, vpiBinStrVal);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiVal, vpiRawFourStateVal);
|
|
|
|
|
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiObjType, vpiAlways);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiObjType, vpiWhile);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiObjType, vpiAttribute);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiObjType, vpiUdpArray);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiObjType, vpiContAssignBit);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar);
|
|
|
|
|
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiMethod, vpiCondition);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiMethod, vpiStmt);
|
|
|
|
|
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiCallbackReason, cbValueChange);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiCallbackReason, cbAtEndOfSimTime);
|
|
|
|
|
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiType);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiProtected);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiDirection);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiTermIndex);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiConstType);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiAutomatic);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiOffset);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiStop);
|
|
|
|
|
CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef CHECK_ENUM_STR
|
|
|
|
|
#undef CHECK_RESULT_CSTR
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// callback related
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
2015-10-04 02:33:06 +00:00
|
|
|
|
// cppcheck-suppress nullPointer
|
2015-09-26 02:57:28 +00:00
|
|
|
|
if (VL_UNLIKELY(!cb_data_p)) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s : callback data pointer is null", VL_FUNC);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
switch (cb_data_p->reason) {
|
|
|
|
|
case cbAfterDelay: {
|
|
|
|
|
QData time = 0;
|
|
|
|
|
if (cb_data_p->time) time = _VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
|
|
|
|
|
VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, VL_TIME_Q()+time);
|
2015-10-04 02:33:06 +00:00
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_register_cb %d %p delay=%" VL_PRI64 "u\n",cb_data_p->reason,vop,time););
|
2015-09-26 02:57:28 +00:00
|
|
|
|
VerilatedVpi::cbTimedAdd(vop);
|
|
|
|
|
return vop->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
case cbReadWriteSynch: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
|
case cbReadOnlySynch: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
|
case cbNextSimTime: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
|
case cbStartOfSimulation: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
|
case cbEndOfSimulation: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
|
case cbValueChange: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
|
case cbPLIError: // FALLTHRU // NOP, but need to return handle, so make object
|
|
|
|
|
case cbEnterInteractive: // FALLTHRU // NOP, but need to return handle, so make object
|
|
|
|
|
case cbExitInteractive: // FALLTHRU // NOP, but need to return handle, so make object
|
|
|
|
|
case cbInteractiveScopeChange: { // FALLTHRU // NOP, but need to return handle, so make object
|
|
|
|
|
VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, 0);
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_register_cb %d %p\n",cb_data_p->reason,vop););
|
|
|
|
|
VerilatedVpi::cbReasonAdd(vop);
|
|
|
|
|
return vop->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason));
|
|
|
|
|
return NULL;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_remove_cb(vpiHandle object) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_remove_cb %p\n",object););
|
|
|
|
|
VerilatedVpioCb* vop = VerilatedVpioCb::castp(object);
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
if (vop->cb_datap()->reason == cbAfterDelay) {
|
|
|
|
|
VerilatedVpi::cbTimedRemove(vop);
|
|
|
|
|
} else {
|
|
|
|
|
VerilatedVpi::cbReasonRemove(vop);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vpi_get_cb_info(vpiHandle object, p_cb_data cb_data_p) {
|
|
|
|
|
_VL_VPI_UNIMP(); return;
|
|
|
|
|
}
|
|
|
|
|
vpiHandle vpi_register_systf(p_vpi_systf_data systf_data_p) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
void vpi_get_systf_info(vpiHandle object, p_vpi_systf_data systf_data_p) {
|
|
|
|
|
_VL_VPI_UNIMP(); return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for obtaining handles
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!namep)) return NULL;
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle_by_name %s %p\n",namep,scope););
|
|
|
|
|
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
|
|
|
|
|
const VerilatedVar* varp;
|
|
|
|
|
const VerilatedScope* scopep;
|
2017-09-23 11:32:37 +00:00
|
|
|
|
std::string scopeAndName = namep;
|
2015-09-26 02:57:28 +00:00
|
|
|
|
if (voScopep) {
|
2017-09-23 11:32:37 +00:00
|
|
|
|
scopeAndName = std::string(voScopep->fullname()) + "." + namep;
|
2015-09-26 02:57:28 +00:00
|
|
|
|
namep = (PLI_BYTE8*)scopeAndName.c_str();
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// This doesn't yet follow the hierarchy in the proper way
|
|
|
|
|
scopep = Verilated::scopeFind(namep);
|
|
|
|
|
if (scopep) { // Whole thing found as a scope
|
|
|
|
|
return (new VerilatedVpioScope(scopep))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
const char* baseNamep = scopeAndName.c_str();
|
2017-09-23 11:32:37 +00:00
|
|
|
|
std::string scopename;
|
2015-09-26 02:57:28 +00:00
|
|
|
|
const char* dotp = strrchr(namep, '.');
|
|
|
|
|
if (VL_LIKELY(dotp)) {
|
|
|
|
|
baseNamep = dotp+1;
|
2017-09-23 11:32:37 +00:00
|
|
|
|
scopename = std::string(namep,dotp-namep);
|
2015-09-26 02:57:28 +00:00
|
|
|
|
}
|
|
|
|
|
scopep = Verilated::scopeFind(scopename.c_str());
|
|
|
|
|
if (!scopep) return NULL;
|
|
|
|
|
varp = scopep->varFind(baseNamep);
|
|
|
|
|
}
|
|
|
|
|
if (!varp) return NULL;
|
|
|
|
|
return (new VerilatedVpioVar(varp, scopep))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
|
|
|
|
// Used to get array entries
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle_by_index %p %d\n",object, indx););
|
|
|
|
|
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_LIKELY(varop)) {
|
|
|
|
|
if (varop->varp()->dims()<2) return 0;
|
|
|
|
|
if (VL_LIKELY(varop->varp()->array().left() >= varop->varp()->array().right())) {
|
|
|
|
|
if (VL_UNLIKELY(indx > varop->varp()->array().left() || indx < varop->varp()->array().right())) return 0;
|
|
|
|
|
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
|
|
|
|
indx - varop->varp()->array().right()))
|
|
|
|
|
->castVpiHandle();
|
|
|
|
|
} else {
|
|
|
|
|
if (VL_UNLIKELY(indx < varop->varp()->array().left() || indx > varop->varp()->array().right())) return 0;
|
|
|
|
|
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
|
|
|
|
indx - varop->varp()->array().left()))
|
|
|
|
|
->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
_VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for traversing relationships
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle %d %p\n",type,object););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
switch (type) {
|
|
|
|
|
case vpiLeftRange: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
|
|
|
|
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
case vpiRightRange: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
|
|
|
|
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
case vpiIndex: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
case vpiScope: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
case vpiParent: {
|
|
|
|
|
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle refHandle1, vpiHandle refHandle2, ... ) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_iterate %d %p\n",type,object););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
switch (type) {
|
|
|
|
|
case vpiMemoryWord: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
if (vop->varp()->dims() < 2) return 0;
|
|
|
|
|
if (vop->varp()->dims() > 2) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), vop->fullname() , vop->varp()->dims());
|
|
|
|
|
}
|
|
|
|
|
return (new VerilatedVpioMemoryWordIter(object, vop->varp()))->castVpiHandle();
|
|
|
|
|
}
|
|
|
|
|
case vpiRange: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
if (vop->varp()->dims() < 2) return 0;
|
|
|
|
|
// Unsupported is multidim list
|
|
|
|
|
if (vop->varp()->dims() > 2) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), vop->fullname() , vop->varp()->dims());
|
|
|
|
|
}
|
|
|
|
|
return ((new VerilatedVpioRange(vop->rangep()))->castVpiHandle());
|
|
|
|
|
}
|
|
|
|
|
case vpiReg: {
|
|
|
|
|
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return ((new VerilatedVpioVarIter(vop->scopep()))
|
|
|
|
|
->castVpiHandle());
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vpiHandle vpi_scan(vpiHandle object) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_scan %p\n",object););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return NULL;
|
|
|
|
|
return vop->dovpi_scan();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for processing properties
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
|
|
|
|
|
// Leave this in the header file - in many cases the compiler can constant propagate "object"
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get %d %p\n",property,object););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
switch (property) {
|
|
|
|
|
case vpiTimePrecision: {
|
|
|
|
|
return VL_TIME_PRECISION;
|
|
|
|
|
}
|
|
|
|
|
case vpiType: {
|
|
|
|
|
VerilatedVpio* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return vop->type();
|
|
|
|
|
}
|
|
|
|
|
case vpiDirection: {
|
|
|
|
|
// By forthought, the directions already are vpi enumerated
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return vop->varp()->vldir();
|
|
|
|
|
}
|
|
|
|
|
case vpiScalar: // FALLTHRU
|
|
|
|
|
case vpiVector: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return (property==vpiVector)^(vop->varp()->dims()==0);
|
|
|
|
|
}
|
|
|
|
|
case vpiSize: {
|
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
return vop->size();
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT64 vpi_get64(PLI_INT32 property, vpiHandle object) {
|
|
|
|
|
_VL_VPI_UNIMP();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_BYTE8 *vpi_get_str(PLI_INT32 property, vpiHandle object) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_str %d %p\n",property,object););
|
|
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return NULL;
|
|
|
|
|
switch (property) {
|
|
|
|
|
case vpiName: {
|
|
|
|
|
return (PLI_BYTE8*)vop->name();
|
|
|
|
|
}
|
|
|
|
|
case vpiFullName: {
|
|
|
|
|
return (PLI_BYTE8*)vop->fullname();
|
|
|
|
|
}
|
|
|
|
|
case vpiDefName: {
|
|
|
|
|
return (PLI_BYTE8*)vop->defname();
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delay processing
|
|
|
|
|
|
|
|
|
|
void vpi_get_delays(vpiHandle object, p_vpi_delay delay_p) {
|
|
|
|
|
_VL_VPI_UNIMP();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
void vpi_put_delays(vpiHandle object, p_vpi_delay delay_p) {
|
|
|
|
|
_VL_VPI_UNIMP();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// value processing
|
|
|
|
|
|
|
|
|
|
void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
2017-10-08 01:29:57 +00:00
|
|
|
|
static VL_THREAD_LOCAL char outStr[1+VL_MULS_MAX_WORDS*32]; // Maximum required size is for binary string, one byte per bit plus null termination
|
2015-09-26 02:57:28 +00:00
|
|
|
|
// cppcheck-suppress variableScope
|
2017-10-08 01:29:57 +00:00
|
|
|
|
static VL_THREAD_LOCAL int outStrSz = sizeof(outStr)-1;
|
2015-09-26 02:57:28 +00:00
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_value %p\n",object););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!value_p)) return;
|
|
|
|
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
|
|
|
|
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
|
|
|
|
// This may cause backward compatability issues with older code.
|
|
|
|
|
if (value_p->format == vpiVectorVal) {
|
|
|
|
|
// Vector pointer must come from our memory pool
|
|
|
|
|
// It only needs to persist until the next vpi_get_value
|
2017-10-08 01:29:57 +00:00
|
|
|
|
static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS*2];
|
2015-09-26 02:57:28 +00:00
|
|
|
|
value_p->value.vector = out;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8:
|
|
|
|
|
out[0].aval = *((CData*)(vop->varDatap()));
|
|
|
|
|
out[0].bval = 0;
|
|
|
|
|
return;
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
out[0].aval = *((SData*)(vop->varDatap()));
|
|
|
|
|
out[0].bval = 0;
|
|
|
|
|
return;
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
out[0].aval = *((IData*)(vop->varDatap()));
|
|
|
|
|
out[0].bval = 0;
|
|
|
|
|
return;
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int words = VL_WORDS_I(vop->varp()->range().elements());
|
|
|
|
|
if (VL_UNLIKELY(words >= VL_MULS_MAX_WORDS)) {
|
|
|
|
|
vl_fatal(__FILE__,__LINE__,"", "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile");
|
|
|
|
|
}
|
|
|
|
|
WDataInP datap = ((IData*)(vop->varDatap()));
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=0; i<words; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
out[i].aval = datap[i];
|
|
|
|
|
out[i].bval = 0;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case VLVT_UINT64: {
|
|
|
|
|
QData data = *((QData*)(vop->varDatap()));
|
|
|
|
|
out[1].aval = (IData)(data>>VL_ULL(32));
|
|
|
|
|
out[1].bval = 0;
|
|
|
|
|
out[0].aval = (IData)(data);
|
|
|
|
|
out[0].bval = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiBinStrVal) {
|
|
|
|
|
value_p->value.str = outStr;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int bits = vop->varp()->range().elements();
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
|
|
|
|
int i;
|
|
|
|
|
if (bits > outStrSz) {
|
|
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
|
|
|
|
bits = outStrSz;
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits);
|
|
|
|
|
}
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (i=0; i<bits; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
char val = (datap[i>>3]>>(i&7))&1;
|
|
|
|
|
outStr[bits-i-1] = val?'1':'0';
|
|
|
|
|
}
|
|
|
|
|
outStr[i]=0; // NULL terminate
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiOctStrVal) {
|
|
|
|
|
value_p->value.str = outStr;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int chars = (vop->varp()->range().elements()+2)/3;
|
|
|
|
|
int bytes = VL_BYTES_I(vop->varp()->range().elements());
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
|
|
|
|
int i;
|
|
|
|
|
if (chars > outStrSz) {
|
|
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
|
|
|
|
|
chars = outStrSz;
|
|
|
|
|
}
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (i=0; i<chars; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
div_t idx = div(i*3, 8);
|
|
|
|
|
int val = datap[idx.quot];
|
|
|
|
|
if ((idx.quot+1)<bytes) {
|
|
|
|
|
// if the next byte is valid or that in
|
|
|
|
|
// for when the required 3 bits straddle adjacent bytes
|
|
|
|
|
val |= datap[idx.quot+1]<<8;
|
|
|
|
|
}
|
|
|
|
|
// align so least significant 3 bits represent octal char
|
|
|
|
|
val >>= idx.rem;
|
|
|
|
|
if (i==(chars-1)) {
|
|
|
|
|
// most signifcant char, mask off non existant bits when vector
|
|
|
|
|
// size is not a multiple of 3
|
|
|
|
|
unsigned int rem = vop->varp()->range().elements() % 3;
|
|
|
|
|
if (rem) {
|
|
|
|
|
// generate bit mask & zero non existant bits
|
|
|
|
|
val &= (1<<rem)-1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
outStr[chars-i-1] = '0' + (val&7);
|
|
|
|
|
}
|
|
|
|
|
outStr[i]=0; // NULL terminate
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
strcpy(outStr, "0");
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiDecStrVal) {
|
|
|
|
|
value_p->value.str = outStr;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
// outStrSz does not include NULL termination so add one
|
|
|
|
|
case VLVT_UINT8 : VL_SNPRINTF(outStr, outStrSz+1, "%hhu", (unsigned char )*((CData*)(vop->varDatap()))); return;
|
|
|
|
|
case VLVT_UINT16: VL_SNPRINTF(outStr, outStrSz+1, "%hu", (unsigned short)*((SData*)(vop->varDatap()))); return;
|
|
|
|
|
case VLVT_UINT32: VL_SNPRINTF(outStr, outStrSz+1, "%u", (unsigned int )*((IData*)(vop->varDatap()))); return;
|
|
|
|
|
case VLVT_UINT64: VL_SNPRINTF(outStr, outStrSz+1, "%llu", (unsigned long long)*((QData*)(vop->varDatap()))); return;
|
|
|
|
|
default:
|
|
|
|
|
strcpy(outStr, "-1");
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s, maximum limit is 64 bits",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiHexStrVal) {
|
|
|
|
|
value_p->value.str = outStr;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int chars = (vop->varp()->range().elements()+3)>>2;
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
|
|
|
|
int i;
|
|
|
|
|
if (chars > outStrSz) {
|
|
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
|
|
|
|
|
chars = outStrSz;
|
|
|
|
|
}
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (i=0; i<chars; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
char val = (datap[i>>1]>>((i&1)<<2))&15;
|
|
|
|
|
if (i==(chars-1)) {
|
|
|
|
|
// most signifcant char, mask off non existant bits when vector
|
|
|
|
|
// size is not a multiple of 4
|
|
|
|
|
unsigned int rem = vop->varp()->range().elements() & 3;
|
|
|
|
|
if (rem) {
|
|
|
|
|
// generate bit mask & zero non existant bits
|
|
|
|
|
val &= (1<<rem)-1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-10-08 01:29:57 +00:00
|
|
|
|
outStr[chars-i-1] = "0123456789abcdef"[static_cast<int>(val)];
|
2015-09-26 02:57:28 +00:00
|
|
|
|
}
|
|
|
|
|
outStr[i]=0; // NULL terminate
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiStringVal) {
|
|
|
|
|
value_p->value.str = outStr;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int bytes = VL_BYTES_I(vop->varp()->range().elements());
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
|
|
|
|
int i;
|
|
|
|
|
if (bytes > outStrSz) {
|
|
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format),
|
|
|
|
|
vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes);
|
|
|
|
|
bytes = outStrSz;
|
|
|
|
|
}
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (i=0; i<bytes; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
char val = datap[bytes-i-1];
|
|
|
|
|
// other simulators replace [leading?] zero chars with spaces, replicate here.
|
|
|
|
|
outStr[i] = val?val:' ';
|
|
|
|
|
}
|
|
|
|
|
outStr[i]=0; // NULL terminate
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiIntVal) {
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8:
|
|
|
|
|
value_p->value.integer = *((CData*)(vop->varDatap()));
|
|
|
|
|
return;
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
value_p->value.integer = *((SData*)(vop->varDatap()));
|
|
|
|
|
return;
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
value_p->value.integer = *((IData*)(vop->varDatap()));
|
|
|
|
|
return;
|
2017-07-06 23:49:34 +00:00
|
|
|
|
case VLVT_WDATA: // FALLTHRU
|
|
|
|
|
case VLVT_UINT64: // FALLTHRU
|
2015-09-26 02:57:28 +00:00
|
|
|
|
default:
|
2017-07-06 23:49:34 +00:00
|
|
|
|
value_p->value.integer = 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiSuppressVal) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
|
|
|
|
|
if (value_p->format == vpiIntVal) {
|
|
|
|
|
value_p->value.integer = vop->num();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
|
|
|
|
p_vpi_time time_p, PLI_INT32 flags) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_put_value %p %p\n",object, value_p););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!value_p)) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with NULL value pointer");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_put_value name=%s fmt=%d vali=%d\n",
|
|
|
|
|
vop->fullname(), value_p->format, value_p->value.integer);
|
|
|
|
|
VL_PRINTF("-vltVpi: varp=%p putatp=%p\n",
|
|
|
|
|
vop->varp()->datap(), vop->varDatap()););
|
|
|
|
|
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value to signal marked read-only, use public_flat_rw instead: ", vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (value_p->format == vpiVectorVal) {
|
|
|
|
|
if (VL_UNLIKELY(!value_p->value.vector)) return NULL;
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8:
|
|
|
|
|
*((CData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask();
|
|
|
|
|
return object;
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
*((SData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask();
|
|
|
|
|
return object;
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
*((IData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask();
|
|
|
|
|
return object;
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int words = VL_WORDS_I(vop->varp()->range().elements());
|
|
|
|
|
WDataOutP datap = ((IData*)(vop->varDatap()));
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=0; i<words; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
datap[i] = value_p->value.vector[i].aval;
|
|
|
|
|
if (i==(words-1)) {
|
|
|
|
|
datap[i] &= vop->mask();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
case VLVT_UINT64: {
|
|
|
|
|
*((QData*)(vop->varDatap())) = _VL_SET_QII(
|
|
|
|
|
value_p->value.vector[1].aval & vop->mask(),
|
|
|
|
|
value_p->value.vector[0].aval);
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiBinStrVal) {
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int bits = vop->varp()->range().elements();
|
|
|
|
|
int len = strlen(value_p->value.str);
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=0; i<bits; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
char set = (i < len)?(value_p->value.str[len-i-1]=='1'):0;
|
|
|
|
|
// zero bits 7:1 of byte when assigning to bit 0, else
|
|
|
|
|
// or in 1 if bit set
|
|
|
|
|
if (i&7) {
|
|
|
|
|
datap[i>>3] |= set<<(i&7);
|
|
|
|
|
} else {
|
|
|
|
|
datap[i>>3] = set;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiOctStrVal) {
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int chars = (vop->varp()->range().elements()+2)/3;
|
|
|
|
|
int bytes = VL_BYTES_I(vop->varp()->range().elements());
|
|
|
|
|
int len = strlen(value_p->value.str);
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
|
|
|
|
div_t idx;
|
|
|
|
|
datap[0] = 0; // reset zero'th byte
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=0; i<chars; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
union {
|
|
|
|
|
char byte[2];
|
|
|
|
|
short half;
|
|
|
|
|
} val;
|
|
|
|
|
idx = div(i*3, 8);
|
|
|
|
|
if (i < len) {
|
|
|
|
|
// ignore illegal chars
|
|
|
|
|
char digit = value_p->value.str[len-i-1];
|
|
|
|
|
if (digit >= '0' && digit <= '7') {
|
|
|
|
|
val.half = digit-'0';
|
|
|
|
|
} else {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Non octal character '%c' in '%s' as value %s for %s",
|
|
|
|
|
VL_FUNC, digit, value_p->value.str,
|
|
|
|
|
VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
val.half = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
val.half = 0;
|
|
|
|
|
}
|
|
|
|
|
// align octal character to position within vector, note that
|
|
|
|
|
// the three bits may straddle a byte bounday so two byte wide
|
|
|
|
|
// assignments are made to adjacent bytes - but not if the least
|
|
|
|
|
// signifcant byte of the aligned value is the most significant
|
|
|
|
|
// byte of the destination.
|
|
|
|
|
val.half <<= idx.rem;
|
|
|
|
|
datap[idx.quot] |= val.byte[0]; // or in value
|
|
|
|
|
if ((idx.quot+1) < bytes) {
|
|
|
|
|
datap[idx.quot+1] = val.byte[1]; // this also resets all bits to 0 prior to or'ing above
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// mask off non existant bits in the most significant byte
|
|
|
|
|
if (idx.quot == (bytes-1)) {
|
|
|
|
|
datap[idx.quot] &= vop->mask_byte(idx.quot);
|
|
|
|
|
} else if (idx.quot+1 == (bytes-1)) {
|
|
|
|
|
datap[idx.quot+1] &= vop->mask_byte(idx.quot+1);
|
|
|
|
|
}
|
|
|
|
|
// zero off remaining top bytes
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=idx.quot+2; i<bytes; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
datap[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiDecStrVal) {
|
|
|
|
|
char remainder[16];
|
|
|
|
|
unsigned long long val;
|
|
|
|
|
int success = sscanf(value_p->value.str, "%30llu%15s", &val, remainder);
|
|
|
|
|
if (success < 1) {
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
|
|
|
|
VL_FUNC, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (success > 1) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Trailing garbage '%s' in '%s' as value %s for %s",
|
|
|
|
|
VL_FUNC, remainder, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
}
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 : *((CData*)(vop->varDatap())) = val & vop->mask(); break;
|
|
|
|
|
case VLVT_UINT16: *((SData*)(vop->varDatap())) = val & vop->mask(); break;
|
|
|
|
|
case VLVT_UINT32: *((IData*)(vop->varDatap())) = val & vop->mask(); break;
|
|
|
|
|
case VLVT_UINT64: *((QData*)(vop->varDatap())) = val; ((IData*)(vop->varDatap()))[1] &= vop->mask(); break;
|
|
|
|
|
case VLVT_WDATA:
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s, maximum limit is 64 bits",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
} else if (value_p->format == vpiHexStrVal) {
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int chars = (vop->varp()->range().elements()+3)>>2;
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
|
|
|
|
char* val = value_p->value.str;
|
|
|
|
|
// skip hex ident if one is detected at the start of the string
|
|
|
|
|
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) {
|
|
|
|
|
val += 2;
|
|
|
|
|
}
|
|
|
|
|
int len = strlen(val);
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=0; i<chars; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
char hex;
|
|
|
|
|
// compute hex digit value
|
|
|
|
|
if (i < len) {
|
|
|
|
|
char digit = val[len-i-1];
|
|
|
|
|
if (digit >= '0' && digit <= '9') hex = digit - '0';
|
|
|
|
|
else if (digit >= 'a' && digit <= 'f') hex = digit - 'a' + 10;
|
|
|
|
|
else if (digit >= 'A' && digit <= 'F') hex = digit - 'A' + 10;
|
|
|
|
|
else {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Non hex character '%c' in '%s' as value %s for %s",
|
|
|
|
|
VL_FUNC, digit, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
hex = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
hex = 0;
|
|
|
|
|
}
|
|
|
|
|
// assign hex digit value to destination
|
|
|
|
|
if (i&1) {
|
|
|
|
|
datap[i>>1] |= hex<<4;
|
|
|
|
|
} else {
|
|
|
|
|
datap[i>>1] = hex; // this also resets all bits to 0 prior to or'ing above of the msb
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// apply bit mask to most significant byte
|
|
|
|
|
datap[(chars-1)>>1] &= vop->mask_byte((chars-1)>>1);
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiStringVal) {
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8 :
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
case VLVT_UINT64:
|
|
|
|
|
case VLVT_WDATA: {
|
|
|
|
|
int bytes = VL_BYTES_I(vop->varp()->range().elements());
|
|
|
|
|
int len = strlen(value_p->value.str);
|
|
|
|
|
CData* datap = ((CData*)(vop->varDatap()));
|
2017-06-06 00:16:51 +00:00
|
|
|
|
for (int i=0; i<bytes; ++i) {
|
2015-09-26 02:57:28 +00:00
|
|
|
|
datap[i] = (i < len)?value_p->value.str[len-i-1]:0; // prepend with 0 values before placing string the least signifcant bytes
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (value_p->format == vpiIntVal) {
|
|
|
|
|
switch (vop->varp()->vltype()) {
|
|
|
|
|
case VLVT_UINT8:
|
|
|
|
|
*((CData*)(vop->varDatap())) = vop->mask() & value_p->value.integer;
|
|
|
|
|
return object;
|
|
|
|
|
case VLVT_UINT16:
|
|
|
|
|
*((SData*)(vop->varDatap())) = vop->mask() & value_p->value.integer;
|
|
|
|
|
return object;
|
|
|
|
|
case VLVT_UINT32:
|
|
|
|
|
*((IData*)(vop->varDatap())) = vop->mask() & value_p->value.integer;
|
|
|
|
|
return object;
|
|
|
|
|
case VLVT_WDATA: // FALLTHRU
|
|
|
|
|
case VLVT_UINT64: // FALLTHRU
|
|
|
|
|
default:
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for ??",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
|
|
|
|
|
PLI_INT32 *index_p, PLI_UINT32 num) {
|
|
|
|
|
_VL_VPI_UNIMP(); return;
|
|
|
|
|
}
|
|
|
|
|
void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
|
|
|
|
|
PLI_INT32 *index_p, PLI_UINT32 num) {
|
|
|
|
|
_VL_VPI_UNIMP(); return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// time processing
|
|
|
|
|
|
|
|
|
|
void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
|
2015-10-04 02:33:06 +00:00
|
|
|
|
// cppcheck-suppress nullPointer
|
2015-09-26 02:57:28 +00:00
|
|
|
|
if (VL_UNLIKELY(!time_p)) {
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_get_time with NULL value pointer");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (time_p->type == vpiSimTime) {
|
|
|
|
|
QData qtime = VL_TIME_Q();
|
2017-06-06 00:04:09 +00:00
|
|
|
|
WData itime[2];
|
2015-09-26 02:57:28 +00:00
|
|
|
|
VL_SET_WQ(itime, qtime);
|
|
|
|
|
time_p->low = itime[0];
|
|
|
|
|
time_p->high = itime[1];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported type (%d)",
|
|
|
|
|
VL_FUNC, time_p->type);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// I/O routines
|
|
|
|
|
|
|
|
|
|
PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *filenamep) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
return VL_FOPEN_S(filenamep,"wb");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
VL_FCLOSE_I(mcd); return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 mcd) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap,formatp);
|
|
|
|
|
int chars = vpi_mcd_vprintf(mcd, formatp, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
return chars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap,formatp);
|
|
|
|
|
int chars = vpi_vprintf(formatp, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
return chars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
return VL_VPRINTF(formatp, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) {
|
|
|
|
|
FILE* fp = VL_CVT_I_FP(mcd);
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
2015-10-04 02:33:06 +00:00
|
|
|
|
// cppcheck-suppress nullPointer
|
2015-09-26 02:57:28 +00:00
|
|
|
|
if (VL_UNLIKELY(!fp)) return 0;
|
|
|
|
|
int chars = vfprintf(fp, format, ap);
|
|
|
|
|
return chars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_flush(void) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
Verilated::flushCall();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
|
|
|
|
|
FILE* fp = VL_CVT_I_FP(mcd);
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!fp)) return 1;
|
|
|
|
|
fflush(fp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// utility routines
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_compare_objects(vpiHandle object1, vpiHandle object2) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
|
|
|
|
|
// executing vpi_chk_error does not reset error
|
|
|
|
|
// error_info_p can be NULL, so only return level in that case
|
|
|
|
|
p_vpi_error_info _error_info_p = VerilatedVpi::error_info()->getError();
|
|
|
|
|
if (error_info_p && _error_info_p) {
|
|
|
|
|
*error_info_p = *_error_info_p;
|
|
|
|
|
}
|
|
|
|
|
if (!_error_info_p) return 0; // no error occured
|
|
|
|
|
return _error_info_p->level; // return error severity level
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_free_object(vpiHandle object) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
return vpi_release_handle(object); // Deprecated
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_release_handle (vpiHandle object) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_release_handle %p\n",object););
|
|
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
|
vpi_remove_cb(object); // May not be a callback, but that's ok
|
|
|
|
|
delete vop;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) {
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
vlog_info_p->argc = Verilated::getCommandArgs()->argc;
|
|
|
|
|
vlog_info_p->argv = (PLI_BYTE8**)Verilated::getCommandArgs()->argv;
|
|
|
|
|
vlog_info_p->product = (PLI_BYTE8*)Verilated::productName();
|
|
|
|
|
vlog_info_p->version = (PLI_BYTE8*)Verilated::productVersion();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// routines added with 1364-2001
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_get_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
PLI_INT32 vpi_put_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
void *vpi_get_userdata(vpiHandle obj) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
PLI_INT32 vpi_put_userdata(vpiHandle obj, void *userdata) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
|
|
|
|
|
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_control %d\n",operation););
|
|
|
|
|
_VL_VPI_ERROR_RESET(); // reset vpi error status
|
|
|
|
|
switch (operation) {
|
|
|
|
|
case vpiFinish: {
|
|
|
|
|
vl_finish(__FILE__,__LINE__,"*VPI*");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
case vpiStop: {
|
|
|
|
|
vl_stop(__FILE__,__LINE__,"*VPI*");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring",
|
|
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiProp(operation));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle vpi_handle_by_multi_index(vpiHandle obj, PLI_INT32 num_index, PLI_INT32 *index_array) {
|
|
|
|
|
_VL_VPI_UNIMP(); return 0;
|
|
|
|
|
}
|