Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
./py/bin/pip install -U ivpm
./py/bin/python3 -m ivpm update -a
./packages/python/bin/pip install -U typing_extensions build
./packages/python/bin/pip install pcpp cxxheaderparser
./packages/python/bin/python3 setup.py build_ext --inplace
./packages/python/bin/python3 -m build -n
ls src
Expand Down
18 changes: 9 additions & 9 deletions ivpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ package:

dep-sets:

- name: default
deps:
- name: pytest
src: pypi
# - name: pyvsc-dataclasses
# src: pypi
- name: fusesoc
src: pypi

- name: default-dev
deps:
Expand All @@ -35,7 +27,6 @@ package:
url: https://github.com/dv-flow/dv-flow-libhdlsim.git
- name: dv-flow-mgr
url: https://github.com/dv-flow/dv-flow-mgr.git
branch: mballance/taskdeps
- name: verilator
url: https://github.com/edapack/verilator-bin
src: gh-rls
Expand Down Expand Up @@ -107,6 +98,15 @@ package:
- name: doxygen-filter-sv
url: https://github.com/SeanOBoyle/DoxygenFilterSystemVerilog.git

- name: default
deps:
- name: pytest
src: pypi
# - name: pyvsc-dataclasses
# src: pypi
- name: fusesoc
src: pypi

env:
- name: PATH
path-prepend:
Expand Down
15 changes: 10 additions & 5 deletions src/hdl_if/impl/call/gen_sv_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(self, out, ind="", uvm=False, deprecated=False):
self._deprecated = deprecated
self._have_imp = False
self._struct_types = set() # Track struct types used in API
self._emitted_struct_types = set() # Track struct types already emitted (across multiple gen() calls)
pass

def _collect_methods(self, api: ApiDef):
Expand Down Expand Up @@ -93,16 +94,20 @@ def gen(self, api : ApiDef):
# Collect struct types used in the API
self._collect_struct_types(api)

# Generate struct typedefs
if self._struct_types:
for struct_type in sorted(self._struct_types, key=lambda t: t.__name__):
# Generate struct typedefs only for types not already emitted
new_struct_types = self._struct_types - self._emitted_struct_types
if new_struct_types:
for struct_type in sorted(new_struct_types, key=lambda t: t.__name__):
self.gen_struct_typedef(struct_type)
self.println()

# Generate conversion functions for each struct
for struct_type in sorted(self._struct_types, key=lambda t: t.__name__):
# Generate conversion functions for each new struct
for struct_type in sorted(new_struct_types, key=lambda t: t.__name__):
self.gen_struct_conversion_functions(struct_type)
self.println()

self._emitted_struct_types.update(new_struct_types)
self._struct_types = set()

# Existing class generation (unchanged)
# self.gen_class_interface_exp(api)
Expand Down
2 changes: 1 addition & 1 deletion src/hdl_if/share/dpi/pyhdl_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ package pyhdl_if;
function automatic PyObject pyhdl_pi_if_HandleErr(PyObject obj);
if (obj == null) begin
$display("--> HandleErr");
$stacktrace;
`STACKTRACE;
PyErr_Print();
$display("<-- HandleErr");
end
Expand Down
4 changes: 4 additions & 0 deletions src/hdl_if/share/dpi/pyhdl_if_macros.svh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
$display x ; \
$finish ;

`ifdef XILINX_SIMULATOR
`define STACKTRACE $display("TODO: no stacktrace support in Xilinx simulator")
`else
`define STACKTRACE $stacktrace
`endif


`endif /* INCLUDED_PYHDL_IF_MACROS_SVH */
4 changes: 2 additions & 2 deletions tests/unit/data/test_struct/struct_bfm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ module struct_bfm
Point_t stored_point;

initial begin
StructBFM_Impl impl = new();
StructTest_exp_impl test;
automatic StructBFM_Impl impl = new();
automatic StructTest_exp_impl test;
int fd;
string line;

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/data/test_struct/struct_comprehensive_bfm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ module struct_comprehensive_bfm
ComprehensiveBFM_imp_impl#(ComprehensiveBFM_Impl) bfm;

initial begin
ComprehensiveBFM_Impl impl = new();
ComprehensiveTest_exp_impl test;
automatic ComprehensiveBFM_Impl impl = new();
automatic ComprehensiveTest_exp_impl test;
int fd;
string line;

Expand Down
42 changes: 42 additions & 0 deletions tests/unit/test_api_gen_sv_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,45 @@ def __init__(self):
assert len(filtered) == 3
names = [a.name for a in filtered]
assert names == ["First", "Second", "Third"]

def test_no_duplicate_struct_typedefs_across_apis(self):
"""Test that struct typedefs are not duplicated when multiple APIs share the same struct type."""

class Point(ct.Structure):
_fields_ = [
("x", ct.c_int32),
("y", ct.c_int32),
]

@api
class FirstAPI(object):
@imp
async def func1(self, pt: Point):
pass

@api
class SecondAPI(object):
@exp
def func2(self, pt: Point):
pass

all_apis = ApiDefRgy.inst().getApis()

out = io.StringIO()
gen = GenSVClass(out, ind="", uvm=False, deprecated=False)
for a in all_apis:
gen.gen(a)
sv_content = out.getvalue()

# Count occurrences of the struct typedef — must appear exactly once
typedef_count = sv_content.count("typedef struct")
assert typedef_count == 1, (
f"Expected 1 struct typedef for Point_t, but found {typedef_count}. "
f"Duplicate typedefs cause SV compilation errors."
)
# Conversion function definitions must also appear exactly once
# (the name may also appear in calls within API method bodies)
assert sv_content.count("function Point_t pyhdl_if_py_to_struct_Point") == 1, \
"pyhdl_if_py_to_struct_Point conversion function definition duplicated"
assert sv_content.count("function pyhdl_if::PyObject pyhdl_if_struct_to_py_Point") == 1, \
"pyhdl_if_struct_to_py_Point conversion function definition duplicated"
Loading