diff --git a/pymtl3/passes/backends/verilog/import_/VerilogVerilatorImportConfigs.py b/pymtl3/passes/backends/verilog/import_/VerilogVerilatorImportConfigs.py index 332c6ec00..b85492f17 100644 --- a/pymtl3/passes/backends/verilog/import_/VerilogVerilatorImportConfigs.py +++ b/pymtl3/passes/backends/verilog/import_/VerilogVerilatorImportConfigs.py @@ -333,6 +333,12 @@ def create_cc_cmd( s ): coverage = "-DVM_COVERAGE" if s.vl_coverage or \ s.vl_line_coverage or \ s.vl_toggle_coverage else "" + + # PP: try not to introduce GNU unique symbols to the shared library. + linker_version_script_filename = "verilator_import_linker_version_script.lds" + dir_to_version_script = os.path.abspath(os.path.dirname(__file__)) + ld_flags += f" -Wl,--version-script={os.path.join(dir_to_version_script, linker_version_script_filename)}" + return f"g++ {c_flags} {c_include_path} {ld_flags}"\ f" -o {out_file} {c_src_files} {ld_libs} {coverage}" diff --git a/pymtl3/passes/backends/verilog/import_/test/VRegTrace.v b/pymtl3/passes/backends/verilog/import_/test/VRegTrace.v index 745645538..b2fae4b5e 100644 --- a/pymtl3/passes/backends/verilog/import_/test/VRegTrace.v +++ b/pymtl3/passes/backends/verilog/import_/test/VRegTrace.v @@ -14,6 +14,8 @@ module test_VRegTrace( logic [512*8-1:0] q_str; `VC_TRACE_BEGIN begin + // PP: we should not use $ system tasks because + // they seem to be generating segfaults at end of pytest?? /* $display("q = %d\n", q); */ $sformat(q_str, "%d", q); vc_trace.append_str( trace_str, "q = " ); diff --git a/pymtl3/passes/backends/verilog/import_/verilator_import_linker_version_script.lds b/pymtl3/passes/backends/verilog/import_/verilator_import_linker_version_script.lds new file mode 100644 index 000000000..3fe73472d --- /dev/null +++ b/pymtl3/passes/backends/verilog/import_/verilator_import_linker_version_script.lds @@ -0,0 +1,11 @@ +VERS_0.1 { + global: + create_model; + destroy_model; + comb_eval; + seq_eval; + assert_en; + trace; + local: + *; +}; diff --git a/pymtl3/passes/backends/verilog/import_/verilator_wrapper_c_template.py b/pymtl3/passes/backends/verilog/import_/verilator_wrapper_c_template.py index 36f9a5140..b9a1d69a4 100644 --- a/pymtl3/passes/backends/verilog/import_/verilator_wrapper_c_template.py +++ b/pymtl3/passes/backends/verilog/import_/verilator_wrapper_c_template.py @@ -108,7 +108,8 @@ m = (V{component_name}_t *) malloc( sizeof(V{component_name}_t) ); model = new V{vl_component_name}(context_ptr); - m->model = (void *) model; + m->model = (void *) model; + m->context_ptr = context_ptr; // Enable tracing. We have added a feature where if the vcd_filename is // "" then we don't do any VCD dumping even if DUMP_VCD is true. @@ -161,6 +162,7 @@ #endif delete model; + delete m->context_ptr; free(m); @@ -226,7 +228,6 @@ // PP: now that we have generated the VCD we need to set CLK back to 0. // We need to dump VCD again to register this clock toggle. m->trace_time += {half_cycle_time}; - g_main_time += {half_cycle_time}; #if HAS_CLK model->clk = 0; @@ -253,7 +254,6 @@ // update simulation time only on clock toggle m->trace_time += {half_cycle_time}; - g_main_time += {half_cycle_time}; }} #endif @@ -323,7 +323,7 @@ assert( dut_scope ); svSetScope( dut_scope ); - model->line_trace( words ); + V{vl_component_name}::line_trace( words ); // Note that the way the line tracing works, the line tracing function // will store how the last character used in the line trace in the diff --git a/pymtl3/passes/backends/verilog/import_/verilator_wrapper_py_template.py b/pymtl3/passes/backends/verilog/import_/verilator_wrapper_py_template.py index d235b6451..bd54c3c96 100644 --- a/pymtl3/passes/backends/verilog/import_/verilator_wrapper_py_template.py +++ b/pymtl3/passes/backends/verilog/import_/verilator_wrapper_py_template.py @@ -9,7 +9,10 @@ normal PyMTL model. This template is based on PyMTL v2. """ +import copy import os +import gc +import weakref from cffi import FFI @@ -77,12 +80,15 @@ def finalize( s ): you might need to call `imported_object.finalize()` at the end of each test to ensure correct behaviors. """ + # print(f"In finalize() method of an instance of {{str(s.__class__)}}") assert s._finalization_count == 0,\ 'Imported component can only be finalized once!' s._finalization_count += 1 # Clean up python side FFI references - del s._line_trace_str + s.ffi.release(s._line_trace_str) + + s._convert_string = None s._ffi_inst.destroy_model( s._ffi_m ) s.ffi.dlclose( s._ffi_inst ) @@ -90,12 +96,17 @@ def finalize( s ): del s._ffi_inst del s.ffi + gc.collect() + # print("End of finalize()") + def __del__( s ): + # print(f"In __del__() method of an instance of {{str(s.__class__)}}") if s._finalization_count == 0: s._finalization_count += 1 # Clean up python side FFI references - del s._line_trace_str + s.ffi.release(s._line_trace_str) + s._convert_string = None s._ffi_inst.destroy_model( s._ffi_m ) s.ffi.dlclose( s._ffi_inst ) @@ -103,6 +114,9 @@ def __del__( s ): del s._ffi_inst del s.ffi + gc.collect() + # print("End of __del__") + def construct( s, *args, **kwargs ): # Set up the VCD file name verilator_vcd_file = "" @@ -123,9 +137,13 @@ def construct( s, *args, **kwargs ): s._ffi_m = s._ffi_inst.create_model( ffi_vl_vcd_file ) # Buffer for line tracing - s._line_trace_str = s.ffi.new('char[512]') + line_trace_str = s.ffi.new('char[512]') + s._line_trace_str = line_trace_str s._convert_string = s.ffi.string + global_weakref_dict = weakref.WeakKeyDictionary() + global_weakref_dict[s] = (line_trace_str) + # Use non-attribute varialbe to reduce CPython bytecode count _ffi_m = s._ffi_m _ffi_inst_comb_eval = s._ffi_inst.comb_eval