Tests: Add uvm-2020-3.2-vlt

This commit is contained in:
Wilson Snyder 2026-08-14 18:31:23 -04:00
parent 92300ab675
commit 91216bdac1
28 changed files with 99650 additions and 22 deletions

View File

@ -13,6 +13,10 @@ contributors that suggested or implemented a given issue are shown in []. Thanks
Verilator 5.051 devel
==========================
**Important:**
* Verilator now supports UVM 2020-3.2; see (#1538) for limitations.
**Other:**
* Add comments as a branch description in coverage .info files (#7843). [Eryk Szpotanski]

View File

@ -1,33 +1,33 @@
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:25:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
25 | a + arr[0].sum() == 10;
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:23:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
23 | a + arr[0].sum() == 10;
| ^~~
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:26:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
26 | a + arr[1].product() == 10;
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:24:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
24 | a + arr[1].product() == 10;
| ^~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:27:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
27 | a + arr[2].xor() == 10;
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:25:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
25 | a + arr[2].xor() == 10;
| ^~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:28:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
28 | a + arr[3].or() == 10;
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:26:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
26 | a + arr[3].or() == 10;
| ^~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:29:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
29 | a + arr[4].and() == 10;
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:27:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
27 | a + arr[4].and() == 10;
| ^~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:31:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
31 | a + sc.arr.sum() == 10;
| ^~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:32:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
32 | a + sc.arr.product() == 10;
| ^~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:33:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
33 | a + sc.arr.sum() == 10;
33 | a + sc.arr.xor() == 10;
| ^~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:34:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
34 | a + sc.arr.product() == 10;
| ^~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:35:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
35 | a + sc.arr.xor() == 10;
| ^~~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:36:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
36 | a + sc.arr.or() == 10;
34 | a + sc.arr.or() == 10;
| ^~
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:37:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
37 | a + sc.arr.and() == 10;
%Warning-CONSTRAINTIGN: t/t_constraint_red_arr_unsup.v:35:16: Unsupported: Array reduction constraint on dynamic array inside array or struct
35 | a + sc.arr.and() == 10;
| ^~~
%Error: Exiting due to

View File

@ -14,6 +14,8 @@ test.scenarios('dist')
if not os.path.exists(test.root + "/.git"):
test.skip("Not in a git repository")
Exempt_Re = r'(test_regress/t/uvm/.*/dpi/uvm_hdl_xcelium.c)'
### Must trim output before and after our file list
files = test.run_capture("cd " + test.root + " && git ls-files --exclude-standard")
if test.verbose:
@ -24,6 +26,8 @@ files = re.sub(r'\s+', ' ', files)
regex = r'(FIX[M]E|BO[Z]O)'
for filename in files.split():
if re.search(Exempt_Re, filename):
continue
if re.search(regex, filename):
names[filename] = True
filename = os.path.join(test.root, filename)

View File

@ -5,6 +5,13 @@
// SPDX-License-Identifier: CC0-1.0
`ifdef T_V2020_3_1
`define T_NEED_REPORT_ERROR
`endif
`ifdef T_V2020_3_2
`define T_NEED_REPORT_ERROR
`endif
`ifdef T_NEED_REPORT_ERROR
function void uvm_report_error(string a, string b);
$display("uvm_report_error(\"%s\", \"%s\")", a, b);
endfunction

View File

@ -1,4 +1,4 @@
UVM Report t/t_uvm_dpi.v:74: id message
UVM Report t/t_uvm_dpi.v:81: id message
uvm_dpi_get_tool_name_c() = Verilator
= uvm_re
= uvm_hdl_check_path

View File

@ -1,4 +1,4 @@
UVM Report t/t_uvm_dpi.v:74: id message
UVM Report t/t_uvm_dpi.v:81: id message
uvm_dpi_get_tool_name_c() = Verilator
= uvm_re
= uvm_hdl_check_path

View File

@ -0,0 +1,136 @@
UVM Report t/t_uvm_dpi.v:81: id message
uvm_dpi_get_tool_name_c() = Verilator
= uvm_re
= uvm_hdl_check_path
= uvm_hdl_read simple variable
= uvm_hdl_deposit simple variable
= uvm_hdl_read single bit
= uvm_hdl_deposit single bit
= uvm_hdl_read multi-bit
= uvm_hdl_deposit multi-bit
= uvm_hdl_read/deposit wide decending
= uvm_hdl_read/deposit wide ascending
= uvm_hdl_read/deposit 1D memory
= uvm_hdl_read/deposit 2D memory
= uvm_hdl_read bad ranges
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET unable to locate hdl path (t.exposed[10:3])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET unable to locate hdl path (t.exposed[99:15])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_read empty name (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET NULL or empty HDL path passed to uvm_hdl_get_vlog
= uvm_hdl_read not found (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET unable to locate hdl path (t.__READ_NOT_FOUND)
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_read with indexed part-select (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET unable to locate hdl path (t.exposed[15+8:8])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_read from real (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET failed to get value for hdl path 't.realSignal'. Common reasons include a signal having an unsupported type, such as a real or a string
= uvm_hdl_read from string (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET failed to get value for hdl path 't.stringSignal'. Common reasons include a signal having an unsupported type, such as a real or a string
= uvm_hdl_read producing error message larger than print buffer (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET unable to locate hdl path (t.lorem_ipsum_dolor_sit_amet_consetetur_sadipscing_elitr_sed_diam_nonumy_eirmod_tempor_invidunt_ut_labore_et_dolore_magna_aliquyam_erat_sed_diam_voluptua_at_vero_eos_et_accusam_et_justo_duo_dolores_et_ea_rebum_stet_clita_kasd_gubergren_no_sea_takimata_sanctus_est_lorem_ipsum_dolor_sit_amet_lorem_ipsum_dolor_sit_amet_consetetur_sadipscing_elitr_sed_diam_nonumy_eirmod_tempor_invidunt_ut_labore_et_dolore_magna_aliquyam_erat_sed_diam_voluptua_at_vero_eos_et_accusam_et_justo_duo_dolores_et_ea_rebum_stet_clita_kasd_gubergren_no_sea_takimata_sanctus_est_lorem_ipsum_dolor_sit_amet_lorem_ipsum_dolor_sit_amet_consetetur_sadipscing_elitr_sed_diam_nonumy_eirmod_tempor_invidunt_ut_labore_et_dolore_magna_aliquyam_erat_sed_diam_voluptua_at_vero_eos_et_accusam_et_justo_duo_dolores_et_ea_rebum_stet_clita_kasd_gubergren_no_sea_takimata_sanctus_est_lorem_ipsum_dolor_sit_amet_duis_autem_vel_eum_iriure_dolor_in_hendrerit_in_vulputate_velit_esse_molestie_consequat_vel_illum_dolore_eu_feugiat_nulla_facil
= uvm_hdl_read from not exposed (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_GET unable to locate hdl path (t.not_exposed)
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_deposit bad ranges
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.exposed[10:3])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.exposed[99:15])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_deposit empty name (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT NULL or empty HDL path passed to uvm_hdl_set_vlog
= uvm_hdl_deposit not found (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.__DEPOSIT_NOT_FOUND)
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_deposit with indexed part-select (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.exposed[15+8:8])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_deposit to real (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT failed to set hdl path 't.realSignal'. Common reasons include a signal having an unsupported type, such as a real or a string, or attempting to force a signal that is not marked as /*verilator forceable*/
= uvm_hdl_deposit to string (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT failed to set hdl path 't.stringSignal'. Common reasons include a signal having an unsupported type, such as a real or a string, or attempting to force a signal that is not marked as /*verilator forceable*/
= Test uvm_hdl_deposit to signal wider than UVM_HDL_MAX_WIDTH (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT hdl path 't.tooWide' is 2048 bits, but the maximum size is 1024. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=<value>
= uvm_hdl_deposit to not exposed (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.not_exposed)
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_force
= uvm_hdl_release
= uvm_hdl_release_and_read
= uvm_hdl_force continuously assigned signal
= uvm_hdl_release continuously assigned signal
= uvm_hdl_release_and_read continuously assigned signal
= uvm_hdl_read partially forced signal
= uvm_hdl_release partially forced signal
= uvm_hdl_force multi-bit
= uvm_hdl_release_and_read partially forced signal
= uvm_hdl_force multi-bit continuously assigned signal
= uvm_hdl_release partially forced continuously assigned signal
= uvm_hdl_release_and_read partially forced continuously assigned signal
= uvm_hdl_force single bit
= uvm_hdl_release_and_read single bit
= uvm_hdl_force single bit on continuously assigned signal
= uvm_hdl_release_and_read single bit on continuously assigned signal
= uvm_hdl_release_and_read lower 16 bits only
= uvm_hdl_release upper 16 bits only of continuously assigned signal
= uvm_hdl_force to not exposed (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.not_exposed)
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_force with indexed part-select (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT set: unable to locate hdl path (t.exposed[15+8:8])
Either the name is incorrect, or you may not have PLI/ACC visibility to that name
= uvm_hdl_force to not forcable (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT failed to set hdl path 't.exposed_not_forceable'. Common reasons include a signal having an unsupported type, such as a real or a string, or attempting to force a signal that is not marked as /*verilator forceable*/
= uvm_hdl_force to real (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT failed to set hdl path 't.realSignal'. Common reasons include a signal having an unsupported type, such as a real or a string, or attempting to force a signal that is not marked as /*verilator forceable*/
= uvm_hdl_force to signal wider than UVM_HDL_MAX_WIDTH (bad)
===
UVM Report expected on next line:
UVM Report ../../t/uvm/v2020_3_2/dpi/uvm_hdl_verilator.c:54: UVM/DPI/VLOG_PUT hdl path 't.tooWide' is 2048 bits, but the maximum size is 1024. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=<value>
*-* All Finished *-*

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt')
test.top_filename = "t/t_uvm_dpi.v"
test.pli_filename = "t/uvm/v2020_3_2/dpi/uvm_dpi.cc"
if re.search(r'clang', test.cxx_version):
test.skip("uvm_regex.cc from upstream has clang warnings")
test.compile(verilator_flags2=[
"--binary",
test.build_jobs_groups,
"--vpi",
"+define+T_V2020_3_2",
"+incdir+t/uvm/v2020_3_2", #
test.pli_filename
])
test.execute(expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.priority(50)
test.scenarios('vlt')
test.top_filename = 't/t_uvm_hello.v'
test.pli_filename = "t/uvm/v2020_3_2/dpi/uvm_dpi.cc"
if test.have_dev_gcov:
test.skip("Test suite intended for full dev coverage without needing this test")
test.compile(v_flags2=[
"--binary",
test.build_jobs_groups,
"--vpi",
"--CFLAGS -O0",
"-Wall",
"+incdir+t/uvm", #
"t/uvm/uvm_pkg_all_v2020_3_2_dpi.svh",
test.pli_filename
])
test.execute(all_run_flags=['' if test.verbose else '+UVM_NO_RELNOTES'])
test.file_grep(test.run_log_filename, r'UVM TEST PASSED')
test.passes()

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.priority(50)
test.scenarios('vlt')
test.top_filename = 't/t_uvm_hello.v'
if test.have_dev_gcov:
test.skip("Test suite intended for full dev coverage without needing this test")
test.compile(v_flags2=[
"--binary",
test.build_jobs_groups,
"--CFLAGS -O0",
"-Wall",
"+incdir+t/uvm", #
"t/uvm/uvm_pkg_all_v2020_3_2_nodpi.svh",
])
test.execute(all_run_flags=['' if test.verbose else '+UVM_NO_RELNOTES'])
test.file_grep(test.run_log_filename, r'UVM TEST PASSED')
test.passes()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
//----------------------------------------------------------------------
// Copyright 2010 AMD
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2010-2011 Mentor Graphics Corporation
// Copyright 2013-2024 NVIDIA Corporation
// Copyright 2010-2013 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_common.c $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
// Implementation of common methods for DPI
extern void m__uvm_report_dpi(int,const char*,const char*,int,const char*, int);
#if defined(XCELIUM) || defined(NCSC)
const static char* uvm_package_scope_name = "uvm_pkg::";
#else
const static char* uvm_package_scope_name = "uvm_pkg";
#endif
void m_uvm_report_dpi( int severity,
char* id,
char* message,
int verbosity,
char* file,
int linenum) {
svScope old_scope = svSetScope(svGetScopeFromName(uvm_package_scope_name));
m__uvm_report_dpi(severity, id, message, verbosity, file, linenum);
svSetScope(old_scope);
}
int int_str_max ( int radix_bits ) {
int val = INT_MAX;
int ret = 1;
while ((val = (val /radix_bits)))
ret++;
return ret;
}

View File

@ -0,0 +1,80 @@
//----------------------------------------------------------------------
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2023 Intel Corporation
// Copyright 2010-2017 Mentor Graphics Corporation
// Copyright 2013-2024 NVIDIA Corporation
// Copyright 2010-2013 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_dpi.cc $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
//
// Top-level file that includes all of the C/C++ files required
// by UVM
//
// The C code may be compiled by compiling this top file only,
// or by compiling individual files then linking them together.
//
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "uvm_dpi.h"
// Avoid -Wmissing-definitions
int uvm_hdl_check_path(char *path);
int uvm_hdl_read(char *path, p_vpi_vecval value);
int uvm_hdl_deposit(char *path, p_vpi_vecval value);
int uvm_hdl_force(char *path, p_vpi_vecval value);
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value);
int uvm_hdl_release(char *path);
void push_data(int lvl,char *entry, int cmd);
void walk_level(int lvl, int argc, char**argv,int cmd);
const char *uvm_dpi_get_next_arg_c (int init);
extern char* uvm_dpi_get_tool_name_c ();
extern char* uvm_dpi_get_tool_version_c ();
extern char* uvm_re_buffer();
extern const char* uvm_re_deglobbed(const char *glob, unsigned char with_brackets);
extern void uvm_re_free(regex_t* handle);
extern regex_t* uvm_re_comp(const char* re, unsigned char deglob);
extern int uvm_re_exec(regex_t* rexp, const char *str);
extern regex_t* uvm_re_compexec(const char* re, const char* str, unsigned char deglob, int* exec_ret);
#include "uvm_common.c"
#include "uvm_regex.cc"
#include "uvm_hdl.c"
#include "uvm_svcmd_dpi.c"
//#ifdef UVM_PLI_POLLING_ENABLE
#include "uvm_hdl_polling.c"
//#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,99 @@
//----------------------------------------------------------------------
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2026 Marvell International Ltd.
// Copyright 2010-2017 Mentor Graphics Corporation
// Copyright 2013-2026 NVIDIA Corporation
// Copyright 2010 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_dpi.h $
// $Rev: 2026-05-08 07:53:24 -0700 $
// $Hash: b79027c3a6650c9072fd2772cb849c270ae4cc85 $
//
//----------------------------------------------------------------------
//
// Top level header filke that wraps all requirements which
// are common to the various C/C++ files in UVM.
//
#ifndef UVM_DPI__H
#define UVM_DPI__H
#include <stdlib.h>
#include "vpi_user.h"
#include "veriuser.h"
#include "svdpi.h"
#ifndef UVM_NO_MALLOC
#include <malloc.h>
#endif
#include <string.h>
#include <stdio.h>
#include <regex.h>
#include <limits.h>
// The following consts and method call are for
// internal usage by the UVM DPI implementation,
// and are not intended for public use.
static const int M_UVM_INFO = 0;
static const int M_UVM_WARNING = 1;
static const int M_UVM_ERROR = 2;
static const int M_UVM_FATAL = 3;
static const int M_UVM_NONE = 0;
static const int M_UVM_LOW = 100;
static const int M_UVM_MEDIUM = 200;
static const int M_UVM_HIGH = 300;
static const int M_UVM_FULL = 400;
static const int M_UVM_DEBUG = 500;
void m_uvm_report_dpi(int severity,
char* id,
char* message,
int verbosity,
char* file,
int linenum);
int int_str_max( int );
char * uvm_re_buffer();
const char * uvm_re_deglobbed(const char *glob, unsigned char with_brackets);
void uvm_re_free(regex_t* handle);
regex_t* uvm_re_comp(const char *re, unsigned char deglob);
int uvm_re_exec(regex_t* rexp, const char *str);
regex_t* uvm_re_compexec(const char *re, const char *str, unsigned char deglob, int* exec_ret);
int uvm_hdl_check_path(char *path);
int uvm_hdl_read(char *path, p_vpi_vecval value);
int uvm_hdl_deposit(char *path, p_vpi_vecval value);
int uvm_hdl_force(char *path, p_vpi_vecval value);
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value);
int uvm_hdl_release(char *path);
void push_data(int lvl,char *entry, int cmd);
void walk_level(int lvl, int argc, char**argv,int cmd);
const char *uvm_dpi_get_next_arg_c (int init);
extern char* uvm_dpi_get_tool_name_c ();
extern char* uvm_dpi_get_tool_version_c ();
#endif

View File

@ -0,0 +1,60 @@
//----------------------------------------------------------------------
// Copyright 2010 AMD
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2023 Intel Corporation
// Copyright 2010-2011 Mentor Graphics Corporation
// Copyright 2020-2024 NVIDIA Corporation
// Copyright 2010 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_dpi.svh $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
`ifndef UVM_DPI_SVH
`define UVM_DPI_SVH
//
// Top-level file for DPI subroutines used by UVM.
//
// Tool-specific distribution overlays may be required.
//
// To use UVM without any tool-specific overlay, use +defin+UVM_NO_DPI
//
`ifdef UVM_NO_DPI
`define UVM_HDL_NO_DPI
`define UVM_REGEX_NO_DPI
`define UVM_CMDLINE_NO_DPI
`endif
`include "dpi/uvm_hdl.svh"
`include "dpi/uvm_svcmd_dpi.svh"
`include "dpi/uvm_regex.svh"
`ifdef UVM_PLI_POLLING_ENABLE
`include "dpi/uvm_polling_dpi.svh"
`endif
`endif // UVM_DPI_SVH

View File

@ -0,0 +1,51 @@
//----------------------------------------------------------------------
// Copyright 2007-2018 Cadence Design Systems, Inc.
// Copyright 2026 Marvell International Ltd.
// Copyright 2009-2011 Mentor Graphics Corporation
// Copyright 2013-2026 NVIDIA Corporation
// Copyright 2010-2011 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_hdl.c $
// $Rev: 2026-05-08 07:53:24 -0700 $
// $Hash: b79027c3a6650c9072fd2772cb849c270ae4cc85 $
//
//----------------------------------------------------------------------
// hdl vendor backends are defined for VCS,QUESTA,VERILATOR,XCELIUM
#if defined(VCS) || defined(VCSMX)
#include "uvm_hdl_vcs.c"
#else
#ifdef QUESTA
#include "uvm_hdl_questa.c"
#else
#ifdef VERILATOR
#include "uvm_hdl_verilator.c"
#else
#if defined(XCELIUM) || defined(NCSC)
#include "uvm_hdl_xcelium.c"
#else
#error "hdl vendor backend is missing"
#endif
#endif
#endif
#endif

View File

@ -0,0 +1,183 @@
//----------------------------------------------------------------------
// Copyright 2012 Accellera Systems Initiative
// Copyright 2015 Analog Devices, Inc.
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2014 Cisco Systems, Inc.
// Copyright 2022-2023 Intel Corporation
// Copyright 2007-2011 Mentor Graphics Corporation
// Copyright 2014-2024 NVIDIA Corporation
// Copyright 2010 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_hdl.svh $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
// TITLE -- NODOCS -- UVM HDL Backdoor Access support routines.
//
// These routines provide an interface to the DPI/PLI
// implementation of backdoor access used by registers.
//
// If you DON'T want to use the DPI HDL API, then compile your
// SystemVerilog code with the vlog switch
//: vlog ... +define+UVM_HDL_NO_DPI ...
//
`ifndef UVM_HDL__SVH
`define UVM_HDL__SVH
`ifndef UVM_HDL_MAX_WIDTH
`define UVM_HDL_MAX_WIDTH 1024
`endif
/*
* VARIABLE -- NODOCS -- UVM_HDL_MAX_WIDTH
* Sets the maximum size bit vector for backdoor access.
* This parameter will be looked up by the
* DPI-C code using:
* vpi_handle_by_name(
* "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
*/
// @uvm-ieee 1800.2-2020 manual 19.6.1
parameter int UVM_HDL_MAX_WIDTH = `UVM_HDL_MAX_WIDTH;
typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t;
`ifndef UVM_HDL_NO_DPI
// Function -- NODOCS -- uvm_hdl_check_path
//
// Checks that the given HDL ~path~ exists. Returns 0 if NOT found, 1 otherwise.
//
import "DPI-C" context function int uvm_hdl_check_path(string path);
// Function -- NODOCS -- uvm_hdl_deposit
//
// Sets the given HDL ~path~ to the specified ~value~.
// Returns 1 if the call succeeded, 0 otherwise.
//
import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
// Function -- NODOCS -- uvm_hdl_force
//
// Forces the ~value~ on the given ~path~. Returns 1 if the call succeeded, 0 otherwise.
//
import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value);
// Function -- NODOCS -- uvm_hdl_force_time
//
// Forces the ~value~ on the given ~path~ for the specified amount of ~force_time~.
// If ~force_time~ is 0, <uvm_hdl_deposit> is called.
// Returns 1 if the call succeeded, 0 otherwise.
//
task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0);
if (force_time == 0) begin
void'(uvm_hdl_deposit(path, value));
return;
end
if (!uvm_hdl_force(path, value)) begin
return;
end
#force_time;
void'(uvm_hdl_release_and_read(path, value));
endtask
// Function -- NODOCS -- uvm_hdl_release_and_read
//
// Releases a value previously set with <uvm_hdl_force>.
// Returns 1 if the call succeeded, 0 otherwise. ~value~ is set to
// the HDL value after the release. For 'reg', the value will still be
// the forced value until it has been procedurally reassigned. For 'wire',
// the value will change immediately to the resolved value of its
// continuous drivers, if any. If none, its value remains as forced until
// the next direct assignment.
//
import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value);
// Function -- NODOCS -- uvm_hdl_release
//
// Releases a value previously set with <uvm_hdl_force>.
// Returns 1 if the call succeeded, 0 otherwise.
//
import "DPI-C" context function int uvm_hdl_release(string path);
// Function -- NODOCS -- uvm_hdl_read()
//
// Gets the value at the given ~path~.
// Returns 1 if the call succeeded, 0 otherwise.
//
import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
`else
function int uvm_hdl_check_path(string path);
uvm_report_fatal("UVM_HDL_CHECK_PATH",
$sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
return 0;
endfunction
function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
uvm_report_fatal("UVM_HDL_DEPOSIT",
$sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
return 0;
endfunction
function int uvm_hdl_force(string path, uvm_hdl_data_t value);
uvm_report_fatal("UVM_HDL_FORCE",
$sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
return 0;
endfunction
task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time=0);
uvm_report_fatal("UVM_HDL_FORCE_TIME",
$sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
endtask
function int uvm_hdl_release(string path);
uvm_report_fatal("UVM_HDL_RELEASE",
$sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
return 0;
endfunction
function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
uvm_report_fatal("UVM_HDL_READ",
$sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
return 0;
endfunction
`endif
`endif

View File

@ -0,0 +1,679 @@
//----------------------------------------------------------------------
// Copyright 2023-2024 Intel Corporation
// Copyright 2025 Marvell International Ltd.
// Copyright 2023-2026 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_hdl_polling.c $
// $Rev: 2026-05-08 07:53:24 -0700 $
// $Hash: b79027c3a6650c9072fd2772cb849c270ae4cc85 $
//
//----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sv_vpi_user.h"
#include "svdpi.h"
#include "uvm_dpi.h"
// Everyone still supports deprecated function vpi_free_object,
// but VCS doesn't yet support vpi_release_handle, which supersedes it
#define vpi_release_handle vpi_free_object
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------------
// DPI import and export prototypes
//--------------------------------------------------------------------------
// DPI import ____ uvm_polling_create
//
// Create an access hook on the signal whose absolute pathname is ~name~.
// Use ~sv_key~ as the key shared between SV and C that will be used as
// the unique identifier for the created probe object.
// This function returns a pointer to a hook_record structure (see
// below), which is returned from C as void* and passed to SV as
// a "chandle". It should be saved for use in future operations
// on this signal. In practice the SV code will do this by maintaining
// an array of chandle indexed by their unique sv_key.
// An access hook freshly created by this function has no properties,
// i.e. it does nothing. To make the access hook useful, it must be
// enabled by a suitable call to uvm_polling_set_enable_callback (see below).
//
extern void * uvm_polling_create(char * name, int sv_key);
// DPI import ____ uvm_polling_set_enable_callback
//
// Enable or disable value-changed callback on the signal referenced
// by p_hook_record ~hnd~. If ~enable~ is true (non-zero), value-change
// monitoring is enabled for the signal. If ~enable~ is false (zero),
// it is disabled. If monitoring is already enabled and this function
// is called with ~enable~ true, the function has no effect. Similarly,
// if monitoring is disabled and the function is called with ~enable~
// false, it has no effect.
//
extern void uvm_polling_set_enable_callback(void * hnd, int enable);
// DPI import ____ uvm_polling_get_callback_enable
//
// Find the current enabled/disabled state of value-change callback
// on the signal accessed by the hook record referenced by ~hnd~.
// Returns 0 (disabled) or 1 (enabled).
//
extern int uvm_polling_get_callback_enable(void * hnd);
// DPI import ____ uvm_polling_getValue32
//
// Get the current value of the signal referenced by ~hnd~.
// The result is placed into the vector ~result~,
// which must be a 32-bit logic or equivalent type.
// ~chunk~ indicates which 32-bit slice of the signal
// is to be read: chunk=0 gets the least significant 32 bits,
// chunk=1 gets bits [63:32], and in general the function
// reads bits [32*chunk+:32]. If the specified chunk is completely
// beyond the end of the vector (i.e. the signal's size is less than
// 32*chunk bits) then the function yields an error. If the signal
// does not completely fill the chunk (for example, a 48-bit signal
// and chunk=1) then the result is zero-extended if the signal is
// unsigned, and sign-extended in the standard Verilog 4-state way
// if the signal is signed.
// Returns 1 if success, 0 if failure (bad handle, chunk out-of-bounds).
//
extern int uvm_polling_getValue32(void * hnd, svLogicVecVal *result, int chunk);
// DPI import _______________________________________ uvm_polling_getSize
//
// Get the number of bits in the signal referenced by ~hnd~.
// Returns zero if the handle is bad.
//
extern int uvm_polling_getSize(void * hnd);
// DPI import _____________________________________ uvm_polling_getSigned
//
// Get a flag indicating whether the signal referenced by ~hnd~
// is signed (0=unsigned, 1=signed).
//
extern int uvm_polling_getSigned(void * hnd); // 1=signed, 0=unsigned
// DPI import _______________________________ uvm_polling_setup_notifier
//
// Here's how we get the value change information back in to SV.
// First we pass the name of a single-bit signal to this function.
// That signal will be toggled by the VPI whenever it requires
// attention from SV because one of the probed signals has changed.
//
extern int uvm_polling_setup_notifier(char * fullname);
// DPI import ____ uvm_polling_process_changelist
//
// When the SV notifier signal is toggled, the SV code must immediately
// call this function. It will service all pending value-change events,
// notifying each affected probe object in turn by calling exported
// function uvm_polling_value_change_notify for that signal.
//
extern void uvm_polling_process_changelist();
// DPI export ____ uvm_polling_value_change_notify
//
// uvm_polling_process_changelist() calls this DPI export function
// once for each probed signal that has a pending value-change event.
// It uses a unique int key, rather than the signal's vpi_handle
// reference, to work around a tool limitation (no associative array
// indexed by chandle).
//
extern void uvm_polling_value_change_notify(int sv_key);
//-----------------------------------------------------------------------------
// Typedefs and private data used by the C functions
//-----------------------------------------------------------------------------
// The following struct is used to hold information about a
// probed signal. Various features of the signal are cached
// here, to avoid making repeated VPI accesses to discover this
// information. The structure sometimes appears on a linked list
// of signals that need to be serviced (the changeList), and
// struct members to support that linked list are also included.
//
typedef struct t_hook_record {
struct t_hook_record *allHooks_link; // linked list pointer - all records
struct t_hook_record *changeList_link; // linked list pointer - records awaiting processing
int on_changeList; // 1 if we're on the list, 0 if not
struct t_hook_record *check; // copy of self-pointer, for safety
vpiHandle obj; // reference to the monitored signal
int sv_key; // unique key to help SV find this
vpiHandle cb; // VPI value-change callback object
int size; // number of bits in the signal
int isSigned; // is the signal signed?
PLI_UINT32 top_mask; // word-mask for most significant 32 bits
PLI_UINT32 top_msb; // MSB position within that word
} s_hook_record, *p_hook_record;
// A single list of hook_records that have value changes yet to be handled
static p_hook_record changeList = NULL;
// A single list of all hook_records, for use when deallocating memory
static p_hook_record allHooks = NULL;
// VPI handle to the single bit that is toggled to notify SV of pending
// value-changes that require service
static vpiHandle notifier = NULL;
// VPI handle to the simulation reset callback
static vpiHandle reset_callback = NULL;
//-----------------------------------------------------------------------------
// Static (file-local) helper functions
//-----------------------------------------------------------------------------
// Report an error in a consistent way. This function should be used when
// control will be returned to SV with an error indication; the SV code will
// then display a more comprehensive error diagnostic.
//
static void uvm_polling_report_error(const char *message) {
m_uvm_report_dpi(M_UVM_ERROR,
(char*) "UVM/DPI/HDL_POLLING",
(char*) message,
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
}
static void uvm_polling_report_fatal(const char *message) {
m_uvm_report_dpi(M_UVM_FATAL,
(char*) "UVM/DPI/HDL_POLLING",
(char*) message,
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
}
static void uvm_polling_report_info(const char *message) {
m_uvm_report_dpi(M_UVM_INFO,
(char*) "UVM/DPI/HDL_POLLING",
(char*) message,
M_UVM_MEDIUM,
(char*)__FILE__,
__LINE__);
}
// Interrupt the simulation because of an error.
// After an error, a user can continue from the stop using
// simulator command-line functionality. This may help with
// debugging by providing additional trace information, but
// behaviour of the signal probe package is not guaranteed
// after any error.
//
static void uvm_polling_stop_on_error(const char *message) {
if (message != NULL) {
uvm_polling_report_fatal(message);
}
// vpi_control(vpiStop, 1);
}
// Get and initialize a new s_hook_record from the heap.
// Add it to the allHooks structure to support memory
// deallocation on simulator restart.
//
static p_hook_record allocate_hook_record() {
p_hook_record rec = (p_hook_record)malloc(sizeof(s_hook_record));
if (rec == NULL) {
uvm_polling_stop_on_error("allocate_hook_record: no memory");
} else {
rec->on_changeList = 0;
rec->check = rec;
rec->obj = NULL;
rec->allHooks_link = allHooks;
allHooks = rec;
}
return rec;
}
// Deallocate a single hook_record structure.
// Destroy its internal referenced VPI objects before deallocation.
//
static void free_hook_record(p_hook_record rec) {
if (rec == NULL) return;
if (rec->cb != NULL) {
(void)vpi_remove_cb(rec->cb);
}
if (rec->obj != NULL) {
(void)vpi_release_handle(rec->obj);
}
free(rec);
}
// Deallocate all memory structures owned by this VPI application.
// This will typically be done by the VPI simulation restart callback.
// NOTE that the restart callback itself is NOT deallocated here,
// because this function is probably called from within that callback.
//
static void uvm_polling_free_mem_structures() {
if (notifier != NULL) {
(void)vpi_release_handle(notifier);
}
while (allHooks != NULL) {
p_hook_record rec = allHooks;
allHooks = rec->allHooks_link;
free_hook_record(rec);
}
}
// Get and remove the first (newest) entry from the
// list of signals with unserviced value changes.
// Return a reference to that entry.
//
static p_hook_record uvm_polling_get_newest_entry() {
p_hook_record rec;
rec = changeList;
if (rec != NULL) {
changeList = rec->changeList_link;
rec->on_changeList = 0;
}
return rec;
}
// Add a signal to the list of unserviced value changes.
// But if the signal is already on that list, don't
// try to add it again.
//
static void changeList_pushIfNeeded(p_hook_record rec) {
if (!rec->on_changeList) {
rec->on_changeList = 1;
rec->changeList_link = changeList;
changeList = rec;
}
}
// Check to see whether a vpiType value represents
// an appropriate Verilog type (vector, reg etc) for probing.
// Basically we are checking for an integral type, but
// there does not seem to be any VPI property for that,
// so instead we must exhaustively list all known
// integral types.
//
static int isVerilogType(PLI_INT32 vpi_type) {
switch (vpi_type) {
case vpiNet:
case vpiNetBit:
case vpiReg:
case vpiRegBit:
case vpiPartSelect:
case vpiBitSelect:
case vpiBitVar:
case vpiEnumVar:
case vpiIntVar:
case vpiLongIntVar:
case vpiShortIntVar:
case vpiIntegerVar:
case vpiByteVar:
return 1;
default:
return 0;
}
}
// Given a handle value obtained from an untrusted source,
// cast it to a p_hook_record and do some sanity checks.
//
static p_hook_record chandle_to_hook(void * hnd) {
p_hook_record hook = (p_hook_record) hnd;
if ((hook != NULL) && (hook->check == hook)) {
return hook;
} else {
uvm_polling_stop_on_error("Bad chandle argument is not a valid created hook");
return NULL;
}
}
//-----------------------------------------------------------------------------
// Static (file-local) helper functions related to simulator action callbacks
//-----------------------------------------------------------------------------
// The callback function used to deal with simulator actions.
// Currently it handles only cbStartOfReset, which is caused by
// an interactive restart of the simulation back to time zero.
static PLI_INT32 uvm_polling_simulator_callback(p_cb_data cb_data_p) {
const char* str = "uvm_polling_simulator_callback: cbStartOfReset, deallocate all internal data\n\n";
char buffer[strlen(str) + 1];
switch (cb_data_p->reason) {
case cbStartOfReset :
uvm_polling_report_info(&buffer[0]);
uvm_polling_free_mem_structures();
break;
}
return 1;
}
// Set up reset/restart callbacks, removing any old callback if necessary
static void uvm_polling_reset_callback() {
s_cb_data cb_data;
// Time and value structs should not be needed, but IUS requires them
s_vpi_time time_s;
s_vpi_value value_s;
// Remove any existing callback
if (reset_callback != NULL) {
(void)vpi_remove_cb(reset_callback);
}
// Set up the new callback
cb_data.cb_rtn = &uvm_polling_simulator_callback;
cb_data.obj = NULL;
cb_data.user_data = NULL;
cb_data.time = &time_s;
time_s.type = vpiSuppressTime;
cb_data.value = &value_s;
value_s.format = vpiSuppressVal;
cb_data.reason = cbStartOfReset;
reset_callback = vpi_register_cb(&cb_data);
}
//-----------------------------------------------------------------------------
// Static (file-local) helper functions related to value-change callbacks
//-----------------------------------------------------------------------------
// Toggle the notifier signal
static PLI_INT32 uvm_polling_toggle_notifier() {
if (notifier == NULL) {
// Throw an error and return FALSE if there's no notifier set up.
uvm_polling_stop_on_error("Value-change callback but no active notifier bit");
return 0;
} else {
s_vpi_value value_s;
value_s.format = vpiScalarVal;
vpi_get_value(notifier, &value_s);
value_s.value.scalar = (value_s.value.scalar == vpi1)? vpi0: vpi1;
vpi_put_value(notifier, &value_s, NULL, vpiNoDelay);
return 1;
}
}
// This is the function that is provided to the VPI as a value-change callback
// handler. There is only one entry point. Each callback's user_data field
// holds a pointer to the corrresponding signal's hook_record structure.
//
static PLI_INT32 uvm_polling_value_change_callback(p_cb_data cb_data) {
p_hook_record hook = chandle_to_hook(cb_data->user_data);
if (hook == NULL) return 0;
// At any given time, the first signal that suffers a
// value-change callback will cause the notifier signal
// to be toggled. Subsequent callbacks don't toggle the
// notifier again, as that might prevent it from being
// detected by SV "@notifier". Instead, they are just
// added to the changeList. When SV eventually responds
// to the notifier change, it causes the changeList to be
// scanned, servicing each signal in turn and emptying
// the changeList. The next value change will then
// give rise to another notification. This mechanism
// avoids any risk of races whereby a notification might
// be missed.
// We detect "first signal" by noting whether
// the changeList is currently empty.
int require_notification = (changeList == NULL);
// Put this object on the changeList, if it isn't already.
changeList_pushIfNeeded(hook);
if (require_notification) {
// Toggle the notifier bit.
int ok = uvm_polling_toggle_notifier();
return ok;
} else {
return 1;
}
}
// Sensitise to a signal by placing a value-change callback on it.
// Set up the callback so that it does not collect the signal's
// value or the callback time (reduces overhead). Keep a copy
// of the callback handle in the signal's hook record, to simplify
// later removal of the callback.
//
static void enable_cb(p_hook_record hook) {
if (hook->cb == NULL) {
s_cb_data cb_data;
s_vpi_time time_s;
s_vpi_value value_s;
cb_data.reason = cbValueChange;
cb_data.cb_rtn = &uvm_polling_value_change_callback;
cb_data.obj = hook->obj;
cb_data.time = &time_s;
time_s.type = vpiSuppressTime;
cb_data.value = &value_s;
value_s.format = vpiSuppressVal;
cb_data.user_data = (PLI_BYTE8*)hook;
hook->cb = vpi_register_cb(&cb_data);
}
}
// Disable value-change callbacks on a signal by removing
// its value-change callback completely.
//
static void disable_cb(p_hook_record hook) {
if (hook->cb != NULL) {
(void) vpi_remove_cb(hook->cb);
hook->cb = NULL;
}
}
//-----------------------------------------------------------------------------
// SV DPI import implementations
//----------------------------------------------------------------------------
void * uvm_polling_create(char *name, int sv_key) {
vpiHandle obj;
p_hook_record rec;
int objType;
const char* str1 = "Unable to create probe on '%s' with key %d, type=%d\n" ;
const char* str2 = "uvm_hdl_polling_create(\"%s\"): object is not a variable or net of integral type\n";
char buffer0[strlen(str1) + strlen(name) + 32];
char buffer1[strlen(str2) + strlen(name) + 32];
// Locate the chosen object
obj = vpi_handle_by_name(name, NULL);
// If there was a problem, return NULL to report it.
if (obj == NULL) {
const char* str = "uvm_polling_create: create(\"%s\") could not locate requested signal\n";
char buffer[strlen(str) + strlen(name)];
sprintf(buffer,str,name);
uvm_polling_report_info(&buffer[0]);
return NULL;
}
// Check the object is indeed a vector variable or net; error if not.
objType = vpi_get(vpiType, obj);
if (!isVerilogType(objType)) {
sprintf(buffer0, str1, name, sv_key, objType);
sprintf(buffer1, str2, name);
uvm_polling_report_info(&buffer0[0]);
uvm_polling_report_info(&buffer1[0]);
return NULL;
}
// Obtain a clean object record from free memory
rec = allocate_hook_record();
// Populate it
rec->obj = obj;
rec->isSigned = vpi_get(vpiSigned, obj);
rec->size = vpi_get(vpiSize, obj);
rec->sv_key = sv_key;
rec->cb = NULL;
rec->top_msb = 1U << ((rec->size-1) % 32);
rec->top_mask = 2U * rec->top_msb - 1U;
return (void *)rec;
}
// Enable or disable value-change callback on the chosen signal.
//
void uvm_polling_set_enable_callback(void * hnd, int enable) {
p_hook_record hook = chandle_to_hook(hnd);
if (hook == NULL) return;
if (enable) {
enable_cb(hook);
} else {
disable_cb(hook);
}
}
// Enquiry: is value-change callback enabled on the chosen signal?
//
int uvm_polling_get_callback_enable(void * hnd) {
p_hook_record hook = chandle_to_hook(hnd);
if (hook == NULL) return 0;
return (hook->cb != NULL);
}
// Get up to 32 bits of the signal's value.
//
int uvm_polling_getValue32(void * hnd, svLogicVecVal *result, int chunk) {
p_hook_record hook;
s_vpi_value value_s;
p_vpi_vecval vec_p;
int chunk_lsb = chunk*32;
hook = chandle_to_hook(hnd);
if (hook == NULL) {
uvm_polling_stop_on_error("uvm_polling_getValue32: bad handle");
return 0;
}
if (chunk<0) {
uvm_polling_report_error("uvm_polling_getValue32: negative chunk index");
return 0;
}
if (chunk_lsb >= hook->size) {
chunk = (hook->size-1)/32;
}
// Get the whole vector value from VPI
value_s.format = vpiVectorVal;
vpi_get_value(hook->obj, &value_s);
// Copy the relevant aval/bval bits into the output argument.
vec_p = value_s.value.vector;
*result = vec_p[chunk];
// Perform sign extension if appropriate.
if ((chunk_lsb + 32) > hook->size) {
// We're working on the most significant word, and it is not full.
result->aval &= hook->top_mask;
result->bval &= hook->top_mask;
if (hook->isSigned) {
if (result->bval & hook->top_msb) {
result->bval |= ~(hook->top_mask);
}
if (result->aval & hook->top_msb) {
result->aval |= ~(hook->top_mask);
}
}
}
return 1;
}
int uvm_polling_getSize(void * hnd) {
p_hook_record hook = chandle_to_hook(hnd);
if (hook == NULL) return 0;
return hook->size;
}
int uvm_polling_getSigned(void * hnd) {
p_hook_record hook = chandle_to_hook(hnd);
if (hook == NULL) return 0;
return hook->isSigned;
}
// This function must be called exactly once when the very first probe is created.
int uvm_polling_setup_notifier(char * fullname) {
vpiHandle obj;
// Locate the chosen notifier signal
obj = vpi_handle_by_name(fullname, NULL);
// If there was a problem, return NULL to report it.
if (obj == NULL) {
uvm_polling_report_error("uvm_polling_setup_notifier() could not locate requested signal");
return 0;
}
// Check the object is indeed a variable of type bit; error if not.
if (vpi_get(vpiType, obj) != vpiBitVar) {
uvm_polling_report_error("uvm_polling_setup_notifier: object is not a bit variable");
return 0;
}
notifier = obj;
uvm_polling_reset_callback();
return 1;
}
// Walk the changeList, calling back to SV to handle each item in turn
// as they are popped off the list. When done, the list will be empty.
void uvm_polling_process_changelist() {
while (changeList != NULL) {
p_hook_record rec = uvm_polling_get_newest_entry();
uvm_polling_value_change_notify(rec->sv_key);
}
}
unsigned int uvm_hdl_signal_size(char* name)
{
const char* str = "uvm_hdl_signal_size : Cannot find name '%s'" ;
char buffer[strlen(str) + strlen(name)];
vpiHandle handle = vpi_handle_by_name(name, NULL);
if (handle != NULL) {
return vpi_get(vpiSize, handle);
} else {
uvm_polling_report_error(&buffer[0]);
return 0;
}
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,955 @@
//----------------------------------------------------------------------
// Copyright 2007-2018 Cadence Design Systems, Inc.
// Copyright 2009-2023 Mentor Graphics Corporation
// Copyright 2013-2024 NVIDIA Corporation
// Copyright 2010-2011 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_hdl_questa.c $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
#include "uvm_dpi.h"
/*
* UVM HDL access C code.
*
*/
/*
* This C code checks to see if there is PLI handle
* with a value set to define the maximum bit width.
*
* If no such variable is found, then the default
* width of 1024 is used.
*
* This function should only get called once or twice,
* its return value is cached in the caller.
*
*/
static int uvm_hdl_max_width()
{
vpiHandle ms;
s_vpi_value value_s = { vpiIntVal, { 0 } };
ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
if(ms == 0)
return 1024; /* If nothing else is defined,
this is the DEFAULT */
vpi_get_value(ms, &value_s);
return value_s.value.integer;
}
// Required to give VHDL back-door access via the FLI
#include <mti.h>
#define MTI_RELEASE_SIGNAL ((mtiForceTypeT)(-1))
/*
* FUNCTION -- NODOCS -- uvm_is_vhdl_path
*
* Given a string path, use the FLI to find the named signal.
* Strip off any bit select applied to a vector
*
*/
int uvm_is_vhdl_path(char *path) {
char *path_ptr = path;
int path_len;
mtiSignalIdT signal_id;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if (*path_ptr != ']') {
signal_id = mti_FindSignal(path);
} else {
while(path_ptr != path && *path_ptr != '[') {
path_ptr--;
path_len--;
}
if(path == path_ptr) {
return 0; // Something strange about string
}
if(*path_ptr == '[') {
path_len--;
}
char path_copy[path_len+1];
int i;
for(i = 0; i < path_len; i++) {
path_copy[i] = path[i];
}
path_copy[path_len]='\0';
signal_id = mti_FindSignal(path_copy);
}
if (signal_id) {
return 1;
} else {
return 0;
}
}
/*
* FUNCTION -- NODOCS -- string_to_vecval
*
* Given a string, and the number of bits,
* set the Verilog aval/bval in 'value'.
*
* The string will contain 'nbits' characters, either
* '0', '1', 'x' or 'z'.
*
*/
void
string_to_vecval(char *s, int nbits, p_vpi_vecval value)
{
char *p;
int j, k;
int bits_assigned;
int chunks;
int abit, bbit;
char c;
p = s;
chunks = (nbits-1)/32 + 1;
bits_assigned = 0;
for(j=0;j<chunks; ++j) {
value[j].aval = 0;
value[j].bval = 0;
for(k=0;k<32;k++) {
c = *p++;
if (c == '1') { abit = 1; bbit = 0; }
else if (c == '0') { abit = 0; bbit = 0; }
else if (c == 'x') { abit = 1; bbit = 1; }
else if (c == 'z') { abit = 0; bbit = 1; }
else { abit = 0; bbit = 0; }
value[j].aval = value[j].aval << 1;
value[j].bval = value[j].bval << 1;
value[j].aval |= abit;
value[j].bval |= bbit;
if (++bits_assigned >= nbits)
break;
}
}
}
/*
* FUNCTION -- NODOCS -- vecval_to_string
*
* Given a vecval (logic verilog type), return
* a string representation. The returned
* string will contain 'nbits' characters, either
* '0', '1', 'x' or 'z'.
*
* For example:
* vecval_to_string(8, 8'b0000_0001)
* vecval_to_string(8, 8'b0000_00x1)
*
* returns:
* "00000001"
* "000000x1"
*/
char *
vecval_to_string(int nbits, p_vpi_vecval value)
{
static char *string_buffer = 0;
static int string_buffer_size = 16;
char *p;
int j, k;
int bits_assigned;
int chunks;
int abit, bbit;
char c;
/* First time, or nbits is really big. */
if ((string_buffer == 0) ||
(nbits > string_buffer_size-1)) {
/* nbits is really big. Make it even
* bigger - to avoid coming in here too many times.
*/
if (nbits > string_buffer_size-1)
string_buffer_size = nbits * 2;
string_buffer = (char *)malloc(string_buffer_size);
}
p = string_buffer + nbits;
*p = 0;
chunks = (nbits-1)/32 + 1;
bits_assigned = 0;
for(j=0;j<chunks; ++j) {
for(k=0;k<32;k++) {
abit = (value[j].aval>>k) & 0x01;
bbit = (value[j].bval>>k) & 0x01;
if ((abit == 1) && (bbit == 0)) c = '1';
else if ((abit == 0) && (bbit == 0)) c = '0';
else if ((abit == 1) && (bbit == 1)) c = 'x';
else if ((abit == 0) && (bbit == 1)) c = 'z';
else { c = 'x'; }
p--;
*p = c;
if (++bits_assigned >= nbits)
break;
}
}
return string_buffer;
}
/*
* FUNCTION -- NODOCS -- string2vhdl_array_of_int
*
* Given a string of '0', '1', 'x', 'z', convert
* that to a VHDL array of ints.
*/
void
string2vhdl_array_of_int(mtiInt32T *array,
unsigned int elements, char *s)
{
unsigned int i;
char c;
if (strlen(s) != elements) {
vpi_printf((PLI_BYTE8*)"FLI: Error: string2vhdl_array_of_int\n");
vpi_printf((PLI_BYTE8*)"FLI: Length of values %0d does\n",
strlen(s));
vpi_printf(
(PLI_BYTE8*)"FLI: NOT match the number of elements (%d)\n",
elements);
tf_dofinish();
}
for(i = 0; i < elements; i++) {
c = *s++;
if (c == '0') array[i] = 2;
else if (c == '1') array[i] = 3;
else if (c == 'x') array[i] = 1;
else if (c == 'z') array[i] = 4;
}
}
/*
* FUNCTION -- NODOCS -- string2vhdl_array_of_char
*
* Given a string of '0', '1', 'x', 'z', convert
* that to a VHDL array of ints.
*/
void
string2vhdl_array_of_char(char *array, unsigned int elements, char *s)
{
unsigned int i;
char c;
if (strlen(s) != elements) {
vpi_printf((PLI_BYTE8*)"FLI: Error: string2vhdl_array_of_char\n");
tf_dofinish();
}
for(i = 0; i < elements; i++) {
c = *s++;
if (c == '0') array[i] = 2;
else if (c == '1') array[i] = 3;
else if (c == 'x') array[i] = 1;
else if (c == 'z') array[i] = 4;
}
}
/*
* FUNCTION -- NODOCS -- vhdl_array_of_char2string
*
* Given an array of VHDL values, convert them
* to a string of '0', '1', 'x' or 'z'.
*/
char *
vhdl_array_of_char2string(char *array, int elements)
{
int i;
char *s;
char *p;
char c;
s = (char *)malloc(elements+1);
p = s;
for(i = 0; i < elements; i++) {
if (array[i] == 2) c = '0';
else if (array[i] == 3) c = '1';
else if (array[i] == 1) c = 'x';
else if (array[i] == 4) c = 'z';
else c = '-';
*p++ = c;
}
*p = 0;
return s;
}
/*
* FUNCTION -- NODOCS -- vhdl_array_of_int2string
*
* Given an array of VHDL values, convert them
* to a string of '0', '1', 'x' or 'z'.
*/
char *
vhdl_array_of_int2string(int *array, int elements)
{
int i;
char *s;
char *p;
char c;
s = (char *)malloc(elements+1);
p = s;
for(i = 0; i < elements; i++) {
if (array[i] == 2) c = '0';
else if (array[i] == 3) c = '1';
else if (array[i] == 1) c = 'x';
else if (array[i] == 4) c = 'z';
else c = '-';
*p++ = c;
}
*p = 0;
return s;
}
/*
* FUNCTION -- NODOCS -- uvm_register_get_vhdl
*
* Used to get the value of a VHDL signal, and return
* the value as a Verilog aval/bval pair.
*/
int uvm_register_get_vhdl(char *path, p_vpi_vecval value)
{
mtiSignalIdT signal_id;
mtiTypeIdT signal_type;
char *char_array;
int nbits = 0;
char *path_ptr = path;
int path_len;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if(*path_ptr != ']') {
// Not a vectored access
signal_id = mti_FindSignal(path);
if (signal_id) {
char_array = (char*)mti_GetArraySignalValue(signal_id, 0);
signal_type = mti_GetSignalType(signal_id);
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) {
nbits = mti_TickLength(signal_type);
} else {
nbits = 1; // Has to be a scalar signal
}
string_to_vecval(
vhdl_array_of_char2string(char_array, nbits),
nbits,
value);
mti_VsimFree(char_array);
return 1;
} else {
vpi_printf(
(PLI_BYTE8*)"FLI: uvm_register_get_vhdl() failed. Cannot find signal '%s'\n",
path);
return 0;
}
} else {
// A vectored access
while(path_ptr != path && *path_ptr != '[') {
path_ptr--;
path_len--;
}
// Extract the range from the path
int lhs, rhs, width, incr;
path_len--;
char path_copy[1024];
strncpy(path_copy, path, path_len);
path_copy[path_len]='\0';
// Find out no of bits in vector
signal_id = mti_FindSignal(path_copy);
if (signal_id) {
char_array = (char*)mti_GetArraySignalValue(signal_id, 0);
signal_type = mti_GetSignalType(signal_id);
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) {
nbits = mti_TickLength(signal_type);
} else {
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ENUM) {
nbits = 1;
}
}
if(strchr(path_ptr, ':') != NULL) {
if(sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
int i;
incr = (lhs>rhs) ? 1 : -1;
width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
char* vectors = vhdl_array_of_char2string(char_array, nbits);
char reduced_vector[256];
for (i = 0; i < width; i++) {
reduced_vector[i] = vectors[(nbits-1)-lhs];
lhs -= incr;
}
string_to_vecval(reduced_vector, width, value);
} else {
return 0;
}
} else {
if(sscanf(path_ptr, "[%u]", &rhs)) {
char* vectors = vhdl_array_of_char2string(char_array, nbits);
char reduced_vector[256];
reduced_vector[0] = vectors[(nbits-1)-rhs];
string_to_vecval(reduced_vector, 1, value);
} else {
return 0;
}
}
mti_VsimFree(char_array);
return 1;
} else {
return 0;
}
}
}
/*
* FUNCTION -- NODOCS -- uvm_register_set_vhdl
*
* Used to set the value of a VHDL signal, given
* the value as a Verilog aval/bval pair.
*/
int uvm_register_set_vhdl(char *path, p_vpi_vecval value, mtiForceTypeT forceType)
{
mtiSignalIdT signal_id;
mtiTypeIdT signal_type;
char *char_array;
char *path_ptr = path;
int path_len;
int nbits = 0;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
vpi_printf((PLI_BYTE8*)"Setting vhdl path %s\n", path);
if(*path_ptr != ']') {
// Not a vectored access
signal_id = mti_FindSignal(path);
if (signal_id) {
char_array = (char*)mti_GetArraySignalValue(signal_id, 0);
signal_type = mti_GetSignalType(signal_id);
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) {
nbits = mti_TickLength(signal_type);
} else {
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ENUM) {
nbits = 1;
}
}
if (forceType == MTI_RELEASE_SIGNAL) {
mti_ReleaseSignal(signal_id);
} else {
mti_ForceSignal(signal_id, vecval_to_string(nbits, value), 0, forceType, -1, -1);
}
mti_VsimFree(char_array);
return 1;
} else {
vpi_printf(
(PLI_BYTE8*)"FLI: uvm_register_set_vhdl() failed. Cannot find signal '%s'\n",
path);
return 0;
}
} else {
// A vectored access:
while(path_ptr != path && *path_ptr != '[') {
path_ptr--;
path_len--;
}
// Extract the range from the path
int lhs, rhs, width, incr;
path_len--;
char path_copy[1024];
strncpy(path_copy, path, path_len);
path_copy[path_len]='\0';
// Find out no of bits in vector
signal_id = mti_FindSignal(path_copy);
if (signal_id) {
char_array = (char*)mti_GetArraySignalValue(signal_id, 0);
signal_type = mti_GetSignalType(signal_id);
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) {
nbits = mti_TickLength(signal_type);
} else {
if(mti_GetTypeKind(signal_type) == MTI_TYPE_ENUM) {
nbits = 1;
}
}
}
if(strchr(path_ptr, ':') != NULL) {
if(sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
int i;
char index_str[20];
char path_str[80];
char vector_val[128];
strcpy(vector_val,vecval_to_string(nbits, value));
incr = (lhs>rhs) ? 1 : -1;
width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
for (i = 0; i < width; i++) {
sprintf(index_str,"(%u)",rhs);
rhs += incr;
strcpy(path_str, path_copy);
strcat(path_str,index_str);
signal_id = mti_FindSignal(path_str);
if (forceType == MTI_RELEASE_SIGNAL) {
mti_ReleaseSignal(signal_id);
} else {
if(vector_val[(nbits-i)-1] == '1') {
mti_ForceSignal(signal_id, (char*)"1", 0, MTI_FORCE_DEPOSIT, -1, -1);
} else {
mti_ForceSignal(signal_id, (char*)"0", 0, MTI_FORCE_DEPOSIT, -1, -1);
}
}
}
}
} else {
vpi_printf((PLI_BYTE8*)"Single vector\n");
if(sscanf(path_ptr,"[%u]", &rhs)) {
char index_str[20];
char path_str[80];
char vector_val[128];
strcpy(vector_val,vecval_to_string(nbits, value));
sprintf(index_str,"(%u)",rhs);
strcpy(path_str, path_copy);
strcat(path_str,index_str);
signal_id = mti_FindSignal(path_str);
if (forceType == MTI_RELEASE_SIGNAL) {
mti_ReleaseSignal(signal_id);
} else {
if(vector_val[(nbits-1)-rhs] == '1') {
mti_ForceSignal(signal_id, (char*)"1", 0, MTI_FORCE_DEPOSIT, -1, -1);
} else {
mti_ForceSignal(signal_id, (char*)"0", 0, MTI_FORCE_DEPOSIT, -1, -1);
}
}
}
}
mti_VsimFree(char_array);
return 1;
}
}
//
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int partsel = 0;
/*
* Given a path with part-select, break into individual bit accesses
* path = pointer to user string
* value = pointer to logic vector
* flag = deposit vs force/release options, etc
*/
static int uvm_hdl_set_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
char *path_ptr = path;
int path_len;
svLogicVecVal bit_value;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if (*path_ptr != ']')
return 0;
while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != ':')
return 0;
while(path_ptr != path && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != '[')
return 0;
int lhs, rhs, width, incr;
// extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[20];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? 1 : -1;
width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
vpi_printf((PLI_BYTE8*)"LHS %u RHS %u\n", lhs, rhs);
// perform set for each individual bit
for (i=0; i < width; i++) {
sprintf(index_str,"%u]",rhs);
strncpy(path_ptr,index_str,path_len);
svGetPartselLogic(&bit_value,value,i,1);
rhs += incr;
if (!uvm_hdl_set_vlog(path,&bit_value,flag))
return 0;
}
return 1;
}
return 0;
}
/*
* Given a path with part-select, break into individual bit accesses
* path = pointer to user string
* value = pointer to logic vector
* flag = deposit vs force/release options, etc
*/
static int uvm_hdl_get_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
char *path_ptr = path;
int path_len;
svLogicVecVal bit_value;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if (*path_ptr != ']')
return 0;
while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != ':')
return 0;
while(path_ptr != path && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != '[')
return 0;
int lhs, rhs, width, incr;
// extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[20];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? 1 : -1;
width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
bit_value.aval = 0;
bit_value.bval = 0;
partsel = 1;
for (i=0; i < width; i++) {
int result;
svLogic logic_bit;
sprintf(index_str,"%u]",rhs);
strncpy(path_ptr,index_str,path_len);
result = uvm_hdl_get_vlog(path,&bit_value,flag);
logic_bit = svGetBitselLogic(&bit_value,0);
svPutPartselLogic(value,bit_value,i,1);
rhs += incr;
if (!result)
return 0;
}
partsel = 0;
return 1;
}
return 0;
}
/*
* Given a path, look the path name up using the PLI,
* and set it to 'value'.
*/
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
static int maxsize = -1;
vpiHandle r;
s_vpi_value value_s = { vpiIntVal, { 0 } };
s_vpi_time time_s = { vpiSimTime, 0, 0, 0.0 };
int result = 0;
result = uvm_hdl_set_vlog_partsel(path,value,flag);
if (result < 0)
return 0;
if (result == 1)
return 1;
if (!strncmp(path,"$root.",6))
r = vpi_handle_by_name(path+6, 0);
else
r = vpi_handle_by_name(path, 0);
if(r == 0)
{
const char * err_str = "set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name";
char buffer[strlen(err_str) + strlen(path)];
sprintf(buffer, err_str, path);
m_uvm_report_dpi(M_UVM_ERROR,
(char*) "UVM/DPI/HDL_SET",
&buffer[0],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
return 0;
}
else
{
if(maxsize == -1)
maxsize = uvm_hdl_max_width();
if (flag == vpiReleaseFlag) {
}
value_s.format = vpiVectorVal;
value_s.value.vector = value;
vpi_put_value(r, &value_s, &time_s, flag);
if (value == NULL) {
value = value_s.value.vector;
}
}
vpi_release_handle(r);
return 1;
}
/*
* Given a path, look the path name up using the PLI
* and return its 'value'.
*/
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
static int maxsize = -1;
int i, size, chunks;
vpiHandle r;
s_vpi_value value_s;
if (!partsel) {
maxsize = uvm_hdl_max_width();
chunks = (maxsize-1)/32 + 1;
for(i=0;i<chunks-1; ++i) {
value[i].aval = 0;
value[i].bval = 0;
}
}
int result = 0;
result = uvm_hdl_get_vlog_partsel(path,value,flag);
if (result < 0)
return 0;
if (result == 1)
return 1;
if (!strncmp(path,"$root.",6))
r = vpi_handle_by_name(path+6, 0);
else
r = vpi_handle_by_name(path, 0);
if(r == 0)
{
const char * err_str = "get: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name";
char buffer[strlen(err_str) + strlen(path)];
sprintf(buffer, err_str, path);
m_uvm_report_dpi(M_UVM_ERROR,
(char*)"UVM/DPI/HDL_GET",
&buffer[0],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
// Exiting is too harsh. Just return instead.
// tf_dofinish();
return 0;
}
else
{
if(maxsize == -1)
maxsize = uvm_hdl_max_width();
size = vpi_get(vpiSize, r);
if(size > maxsize)
{
const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=<value>";
char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))];
sprintf(buffer, err_str, path, size, maxsize);
m_uvm_report_dpi(M_UVM_ERROR,
(char*)"UVM/DPI/HDL_SET",
&buffer[0],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
vpi_release_handle(r);
return 0;
}
chunks = (size-1)/32 + 1;
value_s.format = vpiVectorVal;
vpi_get_value(r, &value_s);
/*dpi and vpi are reversed*/
for(i=0;i<chunks; ++i)
{
value[i].aval = value_s.value.vector[i].aval;
value[i].bval = value_s.value.vector[i].bval;
}
}
//vpi_printf("uvm_hdl_get_vlog(%s,%0x)\n",path,value[0].aval);
vpi_release_handle(r);
return 1;
}
/*
* Given a path, look the path name up using the PLI,
* but don't set or get. Just check.
*
* Return 0 if NOT found.
* Return 1 if found.
*/
int uvm_hdl_check_path(char *path)
{
vpiHandle r;
// Check VHDL for Questa
if(uvm_is_vhdl_path(path)) {
return 1;
}
if (!strncmp(path,"$root.",6)) {
r = vpi_handle_by_name(path+6, 0);
} else
r = vpi_handle_by_name(path, 0);
if(r == 0)
return 0;
else
return 1;
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and return its 'value'.
*/
int uvm_hdl_read(char *path, p_vpi_vecval value)
{
if (uvm_is_vhdl_path(path)) {
return uvm_register_get_vhdl(path, value);
} else {
return uvm_hdl_get_vlog(path, value, vpiNoDelay);
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and set it to 'value'.
*/
int uvm_hdl_deposit(char *path, p_vpi_vecval value)
{
if(uvm_is_vhdl_path(path)) {
return uvm_register_set_vhdl(path, value, MTI_FORCE_DEPOSIT);
} else {
return uvm_hdl_set_vlog(path, value, vpiNoDelay);
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and set it to 'value'.
*/
int uvm_hdl_force(char *path, p_vpi_vecval value)
{
if(uvm_is_vhdl_path(path)) {
return uvm_register_set_vhdl(path, value, MTI_FORCE_FREEZE);
} else {
return uvm_hdl_set_vlog(path, value, vpiForceFlag);
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and release it.
*/
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value)
{
int result = 0;
if(uvm_is_vhdl_path(path)) {
result = uvm_register_set_vhdl(path, value, MTI_RELEASE_SIGNAL);
if (result > 0)
result = uvm_register_get_vhdl(path, value);
} else {
result = uvm_hdl_set_vlog(path, value, vpiReleaseFlag);
if (result > 0)
result = uvm_hdl_get_vlog(path, value, vpiNoDelay);
}
return result;
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and release it.
*/
int uvm_hdl_release(char *path)
{
s_vpi_vecval value;
p_vpi_vecval valuep = &value;
if(uvm_is_vhdl_path(path)) {
return uvm_register_set_vhdl(path, valuep, MTI_RELEASE_SIGNAL);
} else {
return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,276 @@
//----------------------------------------------------------------------
// Copyright 2007-2009 Cadence Design Systems, Inc.
// Copyright 2026 Marvell International Ltd.
// Copyright 2009 Mentor Graphics Corporation
// Copyright 2026 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_hdl_verilator.c $
// $Rev: 2026-05-08 07:53:24 -0700 $
// $Hash: b79027c3a6650c9072fd2772cb849c270ae4cc85 $
//
//----------------------------------------------------------------------
#include "svdpi.h"
#include "vpi_user.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void m_uvm_error(const char *ID, const char *msg, ...);
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value);
static int uvm_hdl_max_width();
// static print buffer
static char m_uvm_temp_print_buffer[1024];
// static print error
static void m_uvm_error(const char *id, const char *msg, ...) {
va_list argptr;
va_start(argptr, msg);
vsnprintf(m_uvm_temp_print_buffer, sizeof(m_uvm_temp_print_buffer), msg, argptr);
va_end(argptr);
m_uvm_report_dpi(M_UVM_ERROR, (char *)id, &m_uvm_temp_print_buffer[0], M_UVM_NONE,
(char *)__FILE__, __LINE__);
}
/*
* UVM HDL access C code.
*
*/
/*
* This C code checks to see if there is PLI handle
* with a value set to define the maximum bit width.
*
* If no such variable is found, then the default
* width of 1024 is used.
*
*/
static int UVM_HDL_MAX_WIDTH = 0;
static int uvm_hdl_max_width() {
if (!UVM_HDL_MAX_WIDTH) {
vpiHandle ms;
s_vpi_value value_s = {vpiIntVal, {0}};
ms = vpi_handle_by_name((PLI_BYTE8 *)"uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
if (ms == 0) {
UVM_HDL_MAX_WIDTH = 1024; /* If nothing else is defined, this is the DEFAULT */
} else {
vpi_get_value(ms, &value_s);
UVM_HDL_MAX_WIDTH = value_s.value.integer;
vpi_release_handle(ms);
}
}
return UVM_HDL_MAX_WIDTH;
}
/*
* Given a path, look the path name up using the PLI,
* and set it to 'value'.
*/
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag) {
vpiHandle r;
s_vpi_value value_s = {vpiIntVal, {0}};
s_vpi_time time_s = {vpiSimTime, 0, 0, 0.0};
int i, size, chunks;
static int s_maxsize = -1;
if (path == NULL || path[0] == '\0') {
m_uvm_error("UVM/DPI/VLOG_PUT", "NULL or empty HDL path passed to uvm_hdl_set_vlog");
return 0;
}
r = vpi_handle_by_name(path, 0);
if (r == 0) {
m_uvm_error("UVM/DPI/VLOG_PUT",
"set: unable to locate hdl path (%s)\n Either the name is incorrect, "
"or you may not have PLI/ACC visibility to that name",
path);
return 0;
}
if (value == NULL && flag != vpiReleaseFlag) {
m_uvm_error("UVM/DPI/VLOG_PUT",
"NULL value pointer passed for hdl path '%s' in non-release operation", path);
vpi_release_handle(r);
return 0;
}
if (value) {
if (s_maxsize == -1) s_maxsize = uvm_hdl_max_width();
size = vpi_get(vpiSize, r);
if (size > s_maxsize) {
m_uvm_error("UVM/DPI/VLOG_PUT",
"hdl path '%s' is %0d bits, but the maximum size is %0d. "
"You can increase the maximum via a compile-time flag: "
"+define+UVM_HDL_MAX_WIDTH=<value>",
path, size, s_maxsize);
vpi_release_handle(r);
return 0;
}
}
value_s.format = value ? vpiVectorVal : vpiSuppressVal;
value_s.value.vector = value;
vpiHandle returnHandle = vpi_put_value(r, &value_s, &time_s, flag);
if (returnHandle == 0) {
vpi_release_handle(r);
m_uvm_error("UVM/DPI/VLOG_PUT",
"failed to set hdl path '%s'. Common reasons include a signal having an "
"unsupported type, such as a real or a string, or attempting to force a signal "
"that is not marked as /*verilator forceable*/",
path);
return 0;
}
if (flag == vpiReleaseFlag && value) {
chunks = (size - 1) / 32 + 1;
for (i = 0; i < chunks; ++i) value[i] = value_s.value.vector[i];
}
vpi_release_handle(r);
return 1;
}
/*
* Given a path, look the path name up using the PLI
* and return its 'value'.
*/
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value) {
static int s_maxsize = -1;
int i, size, chunks;
vpiHandle r;
s_vpi_value value_s = {vpiVectorVal, {0}};
if (path == NULL || path[0] == '\0') {
m_uvm_error("UVM/DPI/VLOG_GET", "NULL or empty HDL path passed to uvm_hdl_get_vlog");
return 0;
}
r = vpi_handle_by_name(path, 0);
if (r == 0) {
m_uvm_error("UVM/DPI/VLOG_GET",
"unable to locate hdl path (%s)\n Either the name is incorrect, or you "
"may not have PLI/ACC visibility to that name",
path);
return 0;
}
if (value == NULL) {
m_uvm_error("UVM/DPI/VLOG_GET", "NULL value pointer passed for hdl path '%s'", path);
vpi_release_handle(r);
return 0;
}
if (s_maxsize == -1) s_maxsize = uvm_hdl_max_width();
size = vpi_get(vpiSize, r);
if (size > s_maxsize) {
m_uvm_error("UVM/DPI/VLOG_GET",
"hdl path '%s' is %0d bits, but the maximum size is %0d. "
"You can increase the maximum via a compile-time flag: "
"+define+UVM_HDL_MAX_WIDTH=<value>",
path, size, s_maxsize);
vpi_release_handle(r);
return 0;
}
chunks = (size - 1) / 32 + 1;
value_s.value.vector = NULL;
vpi_get_value(r, &value_s);
if (value_s.format != vpiVectorVal || value_s.value.vector == 0) {
m_uvm_error("UVM/DPI/VLOG_GET",
"failed to get value for hdl path '%s'. Common reasons include a signal having an "
"unsupported type, such as a real or a string",
path);
vpi_release_handle(r);
return 0;
}
// Note upper bits are not cleared, other simulators do likewise
for (i = 0; i < chunks; ++i) {
value[i].aval = value_s.value.vector[i].aval;
value[i].bval = value_s.value.vector[i].bval;
}
// vpi_printf((PLI_BYTE8 *)"uvm_hdl_get_vlog(%s,%0x)\n", path, value[0].aval);
vpi_release_handle(r);
return 1;
}
/*
* Given a path, look the path name up using the PLI,
* but don't set or get. Just check.
*
* Return 0 if NOT found.
* Return 1 if found.
*/
int uvm_hdl_check_path(char *path) {
vpiHandle handle;
if (path == NULL || path[0] == '\0') {
m_uvm_error("UVM/DPI/VLOG_CHECK", "NULL or empty HDL path passed to uvm_hdl_check_path");
return 0;
}
handle = vpi_handle_by_name(path, 0);
if (handle) vpi_release_handle(handle);
return (handle != 0);
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and return its 'value'.
*/
int uvm_hdl_read(char *path, p_vpi_vecval value) { return uvm_hdl_get_vlog(path, value); }
/*
* Given a path, look the path name up using the PLI
* or the FLI, and set it to 'value'.
*/
int uvm_hdl_deposit(char *path, p_vpi_vecval value) {
return uvm_hdl_set_vlog(path, value, vpiNoDelay);
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and set it to 'value'.
*/
int uvm_hdl_force(char *path, p_vpi_vecval value) {
return uvm_hdl_set_vlog(path, value, vpiForceFlag);
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and release it.
*/
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value) {
return uvm_hdl_set_vlog(path, value, vpiReleaseFlag);
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and release it.
*/
int uvm_hdl_release(char *path) { return uvm_hdl_set_vlog(path, NULL, vpiReleaseFlag); }

View File

@ -0,0 +1,687 @@
//----------------------------------------------------------------------
// Copyright 2007-2023 Cadence Design Systems, Inc.
// Copyright 2009-2011 Mentor Graphics Corporation
// Copyright 2013-2024 NVIDIA Corporation
// Copyright 2010-2011 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_hdl_xcelium.c $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
// use -DINCA_EXTENDED_PARTSEL_SUPPORT to use extended support for vpi_handle_by_name
#include "vhpi_user.h"
#include "vpi_user.h"
#include "veriuser.h"
#include "svdpi.h"
#include <malloc.h>
#include <string.h>
#include <stdio.h>
static void m_uvm_error(const char *ID, const char *msg, ...);
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static void m_uvm_get_object_handle(const char* path, vhpiHandleT *handle,int *language);
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int uvm_hdl_max_width();
// static print buffer
static char m_uvm_temp_print_buffer[1024];
/*
* UVM HDL access C code.
*
*/
static void m_uvm_get_object_handle(const char* path, vhpiHandleT *handle,int *language)
{
*handle = vhpi_handle_by_name(path, 0);
if(*handle)
*language = vhpi_get(vhpiLanguageP, *handle);
}
// returns 0 if the name is NOT a slice
// returns 1 if the name is a slice
static int is_valid_path_slice(const char* path) {
char *path_ptr = (char *) path;
int path_len;
#ifdef INCA_EXTENDED_PARTSEL_SUPPORT
return 0;
#endif
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if (*path_ptr != ']')
return 0;
while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != ':')
return 0;
while(path_ptr != path && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != '[')
return 0;
return 1;
}
static int uvm_hdl_set_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
char *path_ptr = path;
int path_len;
svLogicVecVal bit_value;
if(!is_valid_path_slice(path)) return 0;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if (*path_ptr != ']')
return 0;
while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != ':')
return 0;
while(path_ptr != path && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != '[')
return 0;
int lhs, rhs, width, incr;
// extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[20];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? 1 : -1;
width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
// perform set for each individual bit
for (i=0; i < width; i++) {
sprintf(index_str,"%u]",rhs);
strncpy(path_ptr,index_str,path_len);
svGetPartselLogic(&bit_value,value,i,1);
rhs += incr;
if (uvm_hdl_set_vlog_partsel(path,&bit_value,flag)==0) {
if(uvm_hdl_set_vlog(path,&bit_value,flag)==0) { return 0; };
}
}
return 1;
}
return 0;
}
/*
* Given a path with part-select, break into individual bit accesses
* path = pointer to user string
* value = pointer to logic vector
* flag = deposit vs force/release options, etc
*/
static int uvm_hdl_get_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
char *path_ptr = path;
int path_len;
svLogicVecVal bit_value;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-1);
if (*path_ptr != ']')
return 0;
while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != ':')
return 0;
while(path_ptr != path && *path_ptr != '[')
path_ptr--;
if (path_ptr == path || *path_ptr != '[')
return 0;
int lhs, rhs, width, incr;
// extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[20];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? 1 : -1;
width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
bit_value.aval = 0;
bit_value.bval = 0;
for (i=0; i < width; i++) {
sprintf(index_str,"%u]",rhs);
strncpy(path_ptr,index_str,path_len);
if(uvm_hdl_get_vlog_partsel(path,&bit_value,flag) == 0) {
if(uvm_hdl_get_vlog(path,&bit_value,flag)==0) { return 0; }
}
svGetBitselLogic(&bit_value,0);
svPutPartselLogic(value,bit_value,i,1);
rhs += incr;
}
return 1;
} else {
return 0;
}
}
static void clear_value(p_vpi_vecval value) {
int chunks;
int maxsize = uvm_hdl_max_width();
chunks = (maxsize-1)/32 + 1;
for(int i=0;i<chunks-1; ++i) {
value[i].aval = 0;
value[i].bval = 0;
}
}
/*
* This C code checks to see if there is PLI handle
* with a value set to define the maximum bit width.
*
* This function should only get called once or twice,
* its return value is cached in the caller.
*
*/
static int UVM_HDL_MAX_WIDTH = 0;
static int uvm_hdl_max_width()
{
if(!UVM_HDL_MAX_WIDTH) {
vpiHandle ms;
s_vpi_value value_s = { vpiIntVal, { 0 } };
ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
vpi_get_value(ms, &value_s);
UVM_HDL_MAX_WIDTH= value_s.value.integer;
}
return UVM_HDL_MAX_WIDTH;
}
/*
* Given a path, look the path name up using the PLI,
* and set it to 'value'.
*/
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
static int maxsize = -1;
vpiHandle r;
s_vpi_value value_s = { vpiIntVal, { 0 } };
s_vpi_time time_s = { vpiSimTime, 0, 0, 0.0 };
r = vpi_handle_by_name(path, 0);
if(r == 0)
{
m_uvm_error("UVM/DPI/HDL_SET","set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name",
path);
return 0;
}
else
{
if(maxsize == -1)
maxsize = uvm_hdl_max_width();
if (flag == vpiReleaseFlag) {
// FIXME
//size = vpi_get(vpiSize, r);
//value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval)));
//value = &value_p;
}
value_s.format = vpiVectorVal;
value_s.value.vector = value;
vpi_put_value(r, &value_s, &time_s, flag);
//if (value_p != NULL)
// free(value_p);
if (value == NULL) {
value = value_s.value.vector;
}
}
vpi_release_handle(r);
return 1;
}
static vhpiEnumT vhpiEnumTLookup[4] = {vhpi0,vhpi1,vhpiZ,vhpiX}; // idx={b[0],a[0]}
static vhpiEnumT vhpi2val(int aval,int bval) {
int idx=(((bval<<1) | (aval&1)) & 3);
return vhpiEnumTLookup[idx];
}
static int uvm_hdl_set_vhdl(char* path, p_vpi_vecval value, PLI_INT32 flag)
{
static int maxsize = -1;
int size, chunks, bit, i, j, aval, bval;
vhpiValueT value_s;
vhpiHandleT r = vhpi_handle_by_name(path, 0);
if(maxsize == -1) maxsize = uvm_hdl_max_width();
if(maxsize == -1) maxsize = 1024;
size = vhpi_get(vhpiSizeP, r);
if(size > maxsize)
{
m_uvm_error("UVM/DPI/VHDL_SET","hdl path %s is %0d bits, but the current maximum size is %0d. You may redefine it using the compile-time flag: -define UVM_HDL_MAX_WIDTH=<value>", path, size,maxsize);
tf_dofinish();
}
chunks = (size-1)/32 + 1;
value_s.format = vhpiObjTypeVal;
value_s.bufSize = 0;
value_s.value.str = NULL;
vhpi_get_value(r, &value_s);
switch(value_s.format)
{
case vhpiEnumVal:
{
value_s.value.enumv = vhpi2val(value[0].aval,value[0].bval);
break;
}
case vhpiEnumVecVal:
{
value_s.bufSize = size*sizeof(int);
value_s.value.enumvs = (vhpiEnumT *)malloc(size*sizeof(int));
vhpi_get_value(r, &value_s);
chunks = (size-1)/32 + 1;
bit = 0;
for(i=0;i<chunks && bit<size; ++i)
{
aval = value[i].aval;
bval = value[i].bval;
for(j=0;j<32 && bit<size; ++j)
{
value_s.value.enumvs[size-bit-1]= vhpi2val(aval,bval);
aval>>=1; bval>>=1;
bit++;
}
}
break;
}
default:
{
m_uvm_error("UVM/DPI/VHDL_SET","Failed to set value to hdl path %s (unexpected type: %0d)", path, value_s.format);
tf_dofinish();
return 0;
}
}
vhpi_put_value(r, &value_s, flag);
if(value_s.format == vhpiEnumVecVal)
{
free(value_s.value.enumvs);
}
return 1;
}
/*
* Given a path, look the path name up using the PLI
* and return its 'value'.
*/
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
static int maxsize = -1;
int i, size, chunks;
vpiHandle r;
s_vpi_value value_s;
r = vpi_handle_by_name(path, 0);
if(r == 0)
{
m_uvm_error("UVM/DPI/VLOG_GET","unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name",path);
// Exiting is too harsh. Just return instead.
// tf_dofinish();
return 0;
}
else
{
if(maxsize == -1)
maxsize = uvm_hdl_max_width();
size = vpi_get(vpiSize, r);
if(size > maxsize)
{
m_uvm_error("UVM/DPI/VLOG_GET","hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=<value>",
path,size,maxsize);
//tf_dofinish();
vpi_release_handle(r);
return 0;
}
chunks = (size-1)/32 + 1;
value_s.format = vpiVectorVal;
vpi_get_value(r, &value_s);
/*dpi and vpi are reversed*/
for(i=0;i<chunks; ++i)
{
value[i].aval = value_s.value.vector[i].aval;
value[i].bval = value_s.value.vector[i].bval;
}
}
//vpi_printf("uvm_hdl_get_vlog(%s,%0x)\n",path,value[0].aval);
vpi_release_handle(r);
return 1;
}
static int uvm_hdl_get_vhdl(char* path, p_vpi_vecval value)
{
static int maxsize = -1;
int i, j, size, chunks, bit, aval, bval, rtn;
vhpiValueT value_s;
vhpiHandleT r = vhpi_handle_by_name(path, 0);
if(maxsize == -1) maxsize = uvm_hdl_max_width();
if(maxsize == -1) maxsize = 1024;
size = vhpi_get(vhpiSizeP, r);
if(size > maxsize)
{
m_uvm_error("UVM/DPI/HDL_SET","hdl path %s is %0d bits, but the maximum size is %0d, redefine using -define UVM_HDL_MAX_WIDTH=<value>", path, size,maxsize);
tf_dofinish();
}
chunks = (size-1)/32 + 1;
value_s.format = vhpiObjTypeVal;
value_s.bufSize = 0;
value_s.value.str = NULL;
rtn = vhpi_get_value(r, &value_s);
if(vhpi_check_error(0) != 0)
{
m_uvm_error("UVM/DPI/VHDL_GET","Failed to get value from hdl path %s",path);
tf_dofinish();
return 0;
}
switch (value_s.format)
{
case vhpiIntVal:
{
value[0].aval = value_s.value.intg;
value[0].bval = 0;
break;
}
case vhpiEnumVal:
{
switch(value_s.value.enumv)
{
case vhpiU:
case vhpiW:
case vhpiX:
{
value[0].aval = 1; value[0].bval = 1; break;
}
case vhpiZ:
{
value[0].aval = 0; value[0].bval = 1; break;
}
case vhpi0:
case vhpiL:
case vhpiDontCare:
{
value[0].aval = 0; value[0].bval = 0; break;
}
case vhpi1:
case vhpiH:
{
value[0].aval = 1; value[0].bval = 0; break;
}
}
break;
}
case vhpiEnumVecVal:
{
value_s.bufSize = size;
value_s.value.str = (char*)malloc(size);
rtn = vhpi_get_value(r, &value_s);
if (rtn > 0) {
value_s.value.str = (char*)realloc(value_s.value.str, rtn);
value_s.bufSize = rtn;
vhpi_get_value(r, &value_s);
}
for(i=0; i<((maxsize-1)/32+1); ++i)
{
value[i].aval = 0;
value[i].bval = 0;
}
bit = 0;
for(i=0;i<chunks && bit<size; ++i)
{
aval = 0;
bval = 0;
for(j=0;(j<32) && (bit<size); ++j)
{
aval<<=1; bval<<=1;
switch(value_s.value.enumvs[bit])
{
case vhpiU:
case vhpiW:
case vhpiX:
{
aval |= 1;
bval |= 1;
break;
}
case vhpiZ:
{
bval |= 1;
break;
}
case vhpi0:
case vhpiL:
case vhpiDontCare:
{
break;
}
case vhpi1:
case vhpiH:
{
aval |= 1;
break;
}
}
bit++;
}
value[i].aval = aval;
value[i].bval = bval;
free (value_s.value.str);
}
break;
}
default:
{
m_uvm_error("UVM/DPI/VHDL_GET","Failed to get value from hdl path %s (unexpected type: %0d)", path, value_s.format);
tf_dofinish();
return 0;
}
}
return 1;
}
/*
* Given a path, look the path name up using the PLI,
* but don't set or get. Just check.
*
* Return 0 if NOT found.
* Return 1 if found.
*/
int uvm_hdl_check_path(char *path)
{
vhpiHandleT handle;
int language;
m_uvm_get_object_handle(path,&handle,&language);
return (handle!=0);
}
static void m_uvm_error(const char *id, const char *msg, ...) {
va_list argptr;
va_start(argptr,msg);
vsprintf(m_uvm_temp_print_buffer,msg, argptr);
va_end(argptr);
m_uvm_report_dpi(M_UVM_ERROR,
(char *) id,
&m_uvm_temp_print_buffer[0],
M_UVM_NONE,
(char*) __FILE__,
__LINE__);
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and return its 'value'.
*/
int uvm_hdl_read(char *path, p_vpi_vecval value)
{
vhpiHandleT handle;
int language;
if(is_valid_path_slice(path)) {
clear_value(value);
return uvm_hdl_get_vlog_partsel(path, value, vpiNoDelay);
}
m_uvm_get_object_handle(path,&handle,&language);
switch(language) {
case vhpiVerilog: return uvm_hdl_get_vlog(path, value, vpiNoDelay);
case vhpiVHDL: return uvm_hdl_get_vhdl(path, value);
default:m_uvm_error("UVM/DPI/NOBJ1","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and set it to 'value'.
*/
int uvm_hdl_deposit(char *path, p_vpi_vecval value)
{
vhpiHandleT handle;
int language;
if(is_valid_path_slice(path))
return uvm_hdl_set_vlog_partsel(path, value, vpiNoDelay);
m_uvm_get_object_handle(path,&handle,&language);
switch(language) {
case vhpiVerilog: return uvm_hdl_set_vlog(path, value, vpiNoDelay);
case vhpiVHDL: return uvm_hdl_set_vhdl(path, value, vhpiDepositPropagate);
default:m_uvm_error("UVM/DPI/NOBJ2","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and set it to 'value'.
*/
int uvm_hdl_force(char *path, p_vpi_vecval value)
{
vhpiHandleT handle;
int language;
if(is_valid_path_slice(path))
return uvm_hdl_set_vlog_partsel(path, value, vpiForceFlag);
m_uvm_get_object_handle(path,&handle,&language);
switch(language) {
case vhpiVerilog: return uvm_hdl_set_vlog(path, value, vpiForceFlag);
case vhpiVHDL: return uvm_hdl_set_vhdl(path, value, vhpiForcePropagate);
default:m_uvm_error("UVM/DPI/NOBJ3","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and release it.
*/
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value)
{
vhpiHandleT handle;
int language;
if(is_valid_path_slice(path)) {
uvm_hdl_set_vlog_partsel(path, value, vpiReleaseFlag);
clear_value(value);
return uvm_hdl_get_vlog_partsel(path, value, vpiNoDelay);
}
m_uvm_get_object_handle(path,&handle,&language);
switch(language) {
case vhpiVerilog: uvm_hdl_set_vlog(path, value, vpiReleaseFlag); return uvm_hdl_get_vlog(path, value, vpiNoDelay);
case vhpiVHDL: uvm_hdl_set_vhdl(path, value, vhpiReleaseKV); return uvm_hdl_get_vhdl(path, value);
default:m_uvm_error("UVM/DPI/NOBJ4","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
}
}
/*
* Given a path, look the path name up using the PLI
* or the FLI, and release it.
*/
int uvm_hdl_release(char *path)
{
s_vpi_vecval value;
vhpiHandleT handle;
int language;
if(is_valid_path_slice(path))
return uvm_hdl_set_vlog_partsel(path, &value, vpiReleaseFlag);
m_uvm_get_object_handle(path,&handle,&language);
switch(language) {
case vhpiVerilog: return uvm_hdl_set_vlog(path, &value, vpiReleaseFlag);
case vhpiVHDL: return uvm_hdl_set_vhdl(path, &value, vhpiReleaseKV);
default:m_uvm_error("UVM/DPI/NOBJ5","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
}
}

View File

@ -0,0 +1,94 @@
//----------------------------------------------------------------------
// Copyright 2023 Intel Corporation
// Copyright 2023 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_polling_dpi.svh $
// $Rev: 2024-01-16 12:31:36 -0800 $
// $Hash: 03eb4be614dec8e91a7f62d41cacff41c5f72ac5 $
//
//----------------------------------------------------------------------
`ifndef UVM_DPI_POLLING_SVH
`define UVM_DPI_POLLING_SVH
`ifndef UVM_NO_DPI
import "DPI-C" context function chandle uvm_polling_create(input string name, input int sv_key);
// Set/get value-change callback enable on the chosen signal.
import "DPI-C" context function void uvm_polling_set_enable_callback(chandle hnd, int enable);
import "DPI-C" context function int uvm_polling_get_callback_enable(chandle hnd);
// Get the signal's value.
// Get the signal's static properties.
import "DPI-C" context function int uvm_polling_setup_notifier(string fullname);
import "DPI-C" context function void uvm_polling_process_changelist();
import "DPI-C" context function int uvm_hdl_signal_size(string path);
// import "DPI-C" context function void uvm_polling_free_mem_structures();
`else
// uvm_polling_create
function chandle uvm_polling_create(input string name, input int sv_key);
chandle ch;
uvm_report_fatal("UVM_HDL_POLLING",
$sformatf("VPI access is disabled. Recompile without +define+UVM_HDL_NO_DPI"));
return ch;
endfunction
// uvm_polling_set_enable_callback
function void uvm_polling_set_enable_callback(chandle hnd, int enable);
uvm_report_fatal("UVM_HDL_POLLING",
$sformatf("VPI access is disabled. Recompile without +define+UVM_HDL_NO_DPI"));
endfunction
// uvm_polling_get_callback_enable
function int uvm_polling_get_callback_enable(chandle hnd);
uvm_report_fatal("UVM_HDL_POLLING",
$sformatf("VPI access is disabled. Recompile without +define+UVM_HDL_NO_DPI"));
endfunction
// uvm_polling_setup_notifier
function int uvm_polling_setup_notifier(string fullname);
uvm_report_fatal("UVM_HDL_POLLING",
$sformatf("VPI access is disabled. Recompile without +define+UVM_HDL_NO_DPI"));
endfunction
// uvm_polling_process_changelist
function void uvm_polling_process_changelist();
uvm_report_fatal("UVM_HDL_POLLING",
$sformatf("VPI access is disabled. Recompile without +define+UVM_HDL_NO_DPI"));
endfunction
function int uvm_hdl_signal_size(string path);
uvm_report_fatal("UVM_HDL_POLLING",
$sformatf("VPI access is disabled. Recompile without +define+UVM_HDL_NO_DPI"));
endfunction
`endif
`endif

View File

@ -0,0 +1,368 @@
//----------------------------------------------------------------------
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2023 Marvell International Ltd.
// Copyright 2007-2011 Mentor Graphics Corporation
// Copyright 2013-2024 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_regex.cc $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
#include "uvm_dpi.h"
#include <sys/types.h>
const char uvm_re_bracket_char = '/';
const char uvm_re_escape_char = '\\';
#define UVM_REGEX_MAX_LENGTH 2048
static const char* empty_regex="^$";
static const char* empty_regex_brackets = "/^$/";
typedef regex_t* regex_ptr;
//--------------------------------------------------------------------
// uvm_re_buffer
//
// Returns the current value of the uvm re buffer string. Note that
// the contents are only valid until the next call to a uvm_re_* method.
//--------------------------------------------------------------------
char * uvm_re_buffer()
{
static char buffer[UVM_REGEX_MAX_LENGTH+4];
return &buffer[0];
}
//--------------------------------------------------------------------
// uvm_re_deglobbed
//
// Convert a glob expression to a normal regular expression.
//--------------------------------------------------------------------
const char * uvm_re_deglobbed(const char *glob, unsigned char with_brackets)
{
char* buffer = uvm_re_buffer();
const char *p;
// safety check. Glob should never be ~null~ since this is called
// from DPI. But we'll check anyway.
if(glob == NULL) {
sprintf(buffer, "uvm_glob_to_re called with glob=NULL");
return NULL;
}
size_t glob_len;
glob_len = strlen(glob);
// If either of the following cases appear then return an empty string
//
// 1. The glob string is empty (it has zero characters)
// 2. The glob string has a single character that is the
// uvm_re_bracket_char (i.e. "/")
if(glob_len == 0 || (glob_len == 1 && *glob == uvm_re_bracket_char)) {
if (with_brackets) {
return empty_regex_brackets;
}
else {
return empty_regex;
}
}
// If bracketed with the /glob/, then it's already a regex
if (glob[0] == uvm_re_bracket_char && glob[glob_len-1] == uvm_re_bracket_char) {
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re() glob exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
else {
if (with_brackets) {
strcpy(buffer,glob);
}
else {
strncpy(buffer, &glob[1], glob_len-2);
buffer[glob_len-2] = '\0';
}
}
}
else {
// Convert the glob to a true regular expression (Posix syntax)
size_t iter;
iter = 0;
// Add the opening bracket
if (with_brackets) {
glob_len += 1;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re glob expansion exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = uvm_re_bracket_char;
}
// ^ goes at the beginning...
if (*glob != '^') {
glob_len += 1;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re glob expansion exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = '^';
}
// Note that this for loop auto-terminates when '*p' is \0
for(p = glob; *p; p++) {
// Replace the glob metacharacters with corresponding regular
// expression metacharacters.
switch(*p)
{
// '.' Expansion
case '*':
case '+':
glob_len += 2;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re() expansion exceeds max length(%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = '.';
buffer[iter++] = *p;
break;
// Escape Expansion
case '.':
case '[':
case ']':
case '(':
case ')':
glob_len += 2;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re() expansion exceeds max length(%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = uvm_re_escape_char;
buffer[iter++] = *p;
break;
// '?' --> '.'
case '?':
buffer[iter++] = '.';
break;
// Default (copy char)
default:
buffer[iter++] = *p;
break;
}
}
// Let's check to see if the regular expression is bounded by ^ at
// the beginning and $ at the end. If not, add those characters in
// the appropriate position.
if (buffer[iter-1] != '$') {
glob_len += 1;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re glob expansion exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = '$';
}
if (with_brackets) {
glob_len += 1;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re glob expansion exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = uvm_re_bracket_char;
}
glob_len += 1;
if (glob_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_glob_to_re glob expansion exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
buffer[iter++] = '\0';
}
// vpi_printf("uvm_re_deglobbed(%s, %0d)\n-->%s\n", glob, with_brackets, buffer);
return buffer;
}
//--------------------------------------------------------------------
// uvm_re_free
//
// Frees a previously compiled regular expression.
//--------------------------------------------------------------------
void uvm_re_free(regex_ptr rexp)
{
if (rexp != NULL) {
regfree(rexp);
free(rexp);
}
// vpi_printf("uvm_re_free(%p)\n", rexp);
}
//--------------------------------------------------------------------
// uvm_re_comp
//
// Compiles a regular expression and returns pointer to the compiled
// expression. A return value of NULL indicates that there was
// an error during compilation, and the error information is available
// via uvm_re_err.
//
// Note that the regular expression is on the heap, and must be freed
// by the caller.
//--------------------------------------------------------------------
regex_ptr uvm_re_comp(const char* re, unsigned char deglob)
{
// vpi_printf("uvm_re_comp(%s)\n", re);
char* buffer = uvm_re_buffer();
// Optionally de-globify regular expression
const char* deglobbed;
if (deglob) {
deglobbed = uvm_re_deglobbed(re, false /* no brackets */);
} else {
// No glob, need to copy to buffer manually
size_t re_len;
re_len = strlen(re);
if (re_len > UVM_REGEX_MAX_LENGTH) {
sprintf(buffer, "uvm_re_comp() re exceeds max length (%0d)", UVM_REGEX_MAX_LENGTH);
return NULL;
}
else {
// Strip brackets if necessary
if (re[0] == uvm_re_bracket_char && re[re_len-1] == uvm_re_bracket_char) {
strncpy(buffer, &re[1], re_len-2);
buffer[re_len-2] = '\0';
deglobbed = buffer;
}
else {
deglobbed = re;
}
}
}
// Safety check. Args should never be ~null~ since this is called
// from DPI, but we'll check anyways.
if (deglobbed == NULL) {
// uvm_glob_to_re already set the debug buffer
return NULL;
}
// deglobbed is a const pointer to uvm_re_buffer, so never free it.
regex_ptr rexp;
rexp = (regex_ptr)malloc(sizeof(regex_t));
if (rexp == NULL) {
sprintf(buffer, "uvm_re_comp: internal memory allocation error");
return NULL;
}
int err;
err = regcomp(rexp, deglobbed, REG_EXTENDED);
if (err != 0) {
regerror(err, rexp, buffer, UVM_REGEX_MAX_LENGTH-1);
uvm_re_free(rexp);
return NULL;
}
// vpi_printf("uvm_re_comp(%s)\n-->%p\n", buffer, rexp);
return rexp;
}
//--------------------------------------------------------------------
// uvm_re_exec
//
// Match a string to a pre-compiled regular expression.
//--------------------------------------------------------------------
int uvm_re_exec(regex_ptr rexp, const char * str) {
// Safety check.
if (rexp == NULL) {
sprintf(uvm_re_buffer(), "uvm_re_exec: NULL rexp");
return REG_NOMATCH;
}
if (str == NULL) {
sprintf(uvm_re_buffer(), "uvm_re_exec: NULL str");
return REG_NOMATCH;
}
int retval;
retval = regexec(rexp, str, 0, NULL, 0);
// vpi_printf("uvm_re_exec(%p, %s)\n-->%0d\n", rexp, str, retval);
return retval;
}
//--------------------------------------------------------------------
// uvm_re_compexec
//
// Compiles a regular expression and executes it in a single operation.
// Reduces the number of necessary language boundary crossings from
// 2 to 1.
//
// Note that the regular expression is on the heap, and must be freed
// by the caller.
//--------------------------------------------------------------------
regex_ptr uvm_re_compexec(const char* re, const char* str, unsigned char deglob, int* exec_ret)
{
regex_ptr rexp;
rexp = uvm_re_comp(re, deglob);
if (rexp != NULL) {
// Successful compile
*exec_ret = uvm_re_exec(rexp, str);
}
else {
*exec_ret = REG_NOMATCH;
}
// vpi_printf("uvm_re_compexec(%s,%s,%0d)\n-->%p\n", re, str, *exec_ret, rexp);
return rexp;
}
//--------------------------------------------------------------------
// uvm_re_compexecfree
//
// Compiles a regular expression, executes and frees it in a single operation.
// Reduces the number of necessary language boundary crossings from
// 3 to 1.
//
// Returns 1 on successful execution, 0 on failure.
//--------------------------------------------------------------------
unsigned char uvm_re_compexecfree(const char* re, const char* str, unsigned char deglob, int* exec_ret)
{
regex_ptr rexp;
rexp = uvm_re_compexec(re, str, deglob, exec_ret);
unsigned char success = (rexp != NULL);
if (success) {
uvm_re_free(rexp);
}
// vpi_printf("uvm_re_compexecfree(%s,%s,%0d)\n-->%0d\n", re, str, *exec_ret, success);
return success;
}

View File

@ -0,0 +1,155 @@
//----------------------------------------------------------------------
// Copyright 2010-2018 Cadence Design Systems, Inc.
// Copyright 2010-2012 Mentor Graphics Corporation
// Copyright 2020-2024 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_regex.svh $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
`ifndef UVM_REGEX_NO_DPI
import "DPI-C" function string uvm_re_deglobbed(string glob, bit with_brackets);
import "DPI-C" function string uvm_re_buffer();
import "DPI-C" function void uvm_re_free(chandle rexp);
import "DPI-C" function chandle uvm_re_comp(string re, bit deglob);
import "DPI-C" function int uvm_re_exec(chandle rexp, string str);
import "DPI-C" function chandle uvm_re_compexec(string re, string str, bit deglob, output int exec_ret);
import "DPI-C" function bit uvm_re_compexecfree(string re, string str, bit deglob, output int exec_ret);
typedef class uvm_regex_cache;
// The uvm_re_match cache is disabled by default, to avoid
// potential issues with save-and-restore causing illegal c-side
// dereferencing. When enabled, uvm_re_match should be significantly
// faster.
`ifdef UVM_ENABLE_RE_MATCH_CACHE
function int uvm_re_match(string re, string str, bit deglob = 0);
uvm_regex_cache cache;
chandle cached[$];
int retval;
cache = uvm_regex_cache::get_inst();
cached = cache.get(re);
if (cached.size()) begin
// Cache hit, use pre-compiled regex
retval = uvm_re_exec(cached[0], str);
end
else begin
// Cache miss, compile and cache regex
chandle rexp;
rexp = uvm_re_compexec(re, str, deglob, retval);
if (rexp == null) begin
uvm_report_error("UVM/DPI/REGEX", uvm_re_buffer());
end
else begin
cache.put(re, rexp);
end
end // else: !if(cached.size())
return retval;
endfunction : uvm_re_match
`else // !`ifdef UVM_ENABLE_RE_MATCH_CACHE
function int uvm_re_match(string re, string str, bit deglob = 0);
int retval;
bit success;
success = uvm_re_compexecfree(re, str, deglob, retval);
if (!success) begin
uvm_report_error("UVM/DPI/REGEX", uvm_re_buffer());
end
return retval;
endfunction : uvm_re_match
`endif // !`ifdef UVM_ENABLE_RE_MATCH_CACHE
function string uvm_glob_to_re(string glob);
return uvm_re_deglobbed(glob, 1);
endfunction : uvm_glob_to_re
`else
// The Verilog only version does not match regular expressions,
// it only does glob style matching.
// NOTE: The deglob argument is unused in Verilog only mode,
// as it doesn't make any sense.
function int uvm_re_match(string re, string str, bit deglob = 0);
int e, es, s, ss;
string tmp;
e = 0; s = 0;
es = 0; ss = 0;
if(re.len() == 0)
return 0;
// The ^ used to be used to remove the implicit wildcard, but now we don't
// use implicit wildcard so this character is just stripped.
if(re[0] == "^")
re = re.substr(1, re.len()-1);
//This loop is only needed when the first character of the re may not
//be a *.
while (s != str.len() && re.getc(e) != "*") begin
if ((re.getc(e) != str.getc(s)) && (re.getc(e) != "?"))
return 1;
e++; s++;
end
while (s != str.len()) begin
if (re.getc(e) == "*") begin
e++;
if (e == re.len()) begin
return 0;
end
es = e;
ss = s+1;
end
else if (re.getc(e) == str.getc(s) || re.getc(e) == "?") begin
e++;
s++;
end
else begin
e = es;
s = ss++;
end
end
while (e < re.len() && re.getc(e) == "*")
e++;
if(e == re.len()) begin
return 0;
end
else begin
return 1;
end
endfunction
function string uvm_glob_to_re(string glob);
return glob;
endfunction
`endif

