95 lines
3.1 KiB
C++
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(); }
|
|
}
|