diff --git a/expr_synth.cc b/expr_synth.cc index 444c00bb3..005617959 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1089,7 +1089,8 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) if (base_ != 0) { off = base_->synthesize(des, scope, root); - NetPartSelect*sel = new NetPartSelect(sub, off, expr_width()); + NetPartSelect*sel = new NetPartSelect(sub, off, expr_width(), + base_->has_sign()); sel->set_line(*this); des->add_node(sel); diff --git a/netlist.cc b/netlist.cc index 095338ff3..add9690f0 100644 --- a/netlist.cc +++ b/netlist.cc @@ -885,7 +885,7 @@ const NetDelaySrc* NetNet::delay_path(unsigned idx) const NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid, NetPartSelect::dir_t dir__) : NetNode(sig->scope(), sig->scope()->local_symbol(), 2), - off_(off), wid_(wid), dir_(dir__) + off_(off), wid_(wid), dir_(dir__), signed_flag_(false) { set_line(*sig); @@ -904,9 +904,9 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid, } NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, - unsigned wid) + unsigned wid, bool signed_flag) : NetNode(sig->scope(), sig->scope()->local_symbol(), 3), - off_(0), wid_(wid), dir_(VP) + off_(0), wid_(wid), dir_(VP), signed_flag_(signed_flag) { switch (dir_) { case NetPartSelect::VP: diff --git a/netlist.h b/netlist.h index 9162e7b71..40efe0b47 100644 --- a/netlist.h +++ b/netlist.h @@ -1795,12 +1795,14 @@ class NetPartSelect : public NetNode { explicit NetPartSelect(NetNet*sig, unsigned off, unsigned wid, dir_t dir); explicit NetPartSelect(NetNet*sig, NetNet*sel, - unsigned wid); + unsigned wid, bool signed_flag = false); ~NetPartSelect(); unsigned base() const; unsigned width() const; dir_t dir() const; + /* Is the select signal signed? */ + bool signed_flag() const { return signed_flag_; } virtual void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*tgt) const; @@ -1809,6 +1811,7 @@ class NetPartSelect : public NetNode { unsigned off_; unsigned wid_; dir_t dir_; + bool signed_flag_; }; /* diff --git a/t-dll.cc b/t-dll.cc index 45d7851d7..d89bc58d0 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2153,8 +2153,12 @@ bool dll_target::part_select(const NetPartSelect*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - /* Part selects are always unsigned. */ - obj->u_.part.signed_flag = 0; + /* Part selects are always unsigned, so we use this to indicate + * if the part select base signal is signed or not. */ + if (net->signed_flag()) + obj->u_.part.signed_flag = 1; + else + obj->u_.part.signed_flag = 0; /* Choose the width of the part select. */ obj->width = net->width(); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 3b54dfdc9..bb8cb76e2 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1654,6 +1654,14 @@ static void draw_lpm_part(ivl_lpm_t net) fprintf(vvp_out, ", %u, %u;\n", base, width); } else { const char*sel_symbol = draw_net_input(sel); + /* We need to enhance .part/v to support a signed index. */ + if (ivl_lpm_signed(net) && width_of_nexus(sel) < 8*sizeof(int)) { + fprintf(stderr, "%s:%u: tgt-vvp warning: V0.9 may give " + "incorrect results for a select with a " + "signed index less than %zu bits.\n", + ivl_lpm_file(net), ivl_lpm_lineno(net), + 8*sizeof(int)); + } fprintf(vvp_out, "L_%p%s .part/v %s", net, dly, draw_net_input(ivl_lpm_data(net,0))); fprintf(vvp_out, ", %s", sel_symbol);