View File

@ -0,0 +1,107 @@
//
//------------------------------------------------------------------------------
// Copyright 2010-2012 AMD
// Copyright 2011-2018 Cadence Design Systems, Inc.
// Copyright 2011-2014 Mentor Graphics Corporation
// Copyright 2013-2024 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//------------------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_svcmd_dpi.c $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
#include "uvm_dpi.h"
#include <assert.h>
#define ARGV_STACK_PTR_SIZE 32
// the total number of arguments (minus the -f/-F minus associated filenames)
int argc_total;
// the ptr to the array of ptrs to the args
char** argv_stack=NULL;
char ** argv_ptr=NULL;
void push_data(int lvl,char *entry, int cmd) {
if(cmd==0)
argc_total++;
else
*argv_ptr++=entry;
}
// walk one level (potentially recursive)
void walk_level(int lvl, int argc, char**argv,int cmd) {
int idx;
for(idx=0; ((lvl==0) && idx<argc) || ((lvl>0) && (*argv));idx++,argv++) {
if(strcmp(*argv, "-f") && strcmp(*argv, "-F")) {
push_data(lvl,*argv,cmd);
} else {
argv++;
idx++;
char **n=(char**) *argv;
walk_level(lvl+1,argc,++n,cmd);
}
}
}
const char *uvm_dpi_get_next_arg_c (int init) {
s_vpi_vlog_info info;
static int idx=0;
if(init==1)
{
// free if necessary
free(argv_stack);
argc_total=0;
vpi_get_vlog_info(&info);
walk_level(0,info.argc,info.argv,0);
argv_stack = (char**) malloc (sizeof(char*)*argc_total);
argv_ptr=argv_stack;
walk_level(0,info.argc,info.argv,1);
idx=0;
argv_ptr=argv_stack;
}
if(idx++>=argc_total)
return NULL;
return *argv_ptr++;
}
extern char* uvm_dpi_get_tool_name_c ()
{
s_vpi_vlog_info info;
vpi_get_vlog_info(&info);
return info.product;
}
extern char* uvm_dpi_get_tool_version_c ()
{
s_vpi_vlog_info info;
vpi_get_vlog_info(&info);
return info.version;
}

