verilator/test_regress/t/t_flag_main_vpi.cpp

95 lines
3.1 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: VPI test library for t_flag_main_vpi
//
// Loaded at runtime via +verilator+vpi+<path> to verify that --binary --vpi
// correctly loads shared libraries and invokes vlog_startup_routines[] (or a
// named bootstrap). The design drives its own clock; this library only
// observes 'count' via a cbValueChange callback and calls $finish after
// MAX_TICKS edges -- so a successful $finish proves the library was loaded
// and is able to register callbacks and reach signals by name.
//
// 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-FileCopyrightText: 2025 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#include "vpi_user.h"
#include <cstdio>
#include <cstdlib>
// Number of count increments to observe before calling $finish
static const int MAX_TICKS = 10;
static vpiHandle s_count_handle = nullptr;
static PLI_INT32 count_change_cb(p_cb_data /*cb_data*/) {
if (!s_count_handle) return 0;
s_vpi_value val;
val.format = vpiIntVal;
vpi_get_value(s_count_handle, &val);
if (val.value.integer >= MAX_TICKS) {
vpi_printf(const_cast<char*>("*-* All Finished *-*\n"));
vpi_control(vpiFinish, 0);
}
return 0;
}
static PLI_INT32 start_of_sim_cb(p_cb_data /*cb_data*/) {
s_count_handle = vpi_handle_by_name(const_cast<char*>("t.count"), nullptr);
if (!s_count_handle) {
vpi_printf(const_cast<char*>("ERROR: cannot find t.count\n"));
vpi_control(vpiFinish, 1);
return 0;
}
// Observe count: fire a callback whenever it changes
t_cb_data cb_data;
s_vpi_time t;
s_vpi_value val;
t.type = vpiSuppressTime;
val.format = vpiSuppressVal;
cb_data.reason = cbValueChange;
cb_data.cb_rtn = count_change_cb;
cb_data.obj = s_count_handle;
cb_data.time = &t;
cb_data.value = &val;
cb_data.user_data = nullptr;
vpi_register_cb(&cb_data);
return 0;
}
static PLI_INT32 end_of_sim_cb(p_cb_data /*cb_data*/) {
vpi_printf(const_cast<char*>("VPI end of simulation\n"));
return 0;
}
static void register_callbacks() {
// cbStartOfSimulation
t_cb_data cb_data;
s_vpi_time t;
t.type = vpiSuppressTime;
cb_data.reason = cbStartOfSimulation;
cb_data.cb_rtn = start_of_sim_cb;
cb_data.obj = nullptr;
cb_data.time = &t;
cb_data.value = nullptr;
cb_data.user_data = nullptr;
vpi_register_cb(&cb_data);
// cbEndOfSimulation
cb_data.reason = cbEndOfSimulation;
cb_data.cb_rtn = end_of_sim_cb;
vpi_register_cb(&cb_data);
}
// IEEE 1800 section 37: vlog_startup_routines[] -- null-terminated array of startup functions
extern "C" {
void (*vlog_startup_routines[])() = {register_callbacks, nullptr};
// Named bootstrap entrypoint -- used when library is loaded as <path>:my_vpi_bootstrap
void my_vpi_bootstrap() { register_callbacks(); }
}