From 6dc13bc3838ef4c9a9145ea79219fa7e46b3697b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 5 Mar 2024 22:05:18 +0000 Subject: [PATCH] Fix several issues with array view handling. Issue #856 --- src/driver.c | 2 + src/lower.c | 12 +++--- src/rt/model.c | 67 +++++++++++++++++++++++++++++++--- test/regress/driver22.vhd | 28 ++++++++++++++ test/regress/gold/driver22.txt | 5 +++ test/regress/issue856.vhd | 61 +++++++++++++++++++++++++++++++ test/regress/testlist.txt | 2 + 7 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 test/regress/driver22.vhd create mode 100644 test/regress/gold/driver22.txt create mode 100644 test/regress/issue856.vhd diff --git a/src/driver.c b/src/driver.c index 1685ceba..3aff4921 100644 --- a/src/driver.c +++ b/src/driver.c @@ -441,6 +441,8 @@ void dump_drivers(driver_set_t *ds) printf("%s: { ", istr(tree_ident(tree))); for (; di; di = di->chain_proc) { vhdl_dump(di->prefix, 0); + if (di->view) + printf("<%s>", type_pp(tree_type(di->view))); if (di->tentative) printf("?"); if (di->chain_proc) diff --git a/src/lower.c b/src/lower.c index c635b2ad..a6d6c28c 100644 --- a/src/lower.c +++ b/src/lower.c @@ -11018,8 +11018,7 @@ static void lower_driver_field_cb(lower_unit_t *lu, tree_t field, elem = find_element_mode_indication(view, field, &converse); assert(elem != NULL); - const port_mode_t mode = converse_mode(elem, converse); - if (mode != PORT_OUT && mode != PORT_INOUT) + if (converse_mode(elem, converse) == PORT_IN) return; } @@ -11030,11 +11029,14 @@ static void lower_driver_field_cb(lower_unit_t *lu, tree_t field, emit_drive_signal(data_reg, count_reg); } - else { - void *new_ctx = tag_pointer(elem ? tree_value(elem) : NULL, converse); + else if (elem != NULL && tree_subkind(elem) == PORT_RECORD_VIEW) { + void *new_ctx = tag_pointer(tree_value(elem), converse); lower_for_each_field(lu, type, ptr, VCODE_INVALID_REG, VCODE_INVALID_REG, lower_driver_field_cb, new_ctx); } + else + lower_for_each_field(lu, type, ptr, VCODE_INVALID_REG, + VCODE_INVALID_REG, lower_driver_field_cb, NULL); } static bool can_use_transfer_signal(tree_t proc, driver_set_t *ds) @@ -11539,7 +11541,7 @@ static void lower_map_view_field_cb(lower_unit_t *lu, tree_t field, lower_for_each_field(lu, ftype, src_ptr, dst_ptr, locus, lower_map_view_field_cb, new_ctx); } - else if (converse) + else if (converse_mode(elem, converse) == PORT_IN) lower_for_each_field(lu, ftype, dst_ptr, src_ptr, locus, lower_map_signal_field_cb, NULL); else diff --git a/src/rt/model.c b/src/rt/model.c index e4939bc3..e4ba757a 100644 --- a/src/rt/model.c +++ b/src/rt/model.c @@ -1247,18 +1247,73 @@ static inline bool cmp_values(rt_nexus_t *n, rt_value_t a, rt_value_t b) return cmp_bytes(a.ext, b.ext, valuesz); } +static void check_multiple_sources(rt_nexus_t *n, source_kind_t kind) +{ + if (n->signal->resolution != NULL || kind == SOURCE_FORCING) + return; + + diag_t *d; + if (n->signal->parent->kind == SCOPE_SIGNAL) { + rt_scope_t *root = n->signal->parent; + for (; root->parent->kind == SCOPE_SIGNAL; root = root->parent); + + d = diag_new(DIAG_FATAL, tree_loc(root->where)); + diag_printf(d, "element %s of signal %s has multiple sources", + istr(tree_ident(n->signal->where)), + istr(tree_ident(root->where))); + diag_hint(d, tree_loc(n->signal->where), "element %s declared here", + istr(tree_ident(n->signal->where))); + diag_hint(d, tree_loc(root->where), "composite signal %s declared with " + "unresolved type %s", istr(tree_ident(root->where)), + type_pp(tree_type(root->where))); + } + else { + d = diag_new(DIAG_FATAL, tree_loc(n->signal->where)); + diag_printf(d, "unresolved signal %s has multiple sources", + istr(tree_ident(n->signal->where))); + diag_hint(d, tree_loc(n->signal->where), "signal %s declared with " + "unresolved type %s", istr(tree_ident(n->signal->where)), + type_pp(tree_type(n->signal->where))); + } + + if (n->sources.tag == SOURCE_DRIVER) { + const rt_proc_t *p = n->sources.u.driver.proc; + diag_hint(d, tree_loc(p->where), "driven by process %s", istr(p->name)); + } + else if (n->sources.tag == SOURCE_PORT) { + const rt_signal_t *s = n->sources.u.port.input->signal; + tree_t where = s->where; + if (s->parent->kind == SCOPE_SIGNAL) { + for (rt_scope_t *it = s->parent; it->kind == SCOPE_SIGNAL; + it = it->parent) + where = it->where; + } + + if (tree_kind(where) == T_PORT_DECL) + diag_hint(d, tree_loc(where), "connected to %s port %s", + port_mode_str(tree_subkind(where)), istr(tree_ident(where))); + else + diag_hint(d, tree_loc(where), "connected to signal %s", + istr(tree_ident(where))); + } + + if (kind == SOURCE_DRIVER) { + const rt_proc_t *p = get_active_proc(); + diag_hint(d, tree_loc(p->where), "driven by process %s", istr(p->name)); + } + + diag_emit(d); + jit_abort_with_status(EXIT_FAILURE); +} + static rt_source_t *add_source(rt_model_t *m, rt_nexus_t *n, source_kind_t kind) { rt_source_t *src = NULL; if (n->n_sources == 0) src = &(n->sources); - else if (n->signal->resolution == NULL && kind != SOURCE_FORCING - && (n->sources.tag == SOURCE_DRIVER - || n->sources.u.port.conv_func == NULL)) - jit_msg(tree_loc(n->signal->where), DIAG_FATAL, - "unresolved signal %s has multiple sources", - istr(tree_ident(n->signal->where))); else { + check_multiple_sources(n, kind); + rt_source_t **p; for (p = &(n->sources.chain_input); *p; p = &((*p)->chain_input)) ; diff --git a/test/regress/driver22.vhd b/test/regress/driver22.vhd new file mode 100644 index 00000000..8af391a9 --- /dev/null +++ b/test/regress/driver22.vhd @@ -0,0 +1,28 @@ +entity driver22 is +end entity; + +architecture test of driver22 is + type t_rec is record + f, g : integer; + end record; + + type t_rec_array is array (natural range <>) of t_rec; + + view t_rec_in of t_rec is + f : in; + g : out; + end view; + + signal s : t_rec; +begin + b: block is + port ( p : view (t_rec_in) of t_rec_array ); + port map ( p(0) => s ); + begin + process (all) is + variable sel : natural := 0; + begin + p(sel).g <= p(sel).f + 1; + end process; + end block; +end architecture; diff --git a/test/regress/gold/driver22.txt b/test/regress/gold/driver22.txt new file mode 100644 index 00000000..e21e3c53 --- /dev/null +++ b/test/regress/gold/driver22.txt @@ -0,0 +1,5 @@ +(init): element F of signal P has multiple sources +element F declared here +connected to signal S +composite signal P declared with unresolved type T_REC_ARRAY +driven by process :driver22:b:_p0 diff --git a/test/regress/issue856.vhd b/test/regress/issue856.vhd new file mode 100644 index 00000000..8a95718a --- /dev/null +++ b/test/regress/issue856.vhd @@ -0,0 +1,61 @@ +entity issue856 is +end entity; + +architecture test of issue856 is + type t_point is record + x, y : integer; + end record; + + type t_point_array is array (natural range <>) of t_point; + + type t_rec is record + f : t_point_array(1 to 3); + g : natural; + end record; + + view t_rec_in of t_rec is + f : in; + g : out; + end view; + + alias t_rec_out is t_rec_in'converse; + + type t_rec_array is array (natural range <>) of t_rec; + + procedure do_write (signal s : view t_rec_out) is + begin + for i in s.f'range loop + s.f(i) <= (i*2, i*2 + 1); + end loop; + end procedure; + + signal s : t_rec; +begin + + p1: process is + begin + do_write(s); + wait for 1 ns; + assert s.g = 27; + wait; + end process; + + b: block is + port ( p : view (t_rec_in) of t_rec_array ); + port map ( p(1) => s ); + begin + + g: for i in p'range generate + p2: process (all) + variable sum : integer := 0; + begin + for j in p(i).f'range loop + sum := sum + p(i).f(j).x + p(i).f(j).y; + end loop; + p(i).g <= sum; + end process; + end generate; + + end block; + +end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 323d4fbd..e1a664d1 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -953,3 +953,5 @@ vlog9 verilog issue654 normal,2008 issue854 normal,2019 ename8 normal,2008 +issue856 normal,2019 +driver22 fail,gold,2019 -- 2.39.2