From 60864ff1c7634a15b945170d60b2a408e422d844 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 6 Jan 2024 11:48:45 -0800 Subject: [PATCH 1/2] vvp: repeat: Implement partial vector receive The repeat functor can receive a partial vector. Make sure this is handled. Since the expectation is that will only happen if the input wire is driven by a single partial selection the default recv_vec4_pv_() can be used which replaces the missing bits by `z`. Signed-off-by: Lars-Peter Clausen --- vvp/concat.cc | 7 +++++++ vvp/vvp_net.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/vvp/concat.cc b/vvp/concat.cc index 448a44e92..1f19dd139 100644 --- a/vvp/concat.cc +++ b/vvp/concat.cc @@ -234,6 +234,13 @@ void vvp_fun_repeat::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, port.ptr()->send_vec4(val, 0); } +void vvp_fun_repeat::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t &bit, + unsigned base, unsigned vwid, + vvp_context_t context) +{ + recv_vec4_pv_(port, bit, base, vwid, context); +} + void compile_repeat(char*label, long width, long repeat, struct symb_s arg) { vvp_fun_repeat*fun = new vvp_fun_repeat(width, repeat); diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index b7e14dd7a..a5220209e 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1450,6 +1450,9 @@ class vvp_fun_repeat : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t context); + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned int base, unsigned int vwid, + vvp_context_t context) final; private: unsigned wid_; From 2d22f43ba74d0732b741141672b58ef8f9ff4743 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 3 Jan 2024 21:43:07 -0800 Subject: [PATCH 2/2] Use NetReplicate to implement replication for concat Currently replication in a concatenation is implemented by simply concatenating the input signals multiple times by the replication amount. Replace this to use NetReplicate on the concatenation instead. In case there is only one input vector to the concatenation the replication will directly connect to the input vector. This is slightly more efficient in vvp since the replication functor has only one input while the concatenation has multiple inputs connected to the same wire. When an update of the input occurs the replication functor will only receive a single update, while the concatenation will receive multiple update events, one for each replication. Signed-off-by: Lars-Peter Clausen --- expr_synth.cc | 67 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/expr_synth.cc b/expr_synth.cc index fe10f0c28..54142e51c 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -776,23 +776,24 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) return 0; } - /* Make a NetNet object to carry the output vector. */ - perm_string path = scope->local_symbol(); - netvector_t*osig_vec = new netvector_t(data_type, expr_width()-1, 0); - NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, osig_vec); - osig->set_line(*this); - osig->local_flag(true); + NetNet *osig = nullptr; - NetConcat*cncat = new NetConcat(scope, scope->local_symbol(), - osig->vector_width(), - num_parms * repeat()); - cncat->set_line(*this); - des->add_node(cncat); - connect(cncat->pin(0), osig->pin(0)); + if (num_parms != 1) { + /* Make a NetNet object to carry the output vector. */ + auto osig_vec = new netvector_t(data_type, expr_width() / repeat() - 1, 0); + osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, + osig_vec); + osig->set_line(*this); + osig->local_flag(true); - unsigned count_input_width = 0; - unsigned cur_pin = 1; - for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { + auto cncat = new NetConcat(scope, scope->local_symbol(), + osig->vector_width(), num_parms); + cncat->set_line(*this); + des->add_node(cncat); + connect(cncat->pin(0), osig->pin(0)); + + unsigned count_input_width = 0; + unsigned cur_pin = 1; for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { unsigned concat_item = parms_.size()-idx-1; if (tmp[concat_item] == 0) continue; @@ -800,14 +801,38 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) cur_pin += 1; count_input_width += tmp[concat_item]->vector_width(); } + + if (count_input_width != osig->vector_width()) { + cerr << get_fileline() << ": internal error: " + << "NetEConcat input width = " << count_input_width + << ", expecting " << osig->vector_width() + << endl; + des->errors += 1; + } + } else { + /* There is exactly one input signal */ + for (unsigned idx = 0; idx < parms_.size(); idx++) { + if (tmp[idx]) { + osig = tmp[idx]; + break; + } + } + ivl_assert(*this, osig); } - if (count_input_width != osig->vector_width()) { - cerr << get_fileline() << ": internal error: " - << "NetEConcat input width = " << count_input_width - << ", expecting " << osig->vector_width() - << " (repeat=" << repeat() << ")" << endl; - des->errors += 1; + if (repeat() != 1) { + auto rep = new NetReplicate(scope, scope->local_symbol(), + expr_width(), repeat()); + rep->set_line(*this); + des->add_node(rep); + connect(rep->pin(1), osig->pin(0)); + + auto osig_vec = new netvector_t(data_type, expr_width() - 1, 0); + osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, + osig_vec); + osig->set_line(*this); + osig->local_flag(true); + connect(rep->pin(0), osig->pin(0)); } delete[]tmp;