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 new file mode 100644 index 000000000..068b5f883 --- /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, 'tb_ext_*.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/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 +#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) 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..7453b0a9f 100644 --- a/vunit/vhdl/data_types/src/types.vhd +++ b/vunit/vhdl/data_types/src/types.vhd @@ -5,14 +5,29 @@ -- 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); 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; + + 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;