From b45a52a164565c8e5df4b8c3add325307513ebc5 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 18 May 2021 08:36:04 +0100 Subject: [PATCH] Fix .event/or connectivity when inputs have multiple fanout (issue #508). The old implementation connected all inputs to the same vvp_net_t port, on the basis that we don't care about the data values or what port they arrived on. But if one or more of the inputs fans out to multiple nets, the chains get tangled, which either results in connections being lost or inappropriate connections being made, depending on the order that the inputs are linked. This could have been fixed by using a standard wide functor. But as we don't care about the data values, that would be unnecessary overhead. We just need separate vvp_net_t objects to handle the input connectivity and can keep using a single shared functor. (cherry picked from commit 1f8876be1c49a43e6d8680461a531604ad989388) --- vvp/event.cc | 39 ++++++++++++++++++++++----------------- vvp/event.h | 13 +++++++++---- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/vvp/event.cc b/vvp/event.cc index f070d8db5..439e0a0f5 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -755,7 +755,8 @@ void vvp_fun_anyedge_aa::recv_string(vvp_net_ptr_t port, const std::string&bit, } } -vvp_fun_event_or::vvp_fun_event_or() +vvp_fun_event_or::vvp_fun_event_or(vvp_net_t*base_net) +: base_net_(base_net) { } @@ -763,8 +764,8 @@ vvp_fun_event_or::~vvp_fun_event_or() { } -vvp_fun_event_or_sa::vvp_fun_event_or_sa() -: threads_(0) +vvp_fun_event_or_sa::vvp_fun_event_or_sa(vvp_net_t*base_net) +: vvp_fun_event_or(base_net), threads_(0) { } @@ -780,15 +781,15 @@ vthread_t vvp_fun_event_or_sa::add_waiting_thread(vthread_t thread) return tmp; } -void vvp_fun_event_or_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, +void vvp_fun_event_or_sa::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&bit, vvp_context_t) { run_waiting_threads_(threads_); - vvp_net_t*net = port.ptr(); - net->send_vec4(bit, 0); + base_net_->send_vec4(bit, 0); } -vvp_fun_event_or_aa::vvp_fun_event_or_aa() +vvp_fun_event_or_aa::vvp_fun_event_or_aa(vvp_net_t*base_net) +: vvp_fun_event_or(base_net) { context_scope_ = vpip_peek_context_scope(); context_idx_ = vpip_add_item_to_context(this, context_scope_); @@ -839,8 +840,7 @@ void vvp_fun_event_or_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, (vvp_get_context_item(context, context_idx_)); run_waiting_threads_(state->threads); - vvp_net_t*net = port.ptr(); - net->send_vec4(bit, context); + base_net_->send_vec4(bit, context); } else { context = context_scope_->live_contexts; while (context) { @@ -1005,20 +1005,25 @@ void compile_event(char*label, char*type, unsigned argc, struct symb_s*argv) static void compile_event_or(char*label, unsigned argc, struct symb_s*argv) { - vvp_net_t* ptr = new vvp_net_t; + vvp_net_t*base_net = new vvp_net_t; if (vpip_peek_current_scope()->is_automatic()) { - ptr->fun = new vvp_fun_event_or_aa; + base_net->fun = new vvp_fun_event_or_aa(base_net); } else { - ptr->fun = new vvp_fun_event_or_sa; + base_net->fun = new vvp_fun_event_or_sa(base_net); } - define_functor_symbol(label, ptr); + define_functor_symbol(label, base_net); free(label); - /* This is a very special case. Point all the source inputs to - the same input. It doesn't matter that the streams get - tangled because data values are irrelevant. */ + /* This is a simplified version of a wide functor. We don't + care about the data values or what port they arrived on, + so we can use a single shared functor. */ + vvp_net_t*curr_net = base_net; for (unsigned idx = 0 ; idx < argc ; idx += 1) { - input_connect(ptr, 0, argv[idx].text); + if (idx > 0 && (idx % 4) == 0) { + curr_net = new vvp_net_t; + curr_net->fun = base_net->fun; + } + input_connect(curr_net, idx % 4, argv[idx].text); } free(argv); } diff --git a/vvp/event.h b/vvp/event.h index 5fa249732..421af690e 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -302,13 +302,18 @@ class vvp_fun_anyedge_aa : public vvp_fun_anyedge, public automatic_hooks_s { /* * This functor triggers anytime any input is set, no matter what the - * value. This is similar to a named event, but it has no handle. + * value. This is similar to a named event, but it has no handle. It + * supports wide (more than 4) inputs, so needs a pointer to the base + * net that is used for output. */ class vvp_fun_event_or : public vvp_net_fun_t, public waitable_hooks_s { public: - explicit vvp_fun_event_or(); + explicit vvp_fun_event_or(vvp_net_t*base_net); ~vvp_fun_event_or(); + + protected: + vvp_net_t*base_net_; }; /* @@ -317,7 +322,7 @@ class vvp_fun_event_or : public vvp_net_fun_t, public waitable_hooks_s { class vvp_fun_event_or_sa : public vvp_fun_event_or { public: - explicit vvp_fun_event_or_sa(); + explicit vvp_fun_event_or_sa(vvp_net_t*base_net); ~vvp_fun_event_or_sa(); vthread_t add_waiting_thread(vthread_t thread); @@ -335,7 +340,7 @@ class vvp_fun_event_or_sa : public vvp_fun_event_or { class vvp_fun_event_or_aa : public vvp_fun_event_or, public automatic_hooks_s { public: - explicit vvp_fun_event_or_aa(); + explicit vvp_fun_event_or_aa(vvp_net_t*base_net); ~vvp_fun_event_or_aa(); void alloc_instance(vvp_context_t context);