From 4cc8a318c67ad6d4ca2d07a8bf0922d384026eab Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 7 Jul 2023 22:16:36 +0100 Subject: [PATCH] Add enumeration value/subtype mirrors --- lib/std.19/reflection-body.vhd | 87 +++++++++++++------ src/rt/reflect.c | 152 +++++++++++++++++++++++++++------ test/regress/reflect1.vhd | 13 +++ test/regress/reflect2.vhd | 20 ++++- 4 files changed, 215 insertions(+), 57 deletions(-) diff --git a/lib/std.19/reflection-body.vhd b/lib/std.19/reflection-body.vhd index d9ab5f82..75314183 100644 --- a/lib/std.19/reflection-body.vhd +++ b/lib/std.19/reflection-body.vhd @@ -45,80 +45,106 @@ package body reflection is --------------------------------------------------------------------------- type enumeration_value_mirror_pt is protected body + variable f_owner : value_mirror; + variable f_subtype : enumeration_subtype_mirror; + variable f_pos : natural; + variable f_image : string_ptr; + impure function get_subtype_mirror return enumeration_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 pos return integer is begin - report "unimplemented" severity failure; + return f_pos; end function; impure function image return string is begin - report "unimplemented" severity failure; + return f_image.all; end function; end protected body; --------------------------------------------------------------------------- type enumeration_subtype_mirror_pt is protected body + variable f_owner : subtype_mirror; + + type evm_array is array (natural_index range <>) of enumeration_value_mirror; + type evm_array_ptr is access evm_array; + + variable f_literals : evm_array_ptr; + impure function to_subtype_mirror return subtype_mirror is begin - report "unimplemented" severity failure; + return f_owner; end function; impure function enumeration_literal (literal_idx : natural_index) return enumeration_value_mirror is begin - report "unimplemented" severity failure; + return f_literals.all(literal_idx); end function; impure function enumeration_literal (literal_name : string) - return enumeration_value_mirror is + return enumeration_value_mirror + is + variable tmp : enumeration_value_mirror; begin - report "unimplemented" severity failure; + for i in f_literals.all'range loop + tmp := f_literals.all(i); + --return tmp when tmp.image = literal_name; + if tmp.image = literal_name then + return tmp; + end if; + end loop; + + report literal_name + & " does not denote an enumeration literal of type " + & simple_name + severity error; + return null; 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 enumeration_value_mirror is begin - report "unimplemented" severity failure; + return f_literals.all(f_literals.all'left); end function; impure function right return enumeration_value_mirror is begin - report "unimplemented" severity failure; + return f_literals.all(f_literals.all'right); end function; impure function low return enumeration_value_mirror is begin - report "unimplemented" severity failure; + return left; end function; impure function high return enumeration_value_mirror is begin - report "unimplemented" severity failure; + return right; end function; impure function length return positive_index is begin - report "unimplemented" severity failure; + return positive_index(f_literals.all'length); end function; impure function ascending return boolean is begin - report "unimplemented" severity failure; + return true; end function; end protected body; @@ -666,11 +692,12 @@ package body reflection is --------------------------------------------------------------------------- type subtype_mirror_pt is protected body - variable f_class : type_class; - variable f_name : string_ptr; - variable f_integer : integer_subtype_mirror; - variable f_floating : floating_subtype_mirror; - variable f_array : array_subtype_mirror; + variable f_class : type_class; + variable f_name : string_ptr; + variable f_integer : integer_subtype_mirror; + variable f_enumeration : enumeration_subtype_mirror; + variable f_floating : floating_subtype_mirror; + variable f_array : array_subtype_mirror; impure function get_type_class return type_class is begin @@ -679,7 +706,8 @@ package body reflection is impure function to_enumeration return enumeration_subtype_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_ENUMERATION; + return f_enumeration; end function; impure function to_integer return integer_subtype_mirror is @@ -706,7 +734,8 @@ package body reflection is impure function to_array return array_subtype_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_ARRAY; + return f_array; end function; impure function to_access return access_subtype_mirror is @@ -733,11 +762,12 @@ package body reflection is --------------------------------------------------------------------------- type value_mirror_pt is protected body - variable f_class : value_class; - variable f_subtype : subtype_mirror; - variable f_integer : integer_value_mirror; - variable f_floating : floating_value_mirror; - variable f_array : array_value_mirror; + variable f_class : value_class; + variable f_subtype : subtype_mirror; + variable f_integer : integer_value_mirror; + variable f_enumeration : enumeration_value_mirror; + variable f_floating : floating_value_mirror; + variable f_array : array_value_mirror; impure function get_value_class return value_class is begin @@ -751,7 +781,8 @@ package body reflection is impure function to_enumeration return enumeration_value_mirror is begin - report "unimplemented" severity failure; + assert f_class = CLASS_ENUMERATION; + return f_enumeration; end function; impure function to_integer return integer_value_mirror is diff --git a/src/rt/reflect.c b/src/rt/reflect.c index 4b0f0efa..f37dc0a8 100644 --- a/src/rt/reflect.c +++ b/src/rt/reflect.c @@ -42,6 +42,7 @@ typedef struct _value_mirror value_mirror; 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 { type_t f_type; @@ -72,6 +73,17 @@ typedef struct { integer_subtype_mirror_pt pt; } integer_subtype_mirror; +typedef struct { + void *context; + subtype_mirror *f_owner; + ffi_uarray_t *f_literals; +} enumeration_subtype_mirror_pt; + +typedef struct { + void *access; + enumeration_subtype_mirror_pt pt; +} enumeration_subtype_mirror; + typedef struct { void *context; subtype_mirror *f_owner; @@ -120,6 +132,19 @@ typedef struct _integer_value_mirror { integer_value_mirror_pt pt; } integer_value_mirror; +typedef struct { + void *context; + value_mirror *f_owner; + enumeration_subtype_mirror *f_subtype; + int64_t f_pos; + ffi_uarray_t *f_image; +} enumeration_value_mirror_pt; + +typedef struct _enumeration_value_mirror { + void *access; + enumeration_value_mirror_pt pt; +} enumeration_value_mirror; + typedef struct { void *context; value_mirror *f_owner; @@ -144,12 +169,13 @@ typedef struct { } array_value_mirror; typedef struct { - void *context; - uint8_t f_class; - subtype_mirror *f_subtype; - integer_value_mirror *f_integer; - floating_value_mirror *f_floating; - array_value_mirror *f_array; + void *context; + uint8_t f_class; + subtype_mirror *f_subtype; + integer_value_mirror *f_integer; + enumeration_value_mirror *f_enumeration; + floating_value_mirror *f_floating; + array_value_mirror *f_array; } value_mirror_pt; typedef struct _value_mirror { @@ -158,12 +184,13 @@ typedef struct _value_mirror { } value_mirror; typedef struct { - void *context; - uint8_t f_class; - ffi_uarray_t *f_name; - integer_subtype_mirror *f_integer; - floating_subtype_mirror *f_floating; - array_subtype_mirror *f_array; + void *context; + uint8_t f_class; + ffi_uarray_t *f_name; + integer_subtype_mirror *f_integer; + enumeration_subtype_mirror *f_enumeration; + floating_subtype_mirror *f_floating; + array_subtype_mirror *f_array; } subtype_mirror_pt; typedef struct _subtype_mirror { @@ -226,6 +253,27 @@ static value_mirror *get_value_mirror(void *context, jit_scalar_t value, vm->pt.f_class = CLASS_INTEGER; vm->pt.f_integer = ivm; } + else if (type_is_enum(type)) { + enumeration_value_mirror *evm = + zero_alloc(sizeof(enumeration_value_mirror)); + evm->access = &(evm->pt); + + evm->pt.context = context; + evm->pt.f_pos = value.integer; + evm->pt.f_owner = vm; + evm->pt.f_subtype = vm->pt.f_subtype->pt.f_enumeration; + + LOCAL_TEXT_BUF tb = tb_new(); + type_t base = type_base_recur(type); + tb_istr(tb, tree_ident(type_enum_literal(base, value.integer))); + if (tb_get(tb)[0] != '\'') + tb_downcase(tb); + + evm->pt.f_image = get_string(tb_get(tb)); + + vm->pt.f_class = CLASS_ENUMERATION; + vm->pt.f_enumeration = evm; + } else if (type_is_real(type)) { floating_value_mirror *fvm = zero_alloc(sizeof(floating_value_mirror)); fvm->access = &(fvm->pt); @@ -263,6 +311,14 @@ static integer_value_mirror *get_integer_mirror(void *context, type_t type, return get_value_mirror(context, scalar, type, NULL)->pt.f_integer; } +static enumeration_value_mirror *get_enumeration_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_enumeration; +} + static floating_value_mirror *get_floating_mirror(void *context, type_t type, double value) { @@ -273,31 +329,36 @@ static floating_value_mirror *get_floating_mirror(void *context, type_t type, static subtype_mirror *get_subtype_mirror(void *context, type_t type, const jit_scalar_t *bounds) { + const bool can_cache = type_is_scalar(type); internal_cache_pt *cache = get_cache(context); - for (int i = 0; i < cache->f_num_subtypes; i++) { - cache_elem_t *e = &(cache->f_subtype_cache[i]); - if (e->f_type == type) - return e->f_mirror; + if (can_cache) { + for (int i = 0; i < cache->f_num_subtypes; i++) { + cache_elem_t *e = &(cache->f_subtype_cache[i]); + if (e->f_type == type) + return e->f_mirror; + } } subtype_mirror *sm = zero_alloc(sizeof(subtype_mirror)); sm->access = &(sm->pt); sm->pt.context = context; - 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 (can_cache) { + 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)); - cache->f_subtype_cache = tmp; - cache->f_max_subtypes = new_max; - } + cache->f_subtype_cache = tmp; + cache->f_max_subtypes = new_max; + } - cache_elem_t *e = &(cache->f_subtype_cache[cache->f_num_subtypes++]); - e->f_type = type; - e->f_mirror = sm; + cache_elem_t *e = &(cache->f_subtype_cache[cache->f_num_subtypes++]); + e->f_type = type; + e->f_mirror = sm; + } const char *simple = strrchr(istr(type_ident(type)), '.') + 1; sm->pt.f_name = get_string(simple); @@ -331,6 +392,43 @@ static subtype_mirror *get_subtype_mirror(void *context, type_t type, sm->pt.f_class = CLASS_INTEGER; sm->pt.f_integer = ism; } + else if (type_is_enum(type)) { + enumeration_subtype_mirror *esm = + zero_alloc(sizeof(enumeration_subtype_mirror)); + esm->access = &(esm->pt); + + 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; + } + + esm->pt.context = context; + esm->pt.f_owner = sm; + + type_t base = type_base_recur(type); + const int nlits = type_enum_literals(base); + + const size_t size = + sizeof(ffi_uarray_t) + nlits * sizeof(enumeration_value_mirror *); + esm->pt.f_literals = zero_alloc(size); + + esm->pt.f_literals->dims[0].left = 0; + esm->pt.f_literals->dims[0].length = nlits; + esm->pt.f_literals->ptr = esm->pt.f_literals + 1; + + enumeration_value_mirror **lits = esm->pt.f_literals->ptr; + for (int i = 0; i < nlits; i++) + lits[i] = get_enumeration_mirror(context, base, i); + + sm->pt.f_class = CLASS_ENUMERATION; + sm->pt.f_enumeration = esm; + } else if (type_is_real(type)) { floating_subtype_mirror *fsm = zero_alloc(sizeof(floating_subtype_mirror)); diff --git a/test/regress/reflect1.vhd b/test/regress/reflect1.vhd index 846c5b04..4185899c 100644 --- a/test/regress/reflect1.vhd +++ b/test/regress/reflect1.vhd @@ -14,10 +14,12 @@ begin variable ivm : integer_value_mirror; variable avm : array_value_mirror; variable fvm : floating_value_mirror; + variable evm : enumeration_value_mirror; variable stm : subtype_mirror; variable istm : integer_subtype_mirror; variable astm : array_subtype_mirror; variable fstm : floating_subtype_mirror; + variable estm : enumeration_subtype_mirror; begin vm := v1'reflect; assert vm.get_value_class = CLASS_INTEGER; @@ -63,6 +65,17 @@ begin assert fvm.value = 1.234; assert fvm.get_subtype_mirror.to_subtype_mirror = real'reflect; + evm := true'reflect.to_enumeration; + assert evm.pos = 1; + assert evm.image = "true"; + estm := evm.get_subtype_mirror; + assert estm.length = 2; + assert estm.ascending; + assert estm.left.image = "false"; + assert estm.right.pos = 1; + assert character'reflect.to_enumeration.enumeration_literal(72).image = "'H'"; + assert estm.enumeration_literal("true").pos = 1; + wait; end process; diff --git a/test/regress/reflect2.vhd b/test/regress/reflect2.vhd index 15b3e400..357b0787 100644 --- a/test/regress/reflect2.vhd +++ b/test/regress/reflect2.vhd @@ -5,7 +5,7 @@ use std.reflection.all; architecture test of reflect2 is - procedure test (constant l, r : in integer) is + procedure test_int (constant l, r : in integer) is type my_int is range l to r; variable v1 : my_int := 7; variable vm : value_mirror; @@ -35,6 +35,20 @@ architecture test of reflect2 is assert istm.right.value = integer'right; end procedure; + procedure test_array (constant l, r : in integer) is + variable a : integer_vector(l to r); + variable vm : value_mirror; + variable stm : subtype_mirror; + variable astm : array_subtype_mirror; + begin + vm := a'reflect; + stm := vm.get_subtype_mirror; + astm := stm.to_array; + assert astm.left = index(l); + assert astm.right = index(r); + assert astm.length = index(maximum(r - l + 1, 0)); + end procedure; + begin p1: process is @@ -43,7 +57,9 @@ begin begin assert small_int'reflect.to_integer.right.value = 10; assert small_real'reflect.to_floating.left.value = 0.0; - test(-10, 10); + test_int(-10, 10); + test_array(1, 10); + test_array(2, 3); wait; end process; -- 2.39.2