View File

@ -0,0 +1,85 @@
//
//------------------------------------------------------------------------------
// Copyright 2010-2012 AMD
// Copyright 2013-2018 Cadence Design Systems, Inc.
// Copyright 2022 Marvell International Ltd.
// Copyright 2010-2011 Mentor Graphics Corporation
// Copyright 2020-2024 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//------------------------------------------------------------------------------
//----------------------------------------------------------------------
// Git details (see DEVELOPMENT.md):
//
// $File: src/dpi/uvm_svcmd_dpi.svh $
// $Rev: 2024-02-08 13:43:04 -0800 $
// $Hash: 29e1e3f8ee4d4aa2035dba1aba401ce1c19aa340 $
//
//----------------------------------------------------------------------
// Import DPI functions used by the interface to generate the
// lists.
`ifndef UVM_CMDLINE_NO_DPI
import "DPI-C" function string uvm_dpi_get_next_arg_c (int init);
import "DPI-C" function string uvm_dpi_get_tool_name_c ();
import "DPI-C" function string uvm_dpi_get_tool_version_c ();
function string uvm_dpi_get_next_arg(int init=0);
return uvm_dpi_get_next_arg_c(init);
endfunction
function string uvm_dpi_get_tool_name();
return uvm_dpi_get_tool_name_c();
endfunction
function string uvm_dpi_get_tool_version();
return uvm_dpi_get_tool_version_c();
endfunction
function chandle uvm_dpi_regcomp(string regex);
return uvm_re_comp(regex, .deglob(0));
endfunction
function int uvm_dpi_regexec(chandle preg, string str);
return uvm_re_exec(preg, str);
endfunction
function void uvm_dpi_regfree(chandle preg);
uvm_re_free(preg);
endfunction
`else
function string uvm_dpi_get_next_arg(int init=0);
return "";
endfunction
function string uvm_dpi_get_tool_name();
return "?";
endfunction
function string uvm_dpi_get_tool_version();
return "?";
endfunction
function chandle uvm_dpi_regcomp(string regex); return null; endfunction
function int uvm_dpi_regexec(chandle preg, string str); return 0; endfunction
function void uvm_dpi_regfree(chandle preg); endfunction
`endif