From 1261881c4663521f629a0c41a77ed26c34a22ed8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 30 Jul 2023 15:59:20 +0100 Subject: [PATCH] Reflection for physical and protected types --- NEWS.md | 2 + lib/std.19/reflection-body.vhd | 139 +++++++++++++++++++----------- src/rt/reflect.c | 153 ++++++++++++++++++++++++++++++++- test/regress/reflect5.vhd | 34 ++++++++ www/features.html.in | 2 +- 5 files changed, 278 insertions(+), 52 deletions(-) diff --git a/NEWS.md b/NEWS.md index b560be5c..582cb8d3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,8 @@ XML format which is supported by most CI environments such as GitLab. - Generics on internal instances can now be overridden with the `-g` elaboration option. For example `-g uut.value=42`. +- Implemented the `'reflect` attribute and associated protected types + from VHDL-2019. ## Version 1.10.1 - 2023-07-28 - Fixed incorrect sensitivity list generation with concurrent statements diff --git a/lib/std.19/reflection-body.vhd b/lib/std.19/reflection-body.vhd index 56e36227..fbdc1620 100644 --- a/lib/std.19/reflection-body.vhd +++ b/lib/std.19/reflection-body.vhd @@ -42,6 +42,29 @@ package body reflection is shared variable cache : internal_cache_pt; + function casecmp (x, y : in string) return boolean is + variable xp, yp : integer; + begin + if x'length = y'length then + for i in x'range loop + xp := character'pos(x(i)); + yp := character'pos(y(i)); + next when xp = yp; + if xp >= 97 and xp <= 122 then + xp := xp - 32; + end if; + if yp >= 97 and yp <= 122 then + yp := yp - 32; + end if; + next when xp = yp; + return false; + end loop; + return true; + else + return false; + end if; + end function; + --------------------------------------------------------------------------- type enumeration_value_mirror_pt is protected body @@ -301,98 +324,126 @@ package body reflection is --------------------------------------------------------------------------- type physical_value_mirror_pt is protected body + variable f_owner : value_mirror; + variable f_subtype : physical_subtype_mirror; + variable f_value : integer; + impure function get_subtype_mirror return physical_subtype_mirror is begin - report "unimplemented" severity failure; + return f_subtype; end function; impure function to_value_mirror return value_mirror is begin - report "unimplemented" severity failure; + return f_owner; end function; impure function unit_index return index is begin - report "unimplemented" severity failure; + return 1; end function; impure function value return integer is begin - report "unimplemented" severity failure; + return f_value; end function; impure function image return string is begin - report "unimplemented" severity failure; + return integer'image(f_value) & " " & f_subtype.unit_name(1); end function; end protected body; --------------------------------------------------------------------------- type physical_subtype_mirror_pt is protected body + variable f_owner : subtype_mirror; + variable f_left : physical_value_mirror; + variable f_right : physical_value_mirror; + variable f_low : physical_value_mirror; + variable f_high : physical_value_mirror; + variable f_ascending : boolean; + + type unit_rec is record + f_name : string_ptr; + f_scale : natural; + end record; + + type unit_array is array (index range <>) of unit_rec; + type unit_array_ptr is access unit_array; + + variable f_units : unit_array_ptr; + impure function to_subtype_mirror return subtype_mirror is begin - report "unimplemented" severity failure; + return f_owner; end function; impure function units_length return index is begin - report "unimplemented" severity failure; + return index(f_units'length); end function; impure function unit_name (unit_idx: index) return string is begin - report "unimplemented" severity failure; + return f_units(unit_idx).f_name.all; end function; impure function unit_index (unit_name : string) return index is begin - report "unimplemented" severity failure; + for i in f_units.all'range loop + if casecmp(f_units.all(i).f_name.all, unit_name) then + return i; + end if; + end loop; + report simple_name & " has no unit named " & unit_name + severity error; + return index'left; end function; impure function scale (unit_idx: index) return natural is begin - report "unimplemented" severity failure; + return f_units(unit_idx).f_scale; end function; impure function scale (unit_name: string) return natural is begin - report "unimplemented" severity failure; + return scale(unit_index(unit_name)); end function; impure function simple_name return string is begin - report "unimplemented" severity failure; + return f_owner.simple_name; end function; impure function left return physical_value_mirror is begin - report "unimplemented" severity failure; + return f_left; end function; impure function right return physical_value_mirror is begin - report "unimplemented" severity failure; + return f_right; end function; impure function low return physical_value_mirror is begin - report "unimplemented" severity failure; + return f_low; end function; impure function high return physical_value_mirror is begin - report "unimplemented" severity failure; + return f_high; end function; impure function length return index is begin - report "unimplemented" severity failure; + return maximum(index(f_high.value - f_low.value + 1), 0); end function; impure function ascending return boolean is begin - report "unimplemented" severity failure; + return f_ascending; end function; end protected body; @@ -458,29 +509,6 @@ package body reflection is return f_fields.all(element_idx).f_name.all; end function; - pure function casecmp (x, y : in string) return boolean is - variable xp, yp : integer; - begin - if x'length = y'length then - for i in x'range loop - xp := character'pos(x(i)); - yp := character'pos(y(i)); - next when xp = yp; - if xp >= 97 and xp <= 122 then - xp := xp - 32; - end if; - if yp >= 97 and yp <= 122 then - yp := yp - 32; - end if; - next when xp = yp; - return false; - end loop; - return true; - else - return false; - end if; - end function; - impure function element_index (element_name : string) return index is begin for i in f_fields.all'range loop @@ -762,28 +790,33 @@ package body reflection is --------------------------------------------------------------------------- type protected_value_mirror_pt is protected body + variable f_owner : value_mirror; + variable f_subtype : protected_subtype_mirror; + impure function get_subtype_mirror return protected_subtype_mirror is begin - report "unimplemented" severity failure; + return f_subtype; end function; impure function to_value_mirror return value_mirror is begin - report "unimplemented" severity failure; + return f_owner; end function; end protected body; --------------------------------------------------------------------------- type protected_subtype_mirror_pt is protected body + variable f_owner : subtype_mirror; + impure function to_subtype_mirror return subtype_mirror is begin - report "unimplemented" severity failure; + return f_owner; end function; impure function simple_name return string is begin - report "unimplemented" severity failure; + return f_owner.simple_name; end function; end protected body; @@ -799,6 +832,8 @@ package body reflection is variable f_record : record_subtype_mirror; variable f_file : file_subtype_mirror; variable f_access : access_subtype_mirror; + variable f_physical : physical_subtype_mirror; + variable f_protected : protected_subtype_mirror; impure function get_type_class return type_class is begin @@ -825,7 +860,8 @@ package body reflection is impure function to_physical return physical_subtype_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_PHYSICAL; + return f_physical; end function; impure function to_record return record_subtype_mirror is @@ -854,7 +890,8 @@ package body reflection is impure function to_protected return protected_subtype_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_PROTECTED; + return f_protected; end function; impure function simple_name return string is @@ -875,6 +912,8 @@ package body reflection is variable f_record : record_value_mirror; variable f_file : file_value_mirror; variable f_access : access_value_mirror; + variable f_physical : physical_value_mirror; + variable f_protected : protected_value_mirror; impure function get_value_class return value_class is begin @@ -906,7 +945,8 @@ package body reflection is impure function to_physical return physical_value_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_PHYSICAL; + return f_physical; end function; impure function to_record return record_value_mirror is @@ -935,7 +975,8 @@ package body reflection is impure function to_protected return protected_value_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_PROTECTED; + return f_protected; end function; end protected body; diff --git a/src/rt/reflect.c b/src/rt/reflect.c index 2bdf7622..d5f5a699 100644 --- a/src/rt/reflect.c +++ b/src/rt/reflect.c @@ -44,6 +44,7 @@ typedef struct _subtype_mirror subtype_mirror; typedef struct _integer_value_mirror integer_value_mirror; typedef struct _floating_value_mirror floating_value_mirror; typedef struct _enumeration_value_mirror enumeration_value_mirror; +typedef struct _physical_value_mirror physical_value_mirror; typedef struct { type_t f_type; @@ -100,6 +101,27 @@ typedef struct { floating_subtype_mirror_pt pt; } floating_subtype_mirror; +typedef struct { + ffi_uarray_t *f_name; + int64_t f_scale; +} unit_rec; + +typedef struct { + void *context; + subtype_mirror *f_owner; + physical_value_mirror *f_left; + physical_value_mirror *f_right; + physical_value_mirror *f_low; + physical_value_mirror *f_high; + uint8_t f_ascending; + ffi_uarray_t *f_units; +} physical_subtype_mirror_pt; + +typedef struct { + void *access; + physical_subtype_mirror_pt pt; +} physical_subtype_mirror; + typedef struct { subtype_mirror *f_index_subtype; int64_t f_left; @@ -159,6 +181,16 @@ typedef struct { access_subtype_mirror_pt pt; } access_subtype_mirror; +typedef struct { + void *context; + subtype_mirror *f_owner; +} protected_subtype_mirror_pt; + +typedef struct { + void *access; + protected_subtype_mirror_pt pt; +} protected_subtype_mirror; + typedef struct { void *context; value_mirror *f_owner; @@ -196,6 +228,18 @@ typedef struct _floating_value_mirror { floating_value_mirror_pt pt; } floating_value_mirror; +typedef struct { + void *context; + value_mirror *f_owner; + physical_subtype_mirror *f_subtype; + int64_t f_value; +} physical_value_mirror_pt; + +typedef struct _physical_value_mirror { + void *access; + physical_value_mirror_pt pt; +} physical_value_mirror; + typedef struct { void *context; value_mirror *f_owner; @@ -245,6 +289,17 @@ typedef struct { access_value_mirror_pt pt; } access_value_mirror; +typedef struct { + void *context; + value_mirror *f_owner; + protected_subtype_mirror *f_subtype; +} protected_value_mirror_pt; + +typedef struct { + void *access; + protected_value_mirror_pt pt; +} protected_value_mirror; + typedef struct { void *context; uint8_t f_class; @@ -256,6 +311,8 @@ typedef struct { record_value_mirror *f_record; file_value_mirror *f_file; access_value_mirror *f_access; + physical_value_mirror *f_physical; + protected_value_mirror *f_protected; } value_mirror_pt; typedef struct _value_mirror { @@ -274,6 +331,8 @@ typedef struct { record_subtype_mirror *f_record; file_subtype_mirror *f_file; access_subtype_mirror *f_access; + physical_subtype_mirror *f_physical; + protected_subtype_mirror *f_protected; } subtype_mirror_pt; typedef struct _subtype_mirror { @@ -563,6 +622,29 @@ static value_mirror *get_value_mirror(void *context, jit_scalar_t value, vm->pt.f_class = CLASS_ACCESS; vm->pt.f_access = avm; } + else if (type_is_physical(type)) { + physical_value_mirror *pvm = zero_alloc(sizeof(physical_value_mirror)); + pvm->access = &(pvm->pt); + + pvm->pt.context = context; + pvm->pt.f_value = value.integer; + pvm->pt.f_owner = vm; + pvm->pt.f_subtype = vm->pt.f_subtype->pt.f_physical; + + vm->pt.f_class = CLASS_PHYSICAL; + vm->pt.f_physical = pvm; + } + else if (type_is_protected(type)) { + protected_value_mirror *pvm = zero_alloc(sizeof(protected_value_mirror)); + pvm->access = &(pvm->pt); + + pvm->pt.context = context; + pvm->pt.f_owner = vm; + pvm->pt.f_subtype = vm->pt.f_subtype->pt.f_protected; + + vm->pt.f_class = CLASS_PROTECTED; + vm->pt.f_protected = pvm; + } else jit_msg(NULL, DIAG_FATAL, "unsupported type %s in prefix of REFLECT " "attribute", type_pp(type)); @@ -585,6 +667,13 @@ static enumeration_value_mirror *get_enumeration_mirror(void *context, return get_value_mirror(context, scalar, type, NULL)->pt.f_enumeration; } +static physical_value_mirror *get_physical_mirror(void *context, type_t type, + int64_t value) +{ + jit_scalar_t scalar = { .integer = value }; + return get_value_mirror(context, scalar, type, NULL)->pt.f_physical; +} + static floating_value_mirror *get_floating_mirror(void *context, type_t type, double value) { @@ -638,8 +727,10 @@ static subtype_mirror *get_subtype_mirror(void *context, type_t type, if (cache->f_num_subtypes == cache->f_max_subtypes) { const size_t new_max = MAX(cache->f_max_subtypes * 2, 128); cache_elem_t *tmp = zero_alloc(new_max * sizeof(cache_elem_t)); - memcpy(tmp, cache->f_subtype_cache, - cache->f_max_subtypes * sizeof(cache_elem_t)); + + if (cache->f_subtype_cache != NULL) + memcpy(tmp, cache->f_subtype_cache, + cache->f_max_subtypes * sizeof(cache_elem_t)); cache->f_subtype_cache = tmp; cache->f_max_subtypes = new_max; @@ -862,6 +953,64 @@ static subtype_mirror *get_subtype_mirror(void *context, type_t type, sm->pt.f_class = CLASS_ACCESS; sm->pt.f_access = astm; } + else if (type_is_physical(type)) { + physical_subtype_mirror *psm = + zero_alloc(sizeof(physical_subtype_mirror)); + psm->access = &(psm->pt); + + psm->pt.context = context; + psm->pt.f_owner = sm; + + range_kind_t rkind; + int64_t low = INT64_MIN, high = INT64_MAX; + for (;; type = type_base(type)) { + tree_t r = range_of(type, 0); + rkind = tree_subkind(r); + if (rkind != RANGE_EXPR && folded_bounds(r, &low, &high)) + break; + else if (type_kind(type) != T_SUBTYPE) + break; + } + + psm->pt.f_ascending = (rkind == RANGE_TO); + + type_t index = index_type_of(type, 0); + psm->pt.f_low = get_physical_mirror(context, index, low); + psm->pt.f_high = get_physical_mirror(context, index, high); + + psm->pt.f_left = (rkind == RANGE_TO) ? psm->pt.f_low : psm->pt.f_high; + psm->pt.f_right = (rkind == RANGE_TO) ? psm->pt.f_high : psm->pt.f_low; + + type_t base = type_base_recur(type); + const int nunits = type_units(base); + + psm->pt.f_units = + zero_alloc(sizeof(ffi_uarray_t) + nunits * sizeof(unit_rec)); + psm->pt.f_units->dims[0].left = 1; + psm->pt.f_units->dims[0].length = nunits; + psm->pt.f_units->ptr = psm->pt.f_units + 1; + + unit_rec *units = psm->pt.f_units->ptr; + for (int i = 0; i < nunits; i++) { + tree_t u = type_unit(base, i); + units[i].f_name = get_string(istr(tree_ident(u))); + units[i].f_scale = assume_int(tree_value(u)); + } + + sm->pt.f_class = CLASS_PHYSICAL; + sm->pt.f_physical = psm; + } + else if (type_is_protected(type)) { + protected_subtype_mirror *psm = + zero_alloc(sizeof(protected_subtype_mirror)); + psm->access = &(psm->pt); + + psm->pt.context = context; + psm->pt.f_owner = sm; + + sm->pt.f_class = CLASS_PROTECTED; + sm->pt.f_protected = psm; + } else jit_msg(NULL, DIAG_FATAL, "unsupported type %s in prefix of REFLECT " "attribute", type_pp(type)); diff --git a/test/regress/reflect5.vhd b/test/regress/reflect5.vhd index 5f474203..17f5861d 100644 --- a/test/regress/reflect5.vhd +++ b/test/regress/reflect5.vhd @@ -14,6 +14,16 @@ architecture test of reflect5 is end loop; return path; end function; + + type pt is protected + procedure proc; + end protected; + + type pt is protected body + procedure proc is + begin + end procedure; + end protected body; begin p1: process is @@ -22,8 +32,12 @@ begin variable astm : access_subtype_mirror; variable fvm : file_value_mirror; variable avm : access_value_mirror; + variable pstm : physical_subtype_mirror; + variable pvm : physical_value_mirror; file f : text; variable ptr : line; + variable d : delay_length; + variable p : pt; begin stm := text'reflect; assert stm.get_type_class = CLASS_FILE; @@ -51,6 +65,26 @@ begin assert avm.get.to_array.get(1).to_enumeration.image= "'h'"; assert avm.get.to_array.get(5).to_enumeration.image= "'o'"; + stm := time'reflect; + assert stm.get_type_class = CLASS_PHYSICAL; + pstm := stm.to_physical; + assert pstm.units_length = 8; + assert pstm.unit_index("ns") = 3; + assert pstm.unit_name(5) = "MS"; + assert pstm.scale("fs") = 1; + assert pstm.scale("ns") = 1000000; + + d := 20 ns; + pvm := d'reflect.to_physical; + assert pvm.value = 20000000; + assert pvm.image = "20000000 FS"; + + stm := pt'reflect; + assert stm.get_type_class = CLASS_PROTECTED; + assert stm.to_protected.to_subtype_mirror = stm; + + assert p'reflect.get_value_class = CLASS_PROTECTED; + wait; end process; diff --git a/www/features.html.in b/www/features.html.in index c6ec5af5..617812f8 100644 --- a/www/features.html.in +++ b/www/features.html.in @@ -286,7 +286,7 @@ table below. LCS2016-041 Record introspection/type reflection - 1.10 + master -- 2.39.2