diff --git a/examples/vhdl/external_buffer/run.py b/examples/vhdl/external_buffer/run.py new file mode 100644 index 0000000000..6f13ce1d34 --- /dev/null +++ b/examples/vhdl/external_buffer/run.py @@ -0,0 +1,52 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# +# Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com + +""" +External Buffer + +Interfacing with foreign languages (C) through VHPIDIRECT: +https://ghdl.readthedocs.io/en/latest/using/Foreign.html + +An array of type ``uint8_t`` is allocated in a C application and some values +are written to the first ``1/3``positions. Then, the VHDL simulation is +executed, where the (external) array/buffer is used. + +In the VHDL testbenches, two vector pointers are created, each of them using +a different access mechanism (``id>0`` or ``id<0``). One of them is used to copy +the first ``1/3`` elements to positions ``[1/3, 2/3)``, while incrementing each value +by one. The second one is used to copy elements from ``[1/3, 2/3)`` to ``[2/3, 3/3)``, +while incrementing each value by two. + +When the simulation is finished, the C application checks whether data was successfully +copied/modified. The content of the buffer is printed both before and after the +simulation. +""" + +from vunit import VUnit +from os import popen +from os.path import join, dirname + + +src_path = join(dirname(__file__), 'src') + +c_obj = join(src_path, 'main.o') +# Compile C application to an object +print(popen(' '.join([ + 'gcc', '-fPIC', + '-c', join(src_path, 'main.c'), + '-o', c_obj +])).read()) + +# Enable the external feature for strings +ui = VUnit.from_argv(vhdl_standard='2008', external={'string': True}) + +lib = ui.add_library('lib') +lib.add_source_files(join(src_path, '*.vhd')) + +# Add the C object to the elaboration of GHDL +ui.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj]) + +ui.main() diff --git a/examples/vhdl/external_buffer/src/main.c b/examples/vhdl/external_buffer/src/main.c new file mode 100644 index 0000000000..8b69fc8f28 --- /dev/null +++ b/examples/vhdl/external_buffer/src/main.c @@ -0,0 +1,97 @@ +/* +External Buffer + +Interfacing with foreign languages (C) through VHPIDIRECT: +https://ghdl.readthedocs.io/en/latest/using/Foreign.html + +An array of type uint8_t is allocated and some values are written to the first 1/3 +positions. Then, the VHDL simulation is executed, where the (external) array/buffer +is used. When the simulation is finished, the results are checked. The content of +the buffer is printed both before and after the simulation. + +NOTE: This file is expected to be used along with tb_ext_byte_vector.vhd or tb_ext_string.vhd +*/ + +#include +#include +#include + +extern int ghdl_main (int argc, char **argv); + +uint8_t *D[1]; +const uint32_t length = 5; + +// Check procedure, to be executed when GHDL exits. +// The simulation is expected to copy the first 1/3 elements to positions [1/3, 2/3), +// while incrementing each value by one, and then copy elements from [1/3, 2/3) to +// [2/3, 3/3), while incrementing each value by two. +static void exit_handler(void) { + int i, j, z, k; + uint8_t expected, got; + k = 0; + for (j=0; j<3; j++) { + k += j; + for(i=0; i0) + +void write_char(uint8_t id, uint32_t i, uint8_t v ) { + //printf("C write_char(%d, %d): %d\n", id, i, v); + D[id][i] = v; +} + +uint8_t read_char(uint8_t id, uint32_t i) { + //printf("C read_char(%d, %d): %d\n", id, i, D[id][i]); + return D[id][i]; +} \ No newline at end of file diff --git a/examples/vhdl/external_buffer/src/tb_ext_byte_vector.vhd b/examples/vhdl/external_buffer/src/tb_ext_byte_vector.vhd new file mode 100644 index 0000000000..dda5ed7227 --- /dev/null +++ b/examples/vhdl/external_buffer/src/tb_ext_byte_vector.vhd @@ -0,0 +1,54 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com + +-- NOTE: This file is expected to be used along with foreign languages (C) +-- through VHPIDIRECT: https://ghdl.readthedocs.io/en/latest/using/Foreign.html +-- See main.c for an example of a wrapper application. + +--library vunit_lib; +--context vunit_lib.vunit_context; + +library vunit_lib; +use vunit_lib.run_pkg.all; +use vunit_lib.logger_pkg.all; +use vunit_lib.byte_vector_ptr_pkg.all; + +entity tb_external_byte_vector is + generic ( runner_cfg : string ); +end entity; + +architecture tb of tb_external_byte_vector is + + constant block_len : natural := 5; + + constant ebuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extfnc); -- external through VHPIDIRECT functions 'read_char' and 'write_char' + constant abuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extacc); -- external through access (requires VHPIDIRECT function 'get_string_ptr') + +begin + + main: process + variable val, ind: integer; + begin + test_runner_setup(runner, runner_cfg); + info("Init test"); + for x in 0 to block_len-1 loop + val := get(ebuf, x) + 1; + ind := block_len+x; + set(ebuf, ind, val); + info("SET " & to_string(ind) & ": " & to_string(val)); + end loop; + for x in block_len to 2*block_len-1 loop + val := get(abuf, x) + 2; + ind := block_len+x; + set(abuf, ind, val); + info("SET " & to_string(ind) & ": " & to_string(val)); + end loop; + info("End test"); + test_runner_cleanup(runner); + wait; + end process; + +end architecture; diff --git a/examples/vhdl/external_buffer/src/tb_ext_string.vhd b/examples/vhdl/external_buffer/src/tb_ext_string.vhd new file mode 100644 index 0000000000..5a81a0e930 --- /dev/null +++ b/examples/vhdl/external_buffer/src/tb_ext_string.vhd @@ -0,0 +1,54 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com + +-- NOTE: This file is expected to be used along with foreign languages (C) +-- through VHPIDIRECT: https://ghdl.readthedocs.io/en/latest/using/Foreign.html +-- See main.c for an example of a wrapper application. + +--library vunit_lib; +--context vunit_lib.vunit_context; + +library vunit_lib; +use vunit_lib.run_pkg.all; +use vunit_lib.logger_pkg.all; +use vunit_lib.string_ptr_pkg.all; + +entity tb_external_string is + generic ( runner_cfg : string ); +end entity; + +architecture tb of tb_external_string is + + constant block_len : natural := 5; + + constant ebuf: string_ptr_t := new_string_ptr( 3*block_len, extfnc); -- external through VHPIDIRECT functions 'read_char' and 'write_char' + constant abuf: string_ptr_t := new_string_ptr( 3*block_len, extacc); -- external through access (requires VHPIDIRECT function 'get_string_ptr') + +begin + + main: process + variable val, ind: integer; + begin + test_runner_setup(runner, runner_cfg); + info("Init test"); + for x in 1 to block_len loop + val := get(ebuf, x) + 1; + ind := block_len+x; + set(ebuf, ind, val); + info("SET " & to_string(ind) & ": " & to_string(val)); + end loop; + for x in block_len+1 to 2*block_len loop + val := get(abuf, x) + 2; + ind := block_len+x; + set(abuf, ind, val); + info("SET " & to_string(ind) & ": " & to_string(val)); + end loop; + info("End test"); + test_runner_cleanup(runner); + wait; + end process; + +end architecture; diff --git a/vunit/test/acceptance/test_external_run_scripts.py b/vunit/test/acceptance/test_external_run_scripts.py index 7c35588466..168fb70a32 100644 --- a/vunit/test/acceptance/test_external_run_scripts.py +++ b/vunit/test/acceptance/test_external_run_scripts.py @@ -16,7 +16,7 @@ import sys from vunit import ROOT from vunit.builtins import VHDL_PATH -from vunit.test.common import has_simulator, check_report, simulator_is +from vunit.test.common import has_simulator, check_report, simulator_is, simulator_check def simulator_supports_verilog(): @@ -115,6 +115,13 @@ def test_vhdl_array_axis_vcs_example_project(self): def test_vhdl_axi_dma_example_project(self): self.check(join(ROOT, "examples", "vhdl", "axi_dma", "run.py")) + @unittest.skipIf( + simulator_check(lambda simclass: not simclass.supports_vhpi()), + "This simulator/backend does not support interfacing with external C code" + ) + def test_vhdl_external_buffer_project(self): + self.check(join(ROOT, "examples", "vhdl", "external_buffer", "run.py")) + def test_vhdl_user_guide_example_project(self): self.check(join(ROOT, "examples", "vhdl", "user_guide", "run.py"), exit_code=1) check_report(self.report_file,