From 2422aa5dbfd51f13979c57a44ed12fc9dff82cf1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 7 Jul 2022 21:49:02 +0100 Subject: [PATCH] Incorrect calculation of initial driving/effective values --- src/rt/rtkern.c | 85 +++++++++++++++++++++++---------------- test/regress/driver12.vhd | 81 +++++++++++++++++++++++++++++++++++++ test/regress/testlist.txt | 1 + 3 files changed, 133 insertions(+), 34 deletions(-) create mode 100644 test/regress/driver12.vhd diff --git a/src/rt/rtkern.c b/src/rt/rtkern.c index 6b0c37c3..e60addb4 100644 --- a/src/rt/rtkern.c +++ b/src/rt/rtkern.c @@ -17,6 +17,7 @@ #include "util.h" #include "alloc.h" +#include "array.h" #include "common.h" #include "cover.h" #include "debug.h" @@ -3118,8 +3119,12 @@ static const void *rt_effective_value(rt_nexus_t *nexus) // of the association element that associates an actual with S if (nexus->flags & NET_F_INOUT) { for (rt_source_t *s = nexus->outputs; s; s = s->chain_output) { - if (s->tag == SOURCE_PORT) - return rt_effective_value(s->u.port.output); + if (s->tag == SOURCE_PORT) { + if (likely(s->u.port.conv_func == NULL)) + return rt_effective_value(s->u.port.output); + else + return nexus->resolved; + } } } @@ -3172,37 +3177,6 @@ static void rt_reset_scope(rt_scope_t *s) rt_reset(p); } -static void rt_signal_initial(rt_nexus_t *nexus) -{ - // The initial value of each driver is the default value of the signal - if (nexus->n_sources > 0) { - for (rt_source_t *s = &(nexus->sources); s; s = s->chain_input) { - if (s->tag == SOURCE_DRIVER) - rt_copy_value_ptr(nexus, &(s->u.driver.waveforms.value), - nexus->resolved); - } - } - - const void *initial = nexus->resolved; - - if (nexus->n_sources > 0) { - if (nexus->flags & NET_F_EFFECTIVE) { - void *driving = nexus->resolved + 2*nexus->signal->shared.size; - memcpy(driving, rt_driving_value(nexus), nexus->width * nexus->size); - initial = rt_effective_value(nexus); - } - else { - // Effective value is always the same as the driving value - initial = rt_driving_value(nexus); - } - } - - TRACE("%s initial value %s", istr(tree_ident(nexus->signal->where)), - fmt_nexus(nexus, initial)); - - rt_propagate_nexus(nexus, initial); -} - static int rt_nexus_rank(rt_nexus_t *nexus) { if (nexus->n_sources > 0) { @@ -3240,12 +3214,55 @@ static void rt_initial(tree_t top) for (rt_nexus_t *n = nexuses; n != NULL; n = n->chain) heap_insert(q, rt_nexus_rank(n), n); + SCOPED_A(rt_nexus_t *) effq = AINIT; + while (heap_size(q) > 0) { rt_nexus_t *n = heap_extract_min(q); - rt_signal_initial(n); + + // The initial value of each driver is the default value of the signal + if (n->n_sources > 0) { + for (rt_source_t *s = &(n->sources); s; s = s->chain_input) { + if (s->tag == SOURCE_DRIVER) + rt_copy_value_ptr(n, &(s->u.driver.waveforms.value), + n->resolved); + } + } + + if (n->flags & NET_F_EFFECTIVE) { + // Driving and effective values must be calculated separately + void *driving = n->resolved + 2*n->signal->shared.size; + memcpy(driving, rt_driving_value(n), n->width * n->size); + + APUSH(effq, n); + + TRACE("%s initial driving value %s", + istr(tree_ident(n->signal->where)), fmt_nexus(n, driving)); + } + else { + // Effective value is always the same as the driving value + const void *initial = n->resolved; + if (n->n_sources > 0) + initial = rt_driving_value(n); + + rt_propagate_nexus(n, initial); + + TRACE("%s initial value %s", istr(tree_ident(n->signal->where)), + fmt_nexus(n, initial)); + } } heap_free(q); + + // Update effective values after all initial driving values calculated + for (int i = 0; i < effq.count; i++) { + rt_nexus_t *n = effq.items[i]; + + const void *initial = rt_effective_value(n); + rt_propagate_nexus(n, initial); + + TRACE("%s initial effective value %s", istr(tree_ident(n->signal->where)), + fmt_nexus(n, initial)); + } } static void rt_trace_wakeup(rt_wakeable_t *obj) diff --git a/test/regress/driver12.vhd b/test/regress/driver12.vhd new file mode 100644 index 00000000..01e3ab97 --- /dev/null +++ b/test/regress/driver12.vhd @@ -0,0 +1,81 @@ +library ieee; +use ieee.std_logic_1164.all; + +package pack is + type rec is record + x : std_logic; + y : std_logic_vector(2 downto 0); + end record; + + function init_signals return rec; +end package; + +package body pack is + function init_signals return rec is + begin + return (x => 'Z', y => "000"); + end function; +end package body; + +------------------------------------------------------------------------------- + +use work.pack.all; + +entity sub is + port ( p : inout rec := init_signals ); +end entity; + +library ieee; +use ieee.std_logic_1164.all; + +architecture test of sub is +begin + p1: process is + begin + assert p.x = '0'; + assert p.y = "000"; + wait for 1 ns; + assert p.x = '1'; + wait; + end process; +end architecture; + +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity sub2 is + port ( x : out std_logic := '0'; + y : in std_logic_vector(2 downto 0) ); +end entity; + +architecture test of sub2 is +begin + x <= '0', '1' after 1 ns; +end architecture; + +------------------------------------------------------------------------------- + +entity driver12 is +end entity; + +library ieee; +use ieee.std_logic_1164.all; + +architecture test of driver12 is + signal s : std_logic; + signal t : std_logic_vector(2 downto 0); +begin + + u1: entity work.sub + port map ( + p.x => s, + p.y => t ); + + u2: entity work.sub2 + port map ( + x => s, + y => t ); + +end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index d8e346ef..628ba1d9 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -614,3 +614,4 @@ wait23 normal genpack10 normal,2008 attr17 normal,2002,gold signal23 normal,gold,2008 +driver12 normal -- 2.39.2