diff --git a/examples/vhdl/external_buffer/run.py b/examples/vhdl/external_buffer/run.py index 14c580df4..586a92e30 100644 --- a/examples/vhdl/external_buffer/run.py +++ b/examples/vhdl/external_buffer/run.py @@ -25,28 +25,55 @@ simulation. """ -from vunit import VUnit +from vunit import VUnit, ROOT from os import popen from os.path import join, dirname src_path = join(dirname(__file__), "src") +ext_srcs = join(ROOT, "vunit", "vhdl", "data_types", "src", "external", "ghdl") -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() -) +# Compile C applications to an objects +c_iobj = join(src_path, "imain.o") +c_bobj = join(src_path, "bmain.o") -# Enable the external feature for strings +for val in [["int32_t", c_iobj], ["uint8_t", c_bobj]]: + print( + popen( + " ".join( + [ + "gcc", + "-fPIC", + "-DTYPE=" + val[0], + "-I", + ext_srcs, + "-c", + join(src_path, "main.c"), + "-o", + val[1], + ] + ) + ).read() + ) + +# Enable the external feature for strings/byte_vectors and integer_vectors vu = VUnit.from_argv(vhdl_standard="2008", compile_builtins=False) -vu.add_builtins({"string": True}) +vu.add_builtins({"string": True, "integer": 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]) +for tb in lib.get_test_benches(pattern="*tb_ext*", allow_empty=False): + tb.set_sim_option( + "ghdl.elab_flags", + ["-Wl," + c_bobj, "-Wl,-Wl,--version-script=" + join(ext_srcs, "grt.ver")], + overwrite=True, + ) +for tb in lib.get_test_benches(pattern="*tb_ext*_integer*", allow_empty=False): + tb.set_sim_option( + "ghdl.elab_flags", + ["-Wl," + c_iobj, "-Wl,-Wl,--version-script=" + join(ext_srcs, "grt.ver")], + overwrite=True, + ) vu.main() diff --git a/examples/vhdl/external_buffer/src/main.c b/examples/vhdl/external_buffer/src/main.c index b99a2f3b1..c63bb4e49 100644 --- a/examples/vhdl/external_buffer/src/main.c +++ b/examples/vhdl/external_buffer/src/main.c @@ -9,25 +9,31 @@ positions. Then, the VHDL simulation is executed, where the (external) array/buf 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 +This source file is used for both string/byte_vector and integer_vector. +Accordingly, TYPE must be defined as uint8_t or int32_t during compilation. +Keep in mind that the buffer (D) is of type uint8_t*, independently of TYPE, i.e. +accesses are casted. + +NOTE: This file is expected to be used along with tb_ext_string.vhd, tb_ext_byte_vector.vhd +or tb_ext_integer_vector.vhd */ #include #include #include +#include "vhpidirect_user.h" -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. +/* + 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; + unsigned i, j, z, k; + TYPE expected, got; k = 0; for (j=0; j<3; j++) { k += j; @@ -35,7 +41,7 @@ static void exit_handler(void) { z = (length*j)+i; expected = (i+1)*11 + k; - got = D[0][z]; + got = ((TYPE*)D[0])[z]; if (expected != got) { printf("check error %d: %d %d\n", z, expected, got); exit(1); @@ -50,7 +56,7 @@ static void exit_handler(void) { int main(int argc, char **argv) { // Allocate a buffer which is three times the number of values // that we want to copy/modify - D[0] = (uint8_t *) malloc(3*length*sizeof(uint8_t)); + D[0] = (uint8_t *) malloc(3*length*sizeof(TYPE)); if ( D[0] == NULL ) { perror("execution of malloc() failed!\n"); return -1; @@ -58,11 +64,12 @@ int main(int argc, char **argv) { // Initialize the first 1/3 of the buffer int i; for(i=0; i, 'integer': }. Allowed values are: None, False/True or + ['path/to/custom/file']. """ self._add_files(join(VHDL_PATH, "data_types", "src", "*.vhd")) - use_ext = {"string": False} - files = {"string": None} + use_ext = {"string": False, "integer": False} + files = {"string": None, "integer": None} if external: for ind, val in external.items(): @@ -91,33 +92,34 @@ def _add_data_types(self, external=None): 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() - ): + for _, val in use_ext.items(): + if val 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): + def default_files(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", - ) + return [ + join( + ext_path, + "external_" + type_str + "-" + ("" if cond else "no") + "vhpi.vhd", + ), + join(ext_path, "external_" + type_str + "-body.vhd"), + ] if not files["string"]: - files["string"] = [ - default_pkg(use_ext["string"], "string"), - join(ext_path, "external_string-body.vhd"), - ] + files["string"] = default_files(use_ext["string"], "string") + + if not files["integer"]: + files["integer"] = default_files(use_ext["integer"], "integer_vector") - for ind in files: - for name in files[ind]: + for _, val in files.items(): + for name in val: self._add_files(name) def _add_array_util(self): @@ -234,8 +236,9 @@ 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']}. + :param external: struct to select whether to enable external models for 'string' and/or 'integer' vectors. + {'string': , 'integer': }. Allowed values are: None, False/True or + ['path/to/custom/file']. """ self._add_data_types(external=external) self._add_files(join(VHDL_PATH, "*.vhd")) diff --git a/vunit/ui/vunit.py b/vunit/ui/vunit.py index c4aa953e9..3859ef2fb 100644 --- a/vunit/ui/vunit.py +++ b/vunit/ui/vunit.py @@ -945,8 +945,9 @@ 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']}. + :param external: struct to select whether to enable external models for 'string' and/or 'integer' vectors. + {'string': , 'integer': }. Allowed values are: None, False/True or + ['path/to/custom/file']. """ self._builtins.add_vhdl_builtins(external=external) diff --git a/vunit/vhdl/data_types/src/external/external_integer_vector-body.vhd b/vunit/vhdl/data_types/src/external/external_integer_vector-body.vhd new file mode 100644 index 000000000..c3ab56d73 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/external_integer_vector-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_integer_vector_pkg is + procedure write_integer ( + id : integer; + i : integer; + v : integer + )is begin + assert false report "VHPI write_integer" severity failure; + end; + + impure function read_integer ( + id : integer; + i : integer + ) return integer is begin + assert false report "VHPI read_integer" severity failure; + end; + + impure function get_ptr ( + id : integer + ) return extintvec_access_t is begin + assert false report "VHPI get_intvec_ptr" severity failure; + end; +end package body; diff --git a/vunit/vhdl/data_types/src/external/external_integer_vector-novhpi.vhd b/vunit/vhdl/data_types/src/external/external_integer_vector-novhpi.vhd new file mode 100644 index 000000000..28801ac78 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/external_integer_vector-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_integer_vector_pkg is + procedure write_integer ( + id : integer; + i : integer; + v : integer + ); + + impure function read_integer ( + id : integer; + i : integer + ) return integer; + + impure function get_ptr ( + id : integer + ) return extintvec_access_t; +end package; diff --git a/vunit/vhdl/data_types/src/external/external_integer_vector-vhpi.vhd b/vunit/vhdl/data_types/src/external/external_integer_vector-vhpi.vhd new file mode 100644 index 000000000..03d8cb2ad --- /dev/null +++ b/vunit/vhdl/data_types/src/external/external_integer_vector-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_integer_vector_pkg is + procedure write_integer ( + id : integer; + i : integer; + v : integer + ); + + impure function read_integer ( + id : integer; + i : integer + ) return integer; + + impure function get_ptr ( + id : integer + ) return extintvec_access_t; + + attribute foreign of write_integer : procedure is "VHPIDIRECT write_integer"; + attribute foreign of read_integer : function is "VHPIDIRECT read_integer"; + attribute foreign of get_ptr : function is "VHPIDIRECT get_intvec_ptr"; +end package; diff --git a/vunit/vhdl/data_types/src/external/ghdl/grt.ver b/vunit/vhdl/data_types/src/external/ghdl/grt.ver new file mode 100644 index 000000000..cd09ff8c6 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/ghdl/grt.ver @@ -0,0 +1,16 @@ +VHPIDIRECT { + global: +main; +oct_main; +ghdl_main; +read_char; +write_char; +read_integer; +write_integer; +set_string_ptr; +get_string_ptr; +set_intvec_ptr; +get_intvec_ptr; + local: + *; +}; diff --git a/vunit/vhdl/data_types/src/external/ghdl/stubs.c b/vunit/vhdl/data_types/src/external/ghdl/stubs.c new file mode 100644 index 000000000..9ffb4ef26 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/ghdl/stubs.c @@ -0,0 +1,53 @@ +#include +#include +#include + +void set_string_ptr(uint8_t id, uint8_t *p) { + printf("ERROR set_string_ptr: THIS IS A STUB\n"); + exit(1); + return; +} + +uintptr_t get_string_ptr(uint8_t id) { + printf("ERROR get_string_ptr: THIS IS A STUB\n"); + exit(1); + return NULL; +} + +void write_char( uint8_t id, uint32_t i, uint8_t v ) { + printf("ERROR write_char: THIS IS A STUB\n"); + exit(1); + return; +} + +uint8_t read_char( uint8_t id, uint32_t i ) { + printf("ERROR read_char: THIS IS A STUB\n"); + exit(1); + return 0; +} + +//--- + +void set_intvec_ptr(uint8_t id, uint8_t *p) { + printf("ERROR set_intvec_ptr: THIS IS A STUB\n"); + exit(1); + return; +} + +uintptr_t get_intvec_ptr(uint8_t id) { + printf("ERROR get_intvec_ptr: THIS IS A STUB\n"); + exit(1); + return NULL; +} + +void write_integer(uint8_t id, uint32_t i, int32_t v) { + printf("ERROR write_integer: THIS IS A STUB\n"); + exit(1); + return; +} + +int32_t read_integer(uint8_t id, uint32_t i) { + printf("ERROR read_integer: THIS IS A STUB\n"); + exit(1); + return 0; +} diff --git a/vunit/vhdl/data_types/src/external/ghdl/vhpidirect_user.h b/vunit/vhdl/data_types/src/external/ghdl/vhpidirect_user.h new file mode 100644 index 000000000..2541c2b39 --- /dev/null +++ b/vunit/vhdl/data_types/src/external/ghdl/vhpidirect_user.h @@ -0,0 +1,49 @@ +#include + +extern int ghdl_main (int argc, char **argv); + +uint8_t *D[256]; + +//--- + +// External string/byte_vector through access (mode = extacc) + +void set_string_ptr(uint8_t id, uintptr_t p) { + D[id] = (uint8_t*)p; +} + +uintptr_t get_string_ptr(uint8_t id) { + return (uintptr_t)D[id]; +} + +// External string/byte_vector through functions (mode = extfnc) + +void write_char(uint8_t id, uint32_t i, uint8_t v) { + ((uint8_t*)D[id])[i] = v; +} + +uint8_t read_char(uint8_t id, uint32_t i) { + return ((uint8_t*)D[id])[i]; +} + +//--- + +// External integer_vector through access (mode = extacc) + +void set_intvec_ptr(uint8_t id, uintptr_t p) { + D[id] = (uint8_t*)p; +} + +uintptr_t get_intvec_ptr(uint8_t id) { + return (uintptr_t)D[id]; +} + +// External integer_vector through functions (mode = extfnc) + +void write_integer(uint8_t id, uint32_t i, int32_t v) { + ((int32_t*)D[id])[i] = v; +} + +int32_t read_integer(uint8_t id, uint32_t i) { + return ((int32_t*)D[id])[i]; +} diff --git a/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-2002p.vhd b/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-2002p.vhd index d81be6175..56463869d 100644 --- a/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-2002p.vhd +++ b/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-2002p.vhd @@ -5,12 +5,18 @@ -- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com package body integer_vector_ptr_pkg is - type integer_vector_ptr_storage_t is protected - impure function new_integer_vector_ptr ( + type prot_storage_t is protected + impure function new_vector ( length : natural := 0; - value : val_t := 0 + mode : storage_mode_t := internal; + eid : index_t := -1; + value : val_t := 0 ) return natural; + impure function is_external ( + ref : natural + ) return boolean; + procedure deallocate ( ref : natural ); @@ -40,99 +46,234 @@ package body integer_vector_ptr_pkg is ref : natural; length : natural; drop : natural := 0; - value : val_t := 0 + value : val_t := 0 ); end protected; - type integer_vector_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); - impure function new_integer_vector_ptr ( - length : natural := 0; - value : val_t := 0 - ) return natural is - variable old_ptrs : vava_t; - variable retval : ptr_t := (ref => current_index); + 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 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); + 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; - ptrs(current_index) := new integer_vector_t'(0 to length-1 => value); - current_index := current_index + 1; - return retval.ref; end; - procedure deallocate ( + 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_vector ( + length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; + value : val_t := 0 + ) 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; + 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'(0 to length-1 => 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; + + 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; 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_integer(s.id, index, 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); + ) return val_t is + variable s : storage_t := st.idxs(ref); + begin + case s.mode is + when extfnc => return read_integer(s.id, index); + when extacc => return st.eptrs(s.id)(index); + when internal => return st.ptrs(s.id)(index); + end case; end; procedure reallocate ( ref : natural; length : natural; value : val_t := 0 - ) is begin - deallocate(ptrs(ref)); - ptrs(ref) := new integer_vector_t'(0 to length - 1 => value); + ) is + variable s : storage_t := st.idxs(ref); + begin + 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'(0 to length - 1 => value); + end case; end; procedure resize ( ref : natural; length : natural; drop : natural := 0; - value : val_t := 0 + value : val_t := 0 ) is - variable old_ptr, new_ptr : integer_vector_access_t; + variable oldp, newp : integer_vector_access_t; variable min_len : natural := length; + variable s : storage_t := st.idxs(ref); begin - new_ptr := new integer_vector_t'(0 to length - 1 => value); - old_ptr := ptrs(ref); - if min_len > old_ptr'length - drop then - min_len := old_ptr'length - drop; - end if; - for i in 0 to min_len-1 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'(0 to length-1 => value); + oldp := st.ptrs(s.id); + if min_len > oldp'length - drop then + min_len := oldp'length - drop; + end if; + for i in 0 to min_len-1 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; end protected body; - shared variable integer_vector_ptr_storage : integer_vector_ptr_storage_t; + shared variable vec_ptr_storage : prot_storage_t; function to_integer ( value : ptr_t @@ -149,21 +290,34 @@ package body integer_vector_ptr_pkg is impure function new_integer_vector_ptr ( length : natural := 0; - value : val_t := 0 + mode : storage_mode_t := internal; + eid : index_t := -1; + value : val_t := 0 ) return ptr_t is begin - return (ref => integer_vector_ptr_storage.new_integer_vector_ptr(length, value)); + return (ref => vec_ptr_storage.new_vector( + length => length, + mode => mode, + value => value, + eid => eid + )); + 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 - integer_vector_ptr_storage.deallocate(ptr.ref); + vec_ptr_storage.deallocate(ptr.ref); end; impure function length ( ptr : ptr_t ) return integer is begin - return integer_vector_ptr_storage.length(ptr.ref); + return vec_ptr_storage.length(ptr.ref); end; procedure set ( @@ -171,14 +325,14 @@ package body integer_vector_ptr_pkg is index : natural; value : val_t ) is begin - integer_vector_ptr_storage.set(ptr.ref, index, value); + vec_ptr_storage.set(ptr.ref, index, value); end; impure function get ( ptr : ptr_t; index : natural ) return val_t is begin - return integer_vector_ptr_storage.get(ptr.ref, index); + return vec_ptr_storage.get(ptr.ref, index); end; procedure reallocate ( @@ -186,16 +340,16 @@ package body integer_vector_ptr_pkg is length : natural; value : val_t := 0 ) is begin - integer_vector_ptr_storage.reallocate(ptr.ref, length, value); + vec_ptr_storage.reallocate(ptr.ref, length, value); end; procedure resize ( - ptr : ptr_t; + ptr : ptr_t; length : natural; drop : natural := 0; - value : val_t := 0 + value : val_t := 0 ) is begin - integer_vector_ptr_storage.resize(ptr.ref, length, drop, value); + vec_ptr_storage.resize(ptr.ref, length, drop, value); end; function encode ( diff --git a/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-93.vhd b/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-93.vhd index 4ff7ac8bc..0f31ceca6 100644 --- a/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-93.vhd +++ b/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-93.vhd @@ -5,88 +5,219 @@ -- Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com package body integer_vector_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_integer_vector_ptr ( length : natural := 0; + mode : storage_mode_t := internal; + eid : index_t := -1; value : val_t := 0 - ) return ptr_t is - variable old_ptrs : vava_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); - end if; - ptrs(current_index) := new integer_vector_t'(0 to length-1 => value); - current_index := current_index + 1; - return (ref => current_index-1); + ) 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'(0 to length-1 => 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; - 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; 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_integer(s.id, index, 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); + ) return val_t is + variable s : storage_t := st.idxs(ptr.ref); + begin + case s.mode is + when extfnc => return read_integer(s.id, index); + when extacc => return st.eptrs(s.id)(index); + when internal => return st.ptrs(s.id)(index); + end case; end; procedure reallocate ( ptr : ptr_t; length : natural; value : val_t := 0 - ) is begin - deallocate(ptrs(ptr.ref)); - ptrs(ptr.ref) := new integer_vector_t'(0 to length - 1 => value); + ) is + variable s : storage_t := st.idxs(ptr.ref); + begin + 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'(0 to length - 1 => value); + end case; end; procedure resize ( ptr : ptr_t; length : natural; drop : natural := 0; - value : val_t := 0 + value : val_t := 0 ) is - variable old_ptr, new_ptr : integer_vector_access_t; + variable oldp, newp : integer_vector_access_t; variable min_len : natural := length; + variable s : storage_t := st.idxs(ptr.ref); begin - new_ptr := new integer_vector_t'(0 to length - 1 => value); - old_ptr := ptrs(ptr.ref); - if min_len > old_ptr'length - drop then - min_len := old_ptr'length - drop; - end if; - for i in 0 to min_len-1 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'(0 to length-1 => value); + oldp := st.ptrs(s.id); + if min_len > oldp'length - drop then + min_len := oldp'length - drop; + end if; + for i in 0 to min_len-1 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; function to_integer ( diff --git a/vunit/vhdl/data_types/src/integer_vector_ptr_pkg.vhd b/vunit/vhdl/data_types/src/integer_vector_ptr_pkg.vhd index f90fa0f77..888927267 100644 --- a/vunit/vhdl/data_types/src/integer_vector_ptr_pkg.vhd +++ b/vunit/vhdl/data_types/src/integer_vector_ptr_pkg.vhd @@ -3,7 +3,6 @@ -- 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 an integer vector access type (pointer) -- that can itself be used in arrays and returned from functions unlike a @@ -12,35 +11,46 @@ -- use work.types_pkg.all; +use work.external_integer_vector_pkg.all; + use work.codec_pkg.all; use work.codec_builder_pkg.all; package integer_vector_ptr_pkg is - subtype index_t is integer range -1 to integer'high; + type integer_vector_ptr_t is record ref : index_t; end record; - constant null_ptr : integer_vector_ptr_t := (ref => -1); + constant null_integer_vector_ptr : integer_vector_ptr_t := (ref => -1); + alias null_ptr is null_integer_vector_ptr; alias ptr_t is integer_vector_ptr_t; alias val_t is integer; alias vec_t is integer_vector_t; alias vav_t is integer_vector_access_vector_t; + alias evav_t is extintvec_access_vector_t; alias vava_t is integer_vector_access_vector_access_t; + alias evava_t is extintvec_access_vector_access_t; function to_integer ( value : ptr_t ) return integer; impure function to_integer_vector_ptr ( - value : val_t + value : integer ) return ptr_t; impure function new_integer_vector_ptr ( length : natural := 0; - value : val_t := 0 + mode : storage_mode_t := internal; + eid : index_t := -1; + value : val_t := 0 ) return ptr_t; + impure function is_external ( + ptr : ptr_t + ) return boolean; + procedure deallocate ( ptr : ptr_t ); @@ -70,7 +80,7 @@ package integer_vector_ptr_pkg is ptr : ptr_t; length : natural; drop : natural := 0; - value : val_t := 0 + value : val_t := 0 ); function encode ( @@ -87,8 +97,8 @@ package integer_vector_ptr_pkg is variable result : out ptr_t ); - alias encode_integer_vector_ptr_t is encode[ptr_t return string]; - alias decode_integer_vector_ptr_t is decode[string return ptr_t]; + alias encode_ptr_t is encode[ptr_t return string]; + alias decode_ptr_t is decode[string return ptr_t]; constant integer_vector_ptr_t_code_length : positive := integer_code_length; diff --git a/vunit/vhdl/data_types/src/types.vhd b/vunit/vhdl/data_types/src/types.vhd index 7453b0a9f..c2199c543 100644 --- a/vunit/vhdl/data_types/src/types.vhd +++ b/vunit/vhdl/data_types/src/types.vhd @@ -29,5 +29,9 @@ package types_pkg is 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; + + type extintvec_access_t is access integer_vector_t(0 to integer'high); + type extintvec_access_vector_t is array (natural range <>) of extintvec_access_t; + type extintvec_access_vector_access_t is access extintvec_access_vector_t; end package;