Tests: Add uvm-2020-3.2-vlt
This commit is contained in:
parent
92300ab675
commit
91216bdac1
4
Changes
4
Changes
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *-*
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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); }
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue