From 16f101eb7a57c6fc41bb1806baecb74586219a7b Mon Sep 17 00:00:00 2001 From: umarcor Date: Sun, 7 Apr 2019 06:35:50 +0200 Subject: [PATCH 1/5] feat: add external models to string_ptr --- vunit/builtins.py | 48 ++- vunit/ui.py | 23 +- vunit/verilog.py | 2 +- .../data_types/src/data_types_context.vhd | 2 +- .../src/external/external_string-body.vhd | 28 ++ .../src/external/external_string-novhpi.vhd | 24 ++ .../src/external/external_string-vhpi.vhd | 28 ++ .../src/string_ptr_pkg-body-2002p.vhd | 339 +++++++++++++----- .../data_types/src/string_ptr_pkg-body-93.vhd | 261 ++++++++++---- vunit/vhdl/data_types/src/string_ptr_pkg.vhd | 25 +- vunit/vhdl/data_types/src/types.vhd | 5 + 11 files changed, 609 insertions(+), 176 deletions(-) create mode 100644 vunit/vhdl/data_types/src/external/external_string-body.vhd create mode 100644 vunit/vhdl/data_types/src/external/external_string-novhpi.vhd create mode 100644 vunit/vhdl/data_types/src/external/external_string-vhpi.vhd diff --git a/vunit/builtins.py b/vunit/builtins.py index dfae54117..473119d06 100644 --- a/vunit/builtins.py +++ b/vunit/builtins.py @@ -12,6 +12,7 @@ from os.path import join, abspath, dirname, basename from glob import glob from vunit.vhdl_standard import VHDL +from vunit.test.common import simulator_check VHDL_PATH = abspath(join(dirname(__file__), "vhdl")) VERILOG_PATH = abspath(join(dirname(__file__), "verilog")) @@ -67,12 +68,48 @@ def _add_files(self, pattern): self._vunit_lib.add_source_file(file_name) - def _add_data_types(self): + def _add_data_types(self, external=None): """ - Add data types packages + Add data types packages (sources corresponding to VHPIDIRECT arrays, or their placeholders) + + :param external: struct to select whether to enable external models for 'string'. Allowed values are: + None, {'string': False}, {'string': True} or {'string': ['path/to/custom/file']}. """ self._add_files(join(VHDL_PATH, "data_types", "src", "*.vhd")) + use_ext = {'string': False} + files = {'string': None} + + if external: + for ind, val in external.items(): + if isinstance(val, bool): + use_ext[ind] = val + else: + use_ext[ind] = True + files[ind] = val + + for ind in use_ext: + if use_ext[ind] and simulator_check(lambda simclass: not simclass.supports_vhpi()): + raise RuntimeError("the selected simulator does not support VHPI; must use non-VHPI packages...") + + ext_path = join(VHDL_PATH, "data_types", "src", "external") + + def default_pkg(cond, type_str): + """ + Return name of VHDL file with default VHPIDIRECT foreign declarations. + """ + return join(ext_path, 'external_' + type_str + '-' + ('' if cond else 'no') + 'vhpi.vhd') + + if not files['string']: + files['string'] = [ + default_pkg(use_ext['string'], 'string'), + join(ext_path, "external_string-body.vhd") + ] + + for ind in files: + for name in files[ind]: + self._add_files(name) + def _add_array_util(self): """ Add array utility @@ -166,11 +203,14 @@ def add_verilog_builtins(self): """ self._vunit_lib.add_source_files(join(VERILOG_PATH, "vunit_pkg.sv")) - def add_vhdl_builtins(self): + def add_vhdl_builtins(self, external=None): """ Add vunit VHDL builtin libraries + + :param external: struct to select whether to enable external models for 'string'. Allowed values are: + None, {'string': False}, {'string': True} or {'string': ['path/to/custom/file']}. """ - self._add_data_types() + self._add_data_types(external=external) self._add_files(join(VHDL_PATH, "*.vhd")) for path in ("core", "logging", "string_ops", "check", "dictionary", "run", "path"): self._add_files(join(VHDL_PATH, path, "src", "*.vhd")) diff --git a/vunit/ui.py b/vunit/ui.py index 248e9ea6d..d16a15911 100644 --- a/vunit/ui.py +++ b/vunit/ui.py @@ -118,7 +118,7 @@ A list of PLI file names. ``ghdl.flags`` - Extra arguments passed to ``ghdl --elab-run`` command *before* executable specific flags. Must be a list of strings. + Extra arguments passed to ``ghdl --elab-run`` command *before* executable specific flags. Must be a list of strings. ``incisive.irun_sim_flags`` @@ -308,7 +308,11 @@ def from_argv(cls, argv=None, compile_builtins=True, vhdl_standard=None): """ args = VUnitCLI().parse_args(argv=argv) - return cls.from_args(args, compile_builtins=compile_builtins, vhdl_standard=vhdl_standard) + return cls.from_args( + args, + compile_builtins=compile_builtins, + vhdl_standard=vhdl_standard + ) @classmethod def from_args(cls, args, compile_builtins=True, vhdl_standard=None): @@ -323,9 +327,13 @@ def from_args(cls, args, compile_builtins=True, vhdl_standard=None): :param vhdl_standard: The VHDL standard used to compile files, if None the VUNIT_VHDL_STANDARD environment variable is used :returns: A :class:`.VUnit` object instance - """ - return cls(args, compile_builtins=compile_builtins, vhdl_standard=vhdl_standard) + """ + return cls( + args, + compile_builtins=compile_builtins, + vhdl_standard=vhdl_standard + ) def __init__(self, args, compile_builtins=True, vhdl_standard=None): self._args = args @@ -1079,11 +1087,14 @@ def _run_test(self, test_cases, report): no_color=self._args.no_color) runner.run(test_cases) - def add_builtins(self): + def add_builtins(self, external=None): """ Add vunit VHDL builtin libraries + + :param external: struct to select whether to enable external models for 'string'. Allowed values are: + None, {'string': False}, {'string': True} or {'string': ['path/to/custom/file']}. """ - self._builtins.add_vhdl_builtins() + self._builtins.add_vhdl_builtins(external=external) def add_com(self): """ diff --git a/vunit/verilog.py b/vunit/verilog.py index 56e769059..c0126361e 100644 --- a/vunit/verilog.py +++ b/vunit/verilog.py @@ -16,7 +16,7 @@ class VUnit(VUnitVHDL): VUnit Verilog interface """ - def add_builtins(self): # pylint: disable=arguments-differ + def add_builtins(self, external=None): # pylint: disable=arguments-differ """ Add vunit Verilog builtin libraries """ diff --git a/vunit/vhdl/data_types/src/data_types_context.vhd b/vunit/vhdl/data_types/src/data_types_context.vhd index b31fa7602..d1d1ab04c 100644 --- a/vunit/vhdl/data_types/src/data_types_context.vhd +++ b/vunit/vhdl/data_types/src/data_types_context.vhd @@ -6,10 +6,10 @@ context data_types_context is library vunit_lib; + use vunit_lib.types_pkg.all; use vunit_lib.integer_vector_ptr_pkg.all; use vunit_lib.integer_vector_ptr_pool_pkg.all; use vunit_lib.integer_array_pkg.all; - use vunit_lib.string_ptr_pkg.all; use vunit_lib.queue_pkg.all; use vunit_lib.queue_pool_pkg.all; use vunit_lib.string_ptr_pkg.all; diff --git a/vunit/vhdl/data_types/src/external/external_string-body.vhd b/vunit/vhdl/data_types/src/external/external_string-body.vhd new file mode 100644 index 000000000..2f451cf99 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/external_string-body.vhd @@ -0,0 +1,28 @@ +-- 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 + +package body external_string_pkg is + procedure write_char ( + id : integer; + i : integer; + v : character + )is begin + assert false report "VHPI write_char" severity failure; + end; + + impure function read_char ( + id : integer; + i : integer + ) return character is begin + assert false report "VHPI read_char" severity failure; + end; + + impure function get_ptr ( + id : integer + ) return extstring_access_t is begin + assert false report "VHPI get_string_ptr" severity failure; + end; +end package body; diff --git a/vunit/vhdl/data_types/src/external/external_string-novhpi.vhd b/vunit/vhdl/data_types/src/external/external_string-novhpi.vhd new file mode 100644 index 000000000..cc8d89ea9 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/external_string-novhpi.vhd @@ -0,0 +1,24 @@ +-- 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 + +use work.types_pkg.all; + +package external_string_pkg is + procedure write_char ( + id : integer; + i : integer; + v : character + ); + + impure function read_char ( + id : integer; + i : integer + ) return character; + + impure function get_ptr ( + id : integer + ) return extstring_access_t; +end package; diff --git a/vunit/vhdl/data_types/src/external/external_string-vhpi.vhd b/vunit/vhdl/data_types/src/external/external_string-vhpi.vhd new file mode 100644 index 000000000..d828c4b7b --- /dev/null +++ b/vunit/vhdl/data_types/src/external/external_string-vhpi.vhd @@ -0,0 +1,28 @@ +-- 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 + +use work.types_pkg.all; + +package external_string_pkg is + procedure write_char ( + id : integer; + i : integer; + v : character + ); + + impure function read_char ( + id : integer; + i : integer + ) return character; + + impure function get_ptr ( + id : integer + ) return extstring_access_t; + + attribute foreign of write_char : procedure is "VHPIDIRECT write_char"; + attribute foreign of read_char : function is "VHPIDIRECT read_char"; + attribute foreign of get_ptr : function is "VHPIDIRECT get_string_ptr"; +end package; diff --git a/vunit/vhdl/data_types/src/string_ptr_pkg-body-2002p.vhd b/vunit/vhdl/data_types/src/string_ptr_pkg-body-2002p.vhd index ab65f7d7b..a97c5b334 100644 --- a/vunit/vhdl/data_types/src/string_ptr_pkg-body-2002p.vhd +++ b/vunit/vhdl/data_types/src/string_ptr_pkg-body-2002p.vhd @@ -5,12 +5,18 @@ -- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com package body string_ptr_pkg is - type string_ptr_storage_t is protected - impure function new_string_ptr ( + type prot_storage_t is protected + impure function new_vector ( length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; value : val_t := val_t'low ) return natural; + impure function is_external ( + ref : natural + ) return boolean; + procedure deallocate ( ref : natural ); @@ -21,21 +27,15 @@ package body string_ptr_pkg is procedure set ( ref : natural; - index : natural; + index : positive; value : val_t ); impure function get ( ref : natural; - index : natural + index : positive ) return val_t; - procedure reallocate ( - ref : natural; - length : natural; - value : val_t := val_t'low - ); - procedure reallocate ( ref : natural; value : string @@ -53,81 +53,197 @@ package body string_ptr_pkg is ) return string; end protected; - type string_ptr_storage_t is protected body - variable current_index : integer := 0; - variable ptrs : vava_t := null; + type prot_storage_t is protected body + type storage_t is record + id : integer; + mode : storage_mode_t; + length : integer; + end record; + constant null_storage : storage_t := (integer'low, internal, integer'low); + + type storage_vector_t is array (natural range <>) of storage_t; + type storage_vector_access_t is access storage_vector_t; + + type ptr_storage is record + idx : natural; + ptr : natural; + eptr : natural; + idxs : storage_vector_access_t; + ptrs : vava_t; + eptrs : evava_t; + end record; + + variable st : ptr_storage := (0, 0, 0, null, null, null); + + procedure reallocate_ptrs ( + acc : inout vava_t; + length : integer + ) is + variable old : vava_t := acc; + begin + if old = null then + acc := new vav_t'(0 => null); + elsif old'length <= length then + -- Reallocate ptr pointers to larger ptr; use more size to trade size for speed + acc := new vav_t'(0 to acc'length + 2**16 => null); + for i in old'range loop acc(i) := old(i); end loop; + deallocate(old); + end if; + end; + + procedure reallocate_eptrs ( + acc : inout evava_t; + length : integer + ) is + variable old : evava_t := acc; + begin + if old = null then + acc := new evav_t'(0 => null); + elsif old'length <= length then + acc := new evav_t'(0 to acc'length + 2**16 => null); + for i in old'range loop acc(i) := old(i); end loop; + deallocate(old); + end if; + end; + + procedure reallocate_idxs ( + acc : inout storage_vector_access_t; + length : integer + ) is + variable old : storage_vector_access_t := acc; + begin + if old = null then + acc := new storage_vector_t(0 to 0); + elsif old'length <= length then + acc := new storage_vector_t(0 to acc'length + 2**16); + for i in old'range loop acc(i) := old(i); end loop; + deallocate(old); + end if; + end; - impure function new_string_ptr ( + impure function new_vector ( length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; value : val_t := val_t'low - ) return natural is - variable old_ptrs : string_access_vector_access_t; - begin - if ptrs = null then - ptrs := new vav_t'(0 => null); - elsif ptrs'length <= current_index then - -- Reallocate ptr pointers to larger ptr - -- Use more size to trade size for speed - old_ptrs := ptrs; - ptrs := new vav_t'(0 to ptrs'length + 2**16 => null); - for i in old_ptrs'range loop - ptrs(i) := old_ptrs(i); - end loop; - deallocate(old_ptrs); + ) return natural is begin + reallocate_idxs(st.idxs, st.idx); + if mode = internal then + assert eid = -1 report "mode internal: id/=-1 not supported" severity error; + else + assert eid /= -1 report "mode external: id must be natural" severity error; end if; - ptrs(current_index) := new string'(1 to length => value); - current_index := current_index + 1; - return current_index-1; + case mode is + when internal => + st.idxs(st.idx) := ( + id => st.ptr, + mode => internal, + length => 0 + ); + reallocate_ptrs(st.ptrs, st.ptr); + st.ptrs(st.ptr) := new vec_t'(1 to length => value); + st.ptr := st.ptr + 1; + when extacc => + st.idxs(st.idx) := ( + id => st.eptr, + mode => extacc, + length => length + ); + reallocate_eptrs(st.eptrs, st.eptr); + st.eptrs(st.eptr) := get_ptr(eid); + st.eptr := st.eptr + 1; + when extfnc => + st.idxs(st.idx) := ( + id => eid, + mode => extfnc, + length => length + ); + end case; + st.idx := st.idx + 1; + return st.idx-1; end; - procedure deallocate ( + impure function is_external ( ref : natural + ) return boolean is begin + return st.idxs(ref).mode /= internal; + end; + + -- @TODO Remove check_external when all the functions/procedures are implemented + procedure check_external ( + ref : natural; + s : string ) is begin - deallocate(ptrs(ref)); - ptrs(ref) := null; + assert not is_external(ref) report s & " not implemented for external model" severity error; + end; + + procedure deallocate ( + ref : natural + ) is + variable s : storage_t := st.idxs(ref); + begin + -- @TODO Implement deallocate for external models + check_external(ref, "deallocate"); + deallocate(st.ptrs(s.id)); + st.ptrs(s.id) := null; end; impure function length ( ref : natural - ) return integer is begin - return ptrs(ref)'length; + ) return integer is + variable s : storage_t := st.idxs(ref); + begin + case s.mode is + when internal => return st.ptrs(s.id)'length; + when others => return abs(s.length); + end case; end; procedure set ( ref : natural; - index : natural; + index : positive; value : val_t - ) is begin - ptrs(ref)(index) := value; + ) is + variable s : storage_t := st.idxs(ref); + begin + case s.mode is + when extfnc => write_char(s.id, index-1, value); + when extacc => st.eptrs(s.id)(index) := value; + when internal => st.ptrs(s.id)(index) := value; + end case; end; impure function get ( ref : natural; - index : natural - ) return val_t is begin - return ptrs(ref)(index); - end; - - procedure reallocate ( - ref : natural; - length : natural; - value : val_t := val_t'low - ) is - variable old_ptr, new_ptr : string_access_t; + index : positive + ) return val_t is + variable s : storage_t := st.idxs(ref); begin - deallocate(ptrs(ref)); - ptrs(ref) := new string'(1 to length => value); + case s.mode is + when extfnc => return read_char(s.id, index-1); + when extacc => return st.eptrs(s.id)(index); + when internal => return st.ptrs(s.id)(index); + end case; end; procedure reallocate ( ref : natural; - value : string + value : vec_t ) is - variable old_ptr, new_ptr : string_access_t; - variable n_value : string(1 to value'length) := value; + variable s : storage_t := st.idxs(ref); + variable n_value : vec_t(1 to value'length) := value; begin - deallocate(ptrs(ref)); - ptrs(ref) := new string'(n_value); + case s.mode is + when extfnc => + -- @FIXME The reallocation request is just ignored. What should we do here? + --check_external(ptr, "reallocate"); + when extacc => + -- @TODO Implement reallocate for external models (through access) + check_external(ref, "reallocate"); + when internal => + deallocate(st.ptrs(s.id)); + st.ptrs(s.id) := new vec_t'(n_value); + end case; end; procedure resize ( @@ -136,30 +252,45 @@ package body string_ptr_pkg is drop : natural := 0; value : val_t := val_t'low ) is - variable old_ptr, new_ptr : string_access_t; - variable min_length : natural := length; + variable oldp, newp : string_access_t; + variable min_len : natural := length; + variable s : storage_t := st.idxs(ref); begin - new_ptr := new string'(1 to length => value); - old_ptr := ptrs(ref); - if min_length > old_ptr'length - drop then - min_length := old_ptr'length - drop; - end if; - for i in 1 to min_length loop - new_ptr(i) := old_ptr(drop + i); - end loop; - ptrs(ref) := new_ptr; - deallocate(old_ptr); + case s.mode is + when internal => + newp := new vec_t'(1 to length => value); + oldp := st.ptrs(s.id); + if min_len > oldp'length - drop then + min_len := oldp'length - drop; + end if; + for i in 1 to min_len loop + newp(i) := oldp(drop + i); + end loop; + st.ptrs(s.id) := newp; + deallocate(oldp); + when others => + -- @TODO Implement resize for external models + check_external(ref, "resize"); + end case; end; impure function to_string ( ref : natural - ) return string is begin - return ptrs(ref).all; + ) return string is + variable s : storage_t := st.idxs(ref); + begin + case s.mode is + when internal => + return st.ptrs(s.id).all; + when others => + -- @TODO Implement to_string for external models + check_external(ref, "to_string"); + end case; end; end protected body; - shared variable string_ptr_storage : string_ptr_storage_t; + shared variable vec_ptr_storage : prot_storage_t; function to_integer ( value : ptr_t @@ -176,64 +307,80 @@ package body string_ptr_pkg is impure function new_string_ptr ( length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; value : val_t := val_t'low ) return ptr_t is begin - return (ref => string_ptr_storage.new_string_ptr(length, value)); + return (ref => vec_ptr_storage.new_vector( + length => length, + mode => mode, + value => value, + eid => eid + )); end; impure function new_string_ptr ( - value : string + value : string; + mode : storage_mode_t := internal; + eid : index_t := -1 ) return ptr_t is - variable result : ptr_t := new_string_ptr(value'length); + variable ptr : string_ptr_t := new_string_ptr(value'length, mode, eid, val_t'low); variable n_value : string(1 to value'length) := value; begin for i in 1 to n_value'length loop - set(result, i, n_value(i)); + set(ptr, i, n_value(i)); end loop; - return result; + return ptr; + end; + + impure function is_external ( + ptr : ptr_t + ) return boolean is begin + return vec_ptr_storage.is_external(ptr.ref); end; procedure deallocate ( ptr : ptr_t - ) is - begin - string_ptr_storage.deallocate(ptr.ref); + ) is begin + vec_ptr_storage.deallocate(ptr.ref); end; impure function length ( ptr : ptr_t ) return integer is begin - return string_ptr_storage.length(ptr.ref); + return vec_ptr_storage.length(ptr.ref); end; procedure set ( ptr : ptr_t; - index : natural; + index : positive; value : val_t ) is begin - string_ptr_storage.set(ptr.ref, index, value); + vec_ptr_storage.set(ptr.ref, index, value); end; impure function get ( - ptr : ptr_t; - index : natural + ptr : ptr_t; + index : positive ) return val_t is begin - return string_ptr_storage.get(ptr.ref, index); + return vec_ptr_storage.get(ptr.ref, index); end; procedure reallocate ( - ptr : ptr_t; + ptr : ptr_t; length : natural; value : val_t := val_t'low - ) is begin - string_ptr_storage.reallocate(ptr.ref, length, value); + ) is + variable n_value : string(1 to length) := (1 to length => value); + begin + vec_ptr_storage.reallocate(ptr.ref, n_value); end; procedure reallocate ( ptr : ptr_t; - value : string + value : vec_t ) is begin - string_ptr_storage.reallocate(ptr.ref, value); + vec_ptr_storage.reallocate(ptr.ref, value); end; procedure resize ( @@ -242,13 +389,13 @@ package body string_ptr_pkg is drop : natural := 0; value : val_t := val_t'low ) is begin - string_ptr_storage.resize(ptr.ref, length, drop, value); + vec_ptr_storage.resize(ptr.ref, length, drop, value); end; impure function to_string ( ptr : ptr_t ) return string is begin - return string_ptr_storage.to_string(ptr.ref); + return vec_ptr_storage.to_string(ptr.ref); end; function encode ( @@ -261,15 +408,15 @@ package body string_ptr_pkg is code : string ) return ptr_t is variable ret_val : ptr_t; - variable index : positive := code'left; + variable index : positive := code'left; begin decode(code, index, ret_val); return ret_val; end; procedure decode ( - constant code : string; - variable index : inout positive; + constant code : string; + variable index : inout positive; variable result : out ptr_t ) is begin decode(code, index, result.ref); diff --git a/vunit/vhdl/data_types/src/string_ptr_pkg-body-93.vhd b/vunit/vhdl/data_types/src/string_ptr_pkg-body-93.vhd index 3b0811f78..b1c3a3b45 100644 --- a/vunit/vhdl/data_types/src/string_ptr_pkg-body-93.vhd +++ b/vunit/vhdl/data_types/src/string_ptr_pkg-body-93.vhd @@ -5,59 +5,185 @@ -- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com package body string_ptr_pkg is - shared variable current_index : integer := 0; - shared variable ptrs : vava_t := null; + type storage_t is record + id : integer; + mode : storage_mode_t; + length : integer; + end record; + constant null_storage : storage_t := (integer'low, internal, integer'low); + + type storage_vector_t is array (natural range <>) of storage_t; + type storage_vector_access_t is access storage_vector_t; + + type ptr_storage is record + idx : natural; + ptr : natural; + eptr : natural; + idxs : storage_vector_access_t; + ptrs : vava_t; + eptrs : evava_t; + end record; + + shared variable st : ptr_storage := (0, 0, 0, null, null, null); + + procedure reallocate_ptrs ( + acc : inout vava_t; + length : integer + ) is + variable old : vava_t := acc; + begin + if old = null then + acc := new vav_t'(0 => null); + elsif old'length <= length then + -- Reallocate ptr pointers to larger ptr; use more size to trade size for speed + acc := new vav_t'(0 to acc'length + 2**16 => null); + for i in old'range loop acc(i) := old(i); end loop; + deallocate(old); + end if; + end; + + procedure reallocate_eptrs ( + acc : inout evava_t; + length : integer + ) is + variable old : evava_t := acc; + begin + if old = null then + acc := new evav_t'(0 => null); + elsif old'length <= length then + acc := new evav_t'(0 to acc'length + 2**16 => null); + for i in old'range loop acc(i) := old(i); end loop; + deallocate(old); + end if; + end; + + procedure reallocate_ids ( + acc : inout storage_vector_access_t; + length : integer + ) is + variable old : storage_vector_access_t := acc; + begin + if old = null then + acc := new storage_vector_t(0 to 0); + elsif old'length <= length then + acc := new storage_vector_t(0 to acc'length + 2**16); + for i in old'range loop acc(i) := old(i); end loop; + deallocate(old); + end if; + end; impure function new_string_ptr ( length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; value : val_t := val_t'low + ) return ptr_t is begin + reallocate_ids(st.idxs, st.idx); + case mode is + when internal => + st.idxs(st.idx) := ( + id => st.ptr, + mode => internal, + length => 0 + ); + reallocate_ptrs(st.ptrs, st.ptr); + st.ptrs(st.ptr) := new vec_t'(1 to length => value); + st.ptr := st.ptr + 1; + when extacc => + st.idxs(st.idx) := ( + id => st.eptr, + mode => extacc, + length => length + ); + reallocate_eptrs(st.eptrs, st.eptr); + st.eptrs(st.eptr) := get_ptr(eid); + st.eptr := st.eptr + 1; + when extfnc => + st.idxs(st.idx) := ( + id => eid, + mode => extfnc, + length => length + ); + end case; + st.idx := st.idx + 1; + return (ref => st.idx-1); + end; + + impure function new_string_ptr ( + value : string; + mode : storage_mode_t := internal; + eid : index_t := -1 ) return ptr_t is - variable old_ptrs : vava_t; - variable retval : ptr_t := (ref => current_index); + variable ptr : string_ptr_t := new_string_ptr(value'length, mode, eid, character'low); + variable n_value : string(1 to value'length) := value; begin - if ptrs = null then - ptrs := new vav_t'(0 => null); - elsif ptrs'length <= current_index then - -- Reallocate ptr pointers to larger ptr - -- Use more size to trade size for speed - old_ptrs := ptrs; - ptrs := new vav_t'(0 to ptrs'length + 2**16 => null); - for i in old_ptrs'range loop - ptrs(i) := old_ptrs(i); - end loop; - deallocate(old_ptrs); - end if; - ptrs(current_index) := new string'(1 to length => value); - current_index := current_index + 1; - return retval; + for i in 1 to n_value'length loop + set(ptr, i, n_value(i)); + end loop; + return ptr; end; - procedure deallocate ( + impure function is_external ( ptr : ptr_t + ) return boolean is begin + return st.idxs(ptr.ref).mode /= internal; + end; + + -- @TODO Remove check_external when all the functions/procedures are implemented + procedure check_external ( + ptr : ptr_t; + s : string ) is begin - deallocate(ptrs(ptr.ref)); - ptrs(ptr.ref) := null; + assert not is_external(ptr) report s & " not implemented for external model" severity error; + end; + + procedure deallocate ( + ptr : ptr_t + ) is + variable s : storage_t := st.idxs(ptr.ref); + begin + -- @TODO Implement deallocate for external models + check_external(ptr, "deallocate"); + deallocate(st.ptrs(s.id)); + st.ptrs(s.id) := null; end; impure function length ( ptr : ptr_t - ) return integer is begin - return ptrs(ptr.ref)'length; + ) return integer is + variable s : storage_t := st.idxs(ptr.ref); + begin + case s.mode is + when internal => return st.ptrs(s.id)'length; + when others => return abs(s.length); + end case; end; procedure set ( ptr : ptr_t; - index : natural; + index : positive; value : val_t - ) is begin - ptrs(ptr.ref)(index) := value; + ) is + variable s : storage_t := st.idxs(ptr.ref); + begin + case s.mode is + when extfnc => write_char(s.id, index-1, value); + when extacc => st.eptrs(s.id)(index) := value; + when internal => st.ptrs(s.id)(index) := value; + end case; end; impure function get ( ptr : ptr_t; - index : natural - ) return val_t is begin - return ptrs(ptr.ref)(index); + index : positive + ) return val_t is + variable s : storage_t := st.idxs(ptr.ref); + begin + case s.mode is + when extfnc => return read_char(s.id, index-1); + when extacc => return st.eptrs(s.id)(index); + when internal => return st.ptrs(s.id)(index); + end case; end; procedure reallocate ( @@ -65,21 +191,29 @@ package body string_ptr_pkg is length : natural; value : val_t := val_t'low ) is - variable old_ptr, new_ptr : string_access_t; + variable n_value : string(1 to length) := (1 to length => value); begin - deallocate(ptrs(ptr.ref)); - ptrs(ptr.ref) := new string'(1 to length => value); + reallocate(ptr, n_value); end; procedure reallocate ( ptr : ptr_t; value : string ) is - variable old_ptr, new_ptr : string_access_t; + variable s : storage_t := st.idxs(ptr.ref); variable n_value : string(1 to value'length) := value; begin - deallocate(ptrs(ptr.ref)); - ptrs(ptr.ref) := new string'(n_value); + case s.mode is + when extfnc => + -- @FIXME The reallocation request is just ignored. What should we do here? + --check_external(ptr, "reallocate"); + when extacc => + -- @TODO Implement reallocate for external models (through access) + check_external(ptr, "reallocate"); + when internal => + deallocate(st.ptrs(s.id)); + st.ptrs(s.id) := new vec_t'(n_value); + end case; end; procedure resize ( @@ -88,25 +222,40 @@ package body string_ptr_pkg is drop : natural := 0; value : val_t := val_t'low ) is - variable old_ptr, new_ptr : string_access_t; - variable min_length : natural := length; + variable oldp, newp : string_access_t; + variable min_len : natural := length; + variable s : storage_t := st.idxs(ptr.ref); begin - new_ptr := new string'(1 to length => value); - old_ptr := ptrs(ptr.ref); - if min_length > old_ptr'length - drop then - min_length := old_ptr'length - drop; - end if; - for i in 1 to min_length loop - new_ptr(i) := old_ptr(drop + i); - end loop; - ptrs(ptr.ref) := new_ptr; - deallocate(old_ptr); + case s.mode is + when internal => + newp := new vec_t'(1 to length => value); + oldp := st.ptrs(s.id); + if min_len > oldp'length - drop then + min_len := oldp'length - drop; + end if; + for i in 1 to min_len loop + newp(i) := oldp(drop + i); + end loop; + st.ptrs(s.id) := newp; + deallocate(oldp); + when others => + -- @TODO Implement resize for external models + check_external(ptr, "resize"); + end case; end; impure function to_string ( ptr : ptr_t - ) return string is begin - return ptrs(ptr.ref).all; + ) return string is + variable s : storage_t := st.idxs(ptr.ref); + begin + case s.mode is + when internal => + return st.ptrs(s.id).all; + when others => + -- @TODO Implement to_string for external models + check_external(ptr, "to_string"); + end case; end; function to_integer ( @@ -122,18 +271,6 @@ package body string_ptr_pkg is return (ref => value); end; - impure function new_string_ptr ( - value : string - ) return ptr_t is - variable result : ptr_t := new_string_ptr(value'length); - variable n_value : string(1 to value'length) := value; - begin - for i in 1 to n_value'length loop - set(result, i, n_value(i)); - end loop; - return result; - end; - function encode ( data : ptr_t ) return string is begin diff --git a/vunit/vhdl/data_types/src/string_ptr_pkg.vhd b/vunit/vhdl/data_types/src/string_ptr_pkg.vhd index 65d84020d..b20e256ba 100644 --- a/vunit/vhdl/data_types/src/string_ptr_pkg.vhd +++ b/vunit/vhdl/data_types/src/string_ptr_pkg.vhd @@ -11,11 +11,13 @@ -- use work.types_pkg.all; +use work.external_string_pkg.all; + use work.codec_pkg.all; use work.codec_builder_pkg.all; package string_ptr_pkg is - subtype index_t is integer range -1 to integer'high; + type string_ptr_t is record ref : index_t; end record; @@ -23,8 +25,11 @@ package string_ptr_pkg is alias ptr_t is string_ptr_t; alias val_t is character; + alias vec_t is string; alias vav_t is string_access_vector_t; + alias evav_t is extstring_access_vector_t; alias vava_t is string_access_vector_access_t; + alias evava_t is extstring_access_vector_access_t; function to_integer ( value : ptr_t @@ -36,13 +41,21 @@ package string_ptr_pkg is impure function new_string_ptr ( length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; value : val_t := val_t'low ) return ptr_t; impure function new_string_ptr ( - value : string + value : string; + mode : storage_mode_t := internal; + eid : index_t := -1 ) return ptr_t; + impure function is_external ( + ptr : ptr_t + ) return boolean; + procedure deallocate ( ptr : ptr_t ); @@ -53,13 +66,13 @@ package string_ptr_pkg is procedure set ( ptr : ptr_t; - index : natural; + index : positive; value : val_t ); impure function get ( ptr : ptr_t; - index : natural + index : positive ) return val_t; procedure reallocate ( @@ -70,14 +83,14 @@ package string_ptr_pkg is procedure reallocate ( ptr : ptr_t; - value : string + value : vec_t ); procedure resize ( ptr : ptr_t; length : natural; drop : natural := 0; - value : val_t := val_t'low + value : val_t := val_t'low ); impure function to_string ( diff --git a/vunit/vhdl/data_types/src/types.vhd b/vunit/vhdl/data_types/src/types.vhd index 7e0667320..04d8b1057 100644 --- a/vunit/vhdl/data_types/src/types.vhd +++ b/vunit/vhdl/data_types/src/types.vhd @@ -6,11 +6,16 @@ package types_pkg is subtype byte_t is integer range 0 to 255; + type storage_mode_t is (internal, extfnc, extacc); type string_access_t is access string; type string_access_vector_t is array (natural range <>) of string_access_t; type string_access_vector_access_t is access string_access_vector_t; + type extstring_access_t is access string(1 to integer'high); + type extstring_access_vector_t is array (natural range <>) of extstring_access_t; + type extstring_access_vector_access_t is access extstring_access_vector_t; + type integer_vector_t is array (natural range <>) of integer; type integer_vector_access_t is access integer_vector_t; type integer_vector_access_vector_t is array (natural range <>) of integer_vector_access_t; From 27c6014e8093f8b75dca8cfa2306219b158d3205 Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 3 Jun 2019 21:52:18 +0200 Subject: [PATCH 2/5] add byte_vector_* as an alias of string_* --- .../data_types/src/byte_vector_ptr_pkg.vhd | 103 ++++++++++++++++++ .../data_types/src/data_types_context.vhd | 1 + vunit/vhdl/data_types/src/types.vhd | 9 ++ .../data_types/test/tb_byte_vector_ptr.vhd | 46 ++++++++ 4 files changed, 159 insertions(+) create mode 100644 vunit/vhdl/data_types/src/byte_vector_ptr_pkg.vhd create mode 100644 vunit/vhdl/data_types/test/tb_byte_vector_ptr.vhd diff --git a/vunit/vhdl/data_types/src/byte_vector_ptr_pkg.vhd b/vunit/vhdl/data_types/src/byte_vector_ptr_pkg.vhd new file mode 100644 index 000000000..fa85528c4 --- /dev/null +++ b/vunit/vhdl/data_types/src/byte_vector_ptr_pkg.vhd @@ -0,0 +1,103 @@ +-- 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 +-- +-- The purpose of this package is to provide a byte vector access type (pointer) +-- that can itself be used in arrays and returned from functions unlike a +-- real access type. This is achieved by letting the actual value be a handle +-- into a singleton datastructure of string access types. +-- + +use work.types_pkg.all; +use work.string_ptr_pkg.all; + +package byte_vector_ptr_pkg is + + alias val_t is byte_t; + + alias storage_mode_t is work.string_ptr_pkg.storage_mode_t; + alias byte_vector_ptr_t is string_ptr_t; + alias null_byte_vector_ptr is null_string_ptr; + + alias new_byte_vector_ptr is new_string_ptr[string, storage_mode_t, integer return ptr_t]; + + alias is_external is is_external[ptr_t return boolean]; + alias deallocate is deallocate[ptr_t]; + alias length is length[ptr_t return integer]; + + impure function new_byte_vector_ptr ( + length : natural := 0; + mode : storage_mode_t := internal; + id : integer := 0; + value : val_t := 0 + ) return ptr_t; + + procedure set ( + ptr : ptr_t; + index : natural; + value : val_t + ); + + impure function get ( + ptr : ptr_t; + index : natural + ) return val_t; + + procedure reallocate ( + ptr : ptr_t; + length : natural; + value : val_t := 0 + ); + + procedure resize ( + ptr : ptr_t; + length : natural; + drop : natural := 0; + value : val_t := 0 + ); +end package; + +package body byte_vector_ptr_pkg is + impure function new_byte_vector_ptr ( + length : natural := 0; + mode : storage_mode_t := internal; + id : integer := 0; + value : val_t := 0 + ) return ptr_t is begin + return work.string_ptr_pkg.new_string_ptr(length, mode, id, character'val(value)); + end; + + procedure set ( + ptr : ptr_t; + index : natural; + value : val_t + ) is begin + work.string_ptr_pkg.set(ptr, index+1, character'val(value)); + end; + + impure function get ( + ptr : ptr_t; + index : natural + ) return val_t is begin + return character'pos(work.string_ptr_pkg.get(ptr, index+1)); + end; + + procedure reallocate ( + ptr : ptr_t; + length : natural; + value : val_t := 0 + ) is begin + work.string_ptr_pkg.reallocate(ptr, length, character'val(value)); + end; + + procedure resize ( + ptr : ptr_t; + length : natural; + drop : natural := 0; + value : val_t := 0 + ) is begin + work.string_ptr_pkg.resize(ptr, length, drop, character'val(value)); + end; +end package body; diff --git a/vunit/vhdl/data_types/src/data_types_context.vhd b/vunit/vhdl/data_types/src/data_types_context.vhd index d1d1ab04c..61d5f2cc0 100644 --- a/vunit/vhdl/data_types/src/data_types_context.vhd +++ b/vunit/vhdl/data_types/src/data_types_context.vhd @@ -14,5 +14,6 @@ context data_types_context is use vunit_lib.queue_pool_pkg.all; use vunit_lib.string_ptr_pkg.all; use vunit_lib.string_ptr_pool_pkg.all; + use vunit_lib.byte_vector_ptr_pkg.all; use vunit_lib.dict_pkg.all; end context; diff --git a/vunit/vhdl/data_types/src/types.vhd b/vunit/vhdl/data_types/src/types.vhd index 04d8b1057..0af994658 100644 --- a/vunit/vhdl/data_types/src/types.vhd +++ b/vunit/vhdl/data_types/src/types.vhd @@ -16,8 +16,17 @@ package types_pkg is type extstring_access_vector_t is array (natural range <>) of extstring_access_t; type extstring_access_vector_access_t is access extstring_access_vector_t; + alias byte_vector_access_t is string_access_t; + alias byte_vector_access_vector_t is string_access_vector_t; + alias byte_vector_access_vector_access_t is string_access_vector_access_t; + + alias extbytevec_access_t is extstring_access_t; + alias extbytevec_access_vector_t is extstring_access_vector_t; + alias extbytevec_access_vector_access_t is extstring_access_vector_access_t; + type integer_vector_t is array (natural range <>) of integer; type integer_vector_access_t is access integer_vector_t; type integer_vector_access_vector_t is array (natural range <>) of integer_vector_access_t; type integer_vector_access_vector_access_t is access integer_vector_access_vector_t; end package; + diff --git a/vunit/vhdl/data_types/test/tb_byte_vector_ptr.vhd b/vunit/vhdl/data_types/test/tb_byte_vector_ptr.vhd new file mode 100644 index 000000000..12756e98c --- /dev/null +++ b/vunit/vhdl/data_types/test/tb_byte_vector_ptr.vhd @@ -0,0 +1,46 @@ +-- 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 + +library vunit_lib; +--context vunit_lib.vunit_context; +use vunit_lib.check_pkg.all; +use vunit_lib.run_pkg.all; + +use work.byte_vector_ptr_pkg.all; + +entity tb_byte_vector_ptr is + generic (runner_cfg : string); +end; + +architecture a of tb_byte_vector_ptr is +begin + main : process + variable ptr, ptr2 : byte_vector_ptr_t; + constant a_random_value : natural := 7; + constant another_random_value : natural := 9; + begin + test_runner_setup(runner, runner_cfg); + + while test_suite loop + if run("test_element_access") then + ptr := new_byte_vector_ptr(1); + set(ptr, 0, a_random_value); + assert get(ptr, 0) = a_random_value; + + ptr2 := new_byte_vector_ptr(2); + set(ptr2, 0, another_random_value); + set(ptr2, 1, a_random_value); + assert get(ptr2, 0) = another_random_value; + assert get(ptr2, 1) = a_random_value; + + assert get(ptr, 0) = a_random_value report + "Checking that ptr was not affected by ptr2"; + end if; + end loop; + + test_runner_cleanup(runner); + end process; +end architecture; From 860d362d566c9c8299bcbac824c1a369233b5122 Mon Sep 17 00:00:00 2001 From: umarcor Date: Sun, 21 Apr 2019 02:44:42 +0200 Subject: [PATCH 3/5] add(examples/vhdl/external_buffer) --- examples/vhdl/external_buffer/run.py | 52 ++++++++++ examples/vhdl/external_buffer/src/main.c | 97 +++++++++++++++++++ .../src/tb_ext_byte_vector.vhd | 55 +++++++++++ .../external_buffer/src/tb_ext_string.vhd | 55 +++++++++++ .../acceptance/test_external_run_scripts.py | 9 +- .../data_types/src/byte_vector_ptr_pkg.vhd | 7 +- 6 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 examples/vhdl/external_buffer/run.py create mode 100644 examples/vhdl/external_buffer/src/main.c create mode 100644 examples/vhdl/external_buffer/src/tb_ext_byte_vector.vhd create mode 100644 examples/vhdl/external_buffer/src/tb_ext_string.vhd diff --git a/examples/vhdl/external_buffer/run.py b/examples/vhdl/external_buffer/run.py new file mode 100644 index 000000000..0f207259b --- /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 `_ + +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 (``extfunc`` or ``extacc``). 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 +vu = VUnit.from_argv(vhdl_standard='2008', compile_builtins=False) +vu.add_builtins({'string': True}) + +lib = vu.add_library('lib') +lib.add_source_files(join(src_path, '*.vhd')) + +# Add the C object to the elaboration of GHDL +vu.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj]) + +vu.main() diff --git a/examples/vhdl/external_buffer/src/main.c b/examples/vhdl/external_buffer/src/main.c new file mode 100644 index 000000000..b99a2f3b1 --- /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; i Date: Wed, 25 Sep 2019 23:41:49 +0200 Subject: [PATCH 4/5] move index_t to types_pkg --- vunit/vhdl/data_types/src/types.vhd | 1 + 1 file changed, 1 insertion(+) diff --git a/vunit/vhdl/data_types/src/types.vhd b/vunit/vhdl/data_types/src/types.vhd index 0af994658..7453b0a9f 100644 --- a/vunit/vhdl/data_types/src/types.vhd +++ b/vunit/vhdl/data_types/src/types.vhd @@ -5,6 +5,7 @@ -- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com package types_pkg is + subtype index_t is integer range -1 to integer'high; subtype byte_t is integer range 0 to 255; type storage_mode_t is (internal, extfnc, extacc); From d9d4b51b5e4e246a20927e6350366c1b34ca3221 Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 7 Oct 2019 04:44:20 +0200 Subject: [PATCH 5/5] examples/vhdl/external_buffer: add cp.py run script and tbs --- examples/vhdl/external_buffer/cp.py | 31 ++++++ examples/vhdl/external_buffer/run.py | 2 +- examples/vhdl/external_buffer/src/cp.c | 96 +++++++++++++++++++ .../src/tb_extcp_byte_vector.vhd | 48 ++++++++++ .../external_buffer/src/tb_extcp_string.vhd | 48 ++++++++++ .../acceptance/test_external_run_scripts.py | 1 + 6 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 examples/vhdl/external_buffer/cp.py create mode 100644 examples/vhdl/external_buffer/src/cp.c create mode 100644 examples/vhdl/external_buffer/src/tb_extcp_byte_vector.vhd create mode 100644 examples/vhdl/external_buffer/src/tb_extcp_string.vhd diff --git a/examples/vhdl/external_buffer/cp.py b/examples/vhdl/external_buffer/cp.py new file mode 100644 index 000000000..971927c69 --- /dev/null +++ b/examples/vhdl/external_buffer/cp.py @@ -0,0 +1,31 @@ +# 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 + +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, 'cp.o') +# Compile C application to an object +print(popen(' '.join([ + 'gcc', '-fPIC', + '-c', join(src_path, 'cp.c'), + '-o', c_obj +])).read()) + +# Enable the external feature for strings +vu = VUnit.from_argv(vhdl_standard='2008', compile_builtins=False) +vu.add_builtins({'string': True}) + +lib = vu.add_library('lib') +lib.add_source_files(join(src_path, 'tb_extcp_*.vhd')) + +# Add the C object to the elaboration of GHDL +vu.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj]) + +vu.main() diff --git a/examples/vhdl/external_buffer/run.py b/examples/vhdl/external_buffer/run.py index 0f207259b..068b5f883 100644 --- a/examples/vhdl/external_buffer/run.py +++ b/examples/vhdl/external_buffer/run.py @@ -44,7 +44,7 @@ vu.add_builtins({'string': True}) lib = vu.add_library('lib') -lib.add_source_files(join(src_path, '*.vhd')) +lib.add_source_files(join(src_path, 'tb_ext_*.vhd')) # Add the C object to the elaboration of GHDL vu.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj]) diff --git a/examples/vhdl/external_buffer/src/cp.c b/examples/vhdl/external_buffer/src/cp.c new file mode 100644 index 000000000..dde9c2236 --- /dev/null +++ b/examples/vhdl/external_buffer/src/cp.c @@ -0,0 +1,96 @@ +/* +External Buffer + +Interfacing with foreign languages (C) through VHPIDIRECT: +https://ghdl.readthedocs.io/en/latest/using/Foreign.html + +Two arrays of type uint8_t are allocated and some values are written to the first. +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_extcp_byte_vector.vhd or tb_extcp_string.vhd +*/ + +#include +#include +#include + +extern int ghdl_main (int argc, char **argv); + +uint8_t *D[1]; +const uint32_t length = 10; + +// 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(i=0; i