Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Major rewrite of indexed part selects.

This patch is a major rewrite of the indexed part selects (+: and -:).

It made the following enhancements:

1. Make indexed part selects work correctly with both big and little
   endian vectors.

2. Add a warning flag that warns about constant out of bounds/or 'bx
   indexed selects.

3. Moved the -: parameter code to its own routine.

4. Added support for straddling before part selects in a CA.

5. Added more assert(! number_is_unknown) statements.

6. Add warning for &PV<> select with a signed index signal that is
  less than the width of an int. This will be fixed later.

7. Add support for loading a 'bx/'bz constant into a numeric register.

8. Add a number of signed value fixes to the compiler/code generator.

9. Major fix of draw_select_expr() in the code generator.
  • Loading branch information...
commit 2b17366ad5d59b458042c15311c3cb5bcd467553 1 parent 8623f80
@caryr caryr authored committed
View
6 PExpr.h
@@ -339,6 +339,12 @@ class PEIdent : public PExpr {
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
+ NetExpr*elaborate_expr_param_idx_do_(Design*des,
+ NetScope*scope,
+ const NetExpr*par,
+ NetScope*found,
+ const NetExpr*par_msb,
+ const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_net(Design*des,
NetScope*scope,
NetNet*net,
View
311 elab_expr.cc
@@ -2210,12 +2210,12 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
}
static verinum param_part_select_bits(const verinum&par_val, long wid,
- long lsv, long par_lsv)
+ long lsv)
{
verinum result (verinum::Vx, wid, true);
for (long idx = 0 ; idx < wid ; idx += 1) {
- long off = idx + lsv - par_lsv;
+ long off = idx + lsv;
if (off < 0)
result.set(idx, verinum::Vx);
else if (off < (long)par_val.len())
@@ -2230,7 +2230,7 @@ static verinum param_part_select_bits(const verinum&par_val, long wid,
// If the input is a string, and the part select is working on
// byte boundaries, then make the result into a string.
- if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
+ if (par_val.is_string() && (labs(lsv)%8 == 0) && (wid%8 == 0))
return result.as_string();
return result;
@@ -2286,28 +2286,56 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex);
- verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
+ verinum result = param_part_select_bits(par_ex->value(), wid, lsv-par_lsv);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
+static void warn_param_ob(long par_msv, long par_lsv, bool defined,
+ long par_base, unsigned long wid, long pwid,
+ const LineInfo *info, perm_string name, bool up)
+{
+ long par_max;
+
+ if (defined) {
+ if (par_msv < par_lsv) par_max = par_lsv-par_msv;
+ else par_max = par_msv-par_lsv;
+ } else {
+ if (pwid < 0) par_max = integer_width;
+ else par_max = pwid;
+ }
+
+ /* Is this a select before the start of the parameter? */
+ if (par_base < 0) {
+ cerr << info->get_fileline() << ": warning: " << name << "["
+ << par_base;
+ if (up) cerr << "+:";
+ else cerr << "-:";
+ cerr << wid << "] is selecting before vector." << endl;
+ }
+
+ /* Is this a select after the end of the parameter? */
+ if (par_base + (long)wid - 1 > par_max) {
+ cerr << info->get_fileline() << ": warning: " << name << "["
+ << par_base << "+:" << wid << "] is selecting after vector."
+ << endl;
+ }
+}
+
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
-
long par_msv, par_lsv;
- bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
- if (!flag)
- return 0;
+ if(! calculate_param_range_(des, scope, par_msb, par_msv,
+ par_lsb, par_lsv)) return 0;
NetExpr*base = calculate_up_do_base_(des, scope);
- if (base == 0)
- return 0;
+ if (base == 0) return 0;
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);
@@ -2323,22 +2351,139 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
// Handle the special case that the base is constant. In this
// case, just precalculate the entire constant result.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
+ if (! base_c->value().is_defined()) {
+ NetEConst *ex;
+ ex = new NetEConst(verinum(verinum::Vx, wid, true));
+ ex->set_line(*this);
+ if (warn_ob_select) {
+ perm_string name = peek_tail_name(path_);
+ cerr << get_fileline() << ": warning: " << name
+ << "['bx+:" << wid
+ << "] is always outside vector." << endl;
+ }
+ return ex;
+ }
+ long lsv = base_c->value().as_long();
+ long par_base = par_lsv;
+
+ // Watch out for reversed bit numbering. We're making
+ // the part select from LSB to MSB.
+ if (par_msv < par_lsv) {
+ par_base = lsv;
+ lsv = par_lsv - wid + 1;
+ }
+
+ if (warn_ob_select) {
+ bool defined = true;
+ // Check to see if the parameter has a defined range.
+ if (par_msb == 0) {
+ assert(par_lsb == 0);
+ defined = false;
+ }
+ // Get the parameter values width.
+ long pwid = -1;
+ if (par_ex->has_width()) pwid = par_ex->expr_width()-1;
+ perm_string name = peek_tail_name(path_);
+ warn_param_ob(par_msv, par_lsv, defined, lsv-par_base, wid,
+ pwid, this, name, true);
+ }
+ verinum result = param_part_select_bits(par_ex->value(), wid,
+ lsv-par_base);
+ NetEConst*result_ex = new NetEConst(result);
+ result_ex->set_line(*this);
+ return result_ex;
+ }
+
+ if (par_msv >= par_lsv) {
+ if (par_lsv != 0) base = make_add_expr(base, -par_lsv);
+ } else {
+ base = make_sub_expr(par_lsv-wid+1, base);
+ }
+
+ NetExpr*tmp = par->dup_expr();
+ tmp = new NetESelect(tmp, base, wid);
+ tmp->set_line(*this);
+ return tmp;
+}
+
+NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
+ const NetExpr*par,
+ NetScope*found_in,
+ const NetExpr*par_msb,
+ const NetExpr*par_lsb) const
+{
+ long par_msv, par_lsv;
+ if(! calculate_param_range_(des, scope, par_msb, par_msv,
+ par_lsb, par_lsv)) return 0;
+
+ NetExpr*base = calculate_up_do_base_(des, scope);
+ if (base == 0) return 0;
+
+ unsigned long wid = 0;
+ calculate_up_do_width_(des, scope, wid);
+
+ const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
+ ivl_assert(*this, par_ex);
+
+ if (debug_elaborate)
+ cerr << get_fileline() << ": debug: Calculate part select "
+ << "[" << *base << "-:" << wid << "] from range "
+ << "[" << par_msv << ":" << par_lsv << "]." << endl;
+
+ // Handle the special case that the base is constant. In this
+ // case, just precalculate the entire constant result.
+ if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
+ if (! base_c->value().is_defined()) {
+ NetEConst *ex;
+ ex = new NetEConst(verinum(verinum::Vx, wid, true));
+ ex->set_line(*this);
+ if (warn_ob_select) {
+ perm_string name = peek_tail_name(path_);
+ cerr << get_fileline() << ": warning: " << name
+ << "['bx-:" << wid
+ << "] is always outside vector." << endl;
+ }
+ return ex;
+ }
long lsv = base_c->value().as_long();
+ long par_base = par_lsv + wid - 1;
// Watch out for reversed bit numbering. We're making
// the part select from LSB to MSB.
- if (par_msv < par_lsv)
- lsv = lsv - wid + 1;
+ if (par_msv < par_lsv) {
+ par_base = lsv;
+ lsv = par_lsv;
+ }
+
+ if (warn_ob_select) {
+ bool defined = true;
+ // Check to see if the parameter has a defined range.
+ if (par_msb == 0) {
+ assert(par_lsb == 0);
+ defined = false;
+ }
+ // Get the parameter values width.
+ long pwid = -1;
+ if (par_ex->has_width()) pwid = par_ex->expr_width()-1;
+ perm_string name = peek_tail_name(path_);
+ warn_param_ob(par_msv, par_lsv, defined, lsv-par_base, wid,
+ pwid, this, name, false);
+ }
verinum result = param_part_select_bits(par_ex->value(), wid,
- lsv, par_lsv);
+ lsv-par_base);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
- if ((par_msv < par_lsv) && (wid>1))
- base = make_add_expr(base, 1-(long)wid);
+ if (par_msv >= par_lsv) {
+ if (long offset = par_lsv+wid-1) {
+ base = make_add_expr(base, -offset);
+ }
+ } else {
+ base = make_sub_expr(par_lsv, base);
+ }
NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid);
@@ -2385,49 +2530,16 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
par_msb, par_lsb);
+ if (use_sel == index_component_t::SEL_IDX_DO)
+ return elaborate_expr_param_idx_do_(des, scope, par, found_in,
+ par_msb, par_lsb);
+
// NOTE TO SELF (continued): The code below should be
// rewritten in the above format, as I get to it.
NetExpr*tmp = par->dup_expr();
- if (use_sel == index_component_t::SEL_IDX_DO) {
-
- ivl_assert(*this, !name_tail.index.empty());
- const index_component_t&index_tail = name_tail.index.back();
- ivl_assert(*this, index_tail.msb);
- ivl_assert(*this, index_tail.lsb);
-
- /* Get and evaluate the width of the index
- select. This must be constant. */
- need_constant_expr = true;
- NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
- need_constant_expr = false;
- NetEConst*wid_ec = dynamic_cast<NetEConst*> (wid_ex);
- if (wid_ec == 0) {
- cerr << index_tail.lsb->get_fileline() << ": error: "
- << "Second expression of indexed part select "
- << "most be constant." << endl;
- des->errors += 1;
- return 0;
- }
-
- unsigned wid = wid_ec->value().as_ulong();
-
- NetExpr*idx_ex = elab_and_eval(des, scope, index_tail.msb, -1);
- if (idx_ex == 0) {
- return 0;
- }
-
- if (use_sel == index_component_t::SEL_IDX_DO && wid > 1) {
- idx_ex = make_add_expr(idx_ex, 1-(long)wid);
- }
-
-
- /* Wrap the param expression with a part select. */
- tmp = new NetESelect(tmp, idx_ex, wid);
-
-
- } else if (use_sel == index_component_t::SEL_BIT) {
+ if (use_sel == index_component_t::SEL_BIT) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
@@ -2768,15 +2880,47 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (net->sig()->sb_to_idx(lsv) == 0 &&
wid == net->vector_width()) {
delete base;
+ net->cast_signed(false);
return net;
}
+ long offset = 0;
+ if (net->msi() < net->lsi()) {
+ offset = -wid + 1;
+ }
// Otherwise, make a part select that covers the right
// range.
- ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
+ ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
+ offset));
+ if (warn_ob_select) {
+ long rel_base = net->sig()->sb_to_idx(lsv) + offset;
+ if (rel_base < 0) {
+ cerr << get_fileline() << ": warning: "
+ << net->name();
+ if (net->word_index()) cerr << "[]";
+ cerr << "[" << lsv << "+:" << wid
+ << "] is selecting before vector." << endl;
+ }
+ if (rel_base + wid > net->vector_width()) {
+ cerr << get_fileline() << ": warning: "
+ << net->name();
+ if (net->word_index()) cerr << "[]";
+ cerr << "[" << lsv << "+:" << wid
+ << "] is selecting after vector." << endl;
+ }
+ }
} else {
// Return 'bx for an undefined base.
- ex = new NetEConst(verinum(verinum::Vx, 1, false));
+ ex = new NetEConst(verinum(verinum::Vx, wid, true));
+ ex->set_line(*this);
+ delete base;
+ if (warn_ob_select) {
+ cerr << get_fileline() << ": warning: " << net->name();
+ if (net->word_index()) cerr << "[]";
+ cerr << "['bx+:" << wid
+ << "] is always outside vector." << endl;
+ }
+ return ex;
}
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
@@ -2787,11 +2931,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (net->msi() > net->lsi()) {
if (long offset = net->lsi())
- base = make_add_expr(base, 0-offset);
+ base = make_add_expr(base, -offset);
} else {
- long vwid = net->lsi() - net->msi() + 1;
- long offset = net->msi();
- base = make_sub_expr(vwid-offset-wid, base);
+ base = make_sub_expr(net->lsi()-wid+1, base);
}
NetESelect*ss = new NetESelect(net, base, wid);
@@ -2830,15 +2972,47 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
wid == net->vector_width()) {
delete base;
+ net->cast_signed(false);
return net;
}
+ long offset = 0;
+ if (net->msi() > net->lsi()) {
+ offset = -wid + 1;
+ }
// Otherwise, make a part select that covers the right
// range.
- ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1));
+ ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
+ offset));
+ if (warn_ob_select) {
+ long rel_base = net->sig()->sb_to_idx(lsv) + offset;
+ if (rel_base < 0) {
+ cerr << get_fileline() << ": warning: "
+ << net->name();
+ if (net->word_index()) cerr << "[]";
+ cerr << "[" << lsv << "+:" << wid
+ << "] is selecting before vector." << endl;
+ }
+ if (rel_base + wid > net->vector_width()) {
+ cerr << get_fileline() << ": warning: "
+ << net->name();
+ if (net->word_index()) cerr << "[]";
+ cerr << "[" << lsv << "-:" << wid
+ << "] is selecting after vector." << endl;
+ }
+ }
} else {
// Return 'bx for an undefined base.
- ex = new NetEConst(verinum(verinum::Vx, 1, false));
+ ex = new NetEConst(verinum(verinum::Vx, wid, true));
+ ex->set_line(*this);
+ delete base;
+ if (warn_ob_select) {
+ cerr << get_fileline() << ": warning: " << net->name();
+ if (net->word_index()) cerr << "[]";
+ cerr << "['bx-:" << wid
+ << "] is always outside vector." << endl;
+ }
+ return ex;
}
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
@@ -2847,16 +3021,19 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
return ss;
}
- long offset = net->lsi();
- NetExpr*base_adjusted = wid > 1
- ? make_add_expr(base,1-(long)wid-offset)
- : (offset == 0? base : make_add_expr(base, 0-offset));
- NetESelect*ss = new NetESelect(net, base_adjusted, wid);
+ if (net->msi() > net->lsi()) {
+ if (long offset = net->lsi()+wid-1)
+ base = make_add_expr(base, -offset);
+ } else {
+ base = make_sub_expr(net->lsi(), base);
+ }
+
+ NetESelect*ss = new NetESelect(net, base, wid);
ss->set_line(*this);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Elaborate part "
- << "select base="<< *base_adjusted << ", wid="<< wid << endl;
+ << "select base="<< *base << ", wid="<< wid << endl;
}
return ss;
View
80 elab_lval.cc
@@ -476,14 +476,78 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
- /* Correct the mux for the range of the vector. */
- if (reg->msb() < reg->lsb())
- base = make_sub_expr(reg->lsb(), base);
- else if (reg->lsb() != 0)
- base = make_add_expr(base, - reg->lsb());
-
- if (use_sel == index_component_t::SEL_IDX_DO && wid > 1 ) {
- base = make_add_expr(base, 1-(long)wid);
+ // Handle the special case that the base is constant. For this
+ // case we can reduce the expression.
+ if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
+ // For the undefined case just let the constant pass and
+ // we will handle it in the code generator.
+ if (base_c->value().is_defined()) {
+ long lsv = base_c->value().as_long();
+ long offset = 0;
+ if (((reg->msb() < reg->lsb()) &&
+ use_sel == index_component_t::SEL_IDX_UP) ||
+ ((reg->msb() > reg->lsb()) &&
+ use_sel == index_component_t::SEL_IDX_DO)) {
+ offset = -wid + 1;
+ }
+ delete base;
+ base = new NetEConst(verinum(reg->sb_to_idx(lsv) + offset));
+ if (warn_ob_select) {
+ long rel_base = reg->sb_to_idx(lsv) + offset;
+ if (rel_base < 0) {
+ cerr << get_fileline() << ": warning: " << reg->name();
+ if (reg->array_dimensions() > 0) cerr << "[]";
+ cerr << "[" << lsv;
+ if (use_sel == index_component_t::SEL_IDX_UP) {
+ cerr << "+:";
+ } else {
+ cerr << "-:";
+ }
+ cerr << wid << "] is selecting before vector." << endl;
+ }
+ if (rel_base + wid > reg->vector_width()) {
+ cerr << get_fileline() << ": warning: " << reg->name();
+ if (reg->array_dimensions() > 0) cerr << "[]";
+ cerr << "[" << lsv;
+ if (use_sel == index_component_t::SEL_IDX_UP) {
+ cerr << "+:";
+ } else {
+ cerr << "-:";
+ }
+ cerr << wid << "] is selecting after vector." << endl;
+ }
+ }
+ } else {
+ if (warn_ob_select) {
+ cerr << get_fileline() << ": warning: " << reg->name();
+ if (reg->array_dimensions() > 0) cerr << "[]";
+ cerr << "['bx";
+ if (use_sel == index_component_t::SEL_IDX_UP) {
+ cerr << "+:";
+ } else {
+ cerr << "-:";
+ }
+ cerr << wid << "] is always outside vector." << endl;
+ }
+ }
+ } else {
+ /* Correct the mux for the range of the vector. */
+ if (use_sel == index_component_t::SEL_IDX_UP) {
+ if (reg->msb() > reg->lsb()) {
+ if (long offset = reg->lsb())
+ base = make_add_expr(base, -offset);
+ } else {
+ base = make_sub_expr(reg->lsb()-wid+1, base);
+ }
+ } else {
+ // This is assumed to be a SEL_IDX_DO.
+ if (reg->msb() > reg->lsb()) {
+ if (long offset = reg->lsb()+wid-1)
+ base = make_add_expr(base, -offset);
+ } else {
+ base = make_sub_expr(reg->lsb(), base);
+ }
+ }
}
if (debug_elaborate)
View
46 elab_net.cc
@@ -238,15 +238,33 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
return 0;
}
- long midx_val = tmp->value().as_long();
- midx = sig->sb_to_idx(midx_val);
- delete tmp_ex;
-
/* The width (a constant) is calculated here. */
unsigned long wid = 0;
bool flag = calculate_up_do_width_(des, scope, wid);
- if (! flag)
+ if (! flag) return false;
+
+ /* We have an undefined index and that is out of range. */
+ if (! tmp->value().is_defined()) {
+ if (warn_ob_select) {
+ cerr << get_fileline() << ": warning: "
+ << sig->name();
+ if (sig->array_dimensions() > 0) cerr << "[]";
+ cerr << "['bx";
+ if (index_tail.sel ==
+ index_component_t::SEL_IDX_UP) {
+ cerr << "+:";
+ } else {
+ cerr << "-:";
+ }
+ cerr << wid << "] is always outside vector."
+ << endl;
+ }
return false;
+ }
+
+ long midx_val = tmp->value().as_long();
+ midx = sig->sb_to_idx(midx_val);
+ delete tmp_ex;
if (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(midx_val+wid-1);
@@ -260,9 +278,19 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
/* Warn about an indexed part select that is out of range. */
- if (midx >= (long)sig->vector_width() || lidx < 0) {
- cerr << get_fileline() << ": warning: Indexed part "
- "select " << sig->name();
+ if (warn_ob_select && (lidx < 0)) {
+ cerr << get_fileline() << ": warning: " << sig->name();
+ if (sig->array_dimensions() > 0) cerr << "[]";
+ cerr << "[" << midx_val;
+ if (index_tail.sel == index_component_t::SEL_IDX_UP) {
+ cerr << "+:";
+ } else {
+ cerr << "-:";
+ }
+ cerr << wid << "] is selecting before vector." << endl;
+ }
+ if (warn_ob_select && (midx >= (long)sig->vector_width())) {
+ cerr << get_fileline() << ": warning: " << sig->name();
if (sig->array_dimensions() > 0) {
cerr << "[]";
}
@@ -272,7 +300,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
} else {
cerr << "-:";
}
- cerr << wid << "] is out of range." << endl;
+ cerr << wid << "] is selecting after vector." << endl;
}
/* This is completely out side the signal so just skip it. */
View
9 netlist.cc
@@ -914,9 +914,8 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
pin(1).set_dir(Link::INPUT);
break;
case NetPartSelect::PV:
- pin(0).set_dir(Link::INPUT);
- pin(1).set_dir(Link::OUTPUT);
- break;
+ /* Only a vector to part can be a variable select. */
+ assert(0);
}
pin(2).set_dir(Link::INPUT);
@@ -2349,12 +2348,12 @@ NetNet* NetESignal::sig()
return net_;
}
-unsigned NetESignal::lsi() const
+long NetESignal::lsi() const
{
return net_->lsb();
}
-unsigned NetESignal::msi() const
+long NetESignal::msi() const
{
return net_->msb();
}
View
4 netlist.h
@@ -3829,8 +3829,8 @@ class NetESignal : public NetExpr {
const NetNet* sig() const;
NetNet* sig();
// Declared vector dimensions for the signal.
- unsigned msi() const;
- unsigned lsi() const;
+ long msi() const;
+ long lsi() const;
virtual ivl_variable_type_t expr_type() const;
View
15 tgt-vvp/draw_vpi.c
@@ -109,6 +109,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex,IMM_WID, 0)) {
+ assert(! number_is_unknown(word_ex));
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
@@ -130,6 +131,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, IMM_WID, 0)) {
+ assert(! number_is_unknown(word_ex));
use_word = get_number_immediate(word_ex);
use_word_defined = 1;
word_ex = 0;
@@ -185,6 +187,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
/* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) {
+ assert(! number_is_unknown(bexpr));
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_number_immediate(bexpr),
@@ -206,9 +209,19 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
return 0;
}
} else {
- /* Fallback case: evaluate the expression. */
+ /* Fallback case: evaluate the expression. */
struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
+ /* We need to enhance &PV<> to support a signed index. */
+ if (ivl_expr_signed(bexpr) &&
+ (ivl_expr_width(bexpr) < 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 %d bits.\n",
+ ivl_expr_file(expr),
+ ivl_expr_lineno(expr),
+ 8*sizeof(int));
+ }
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
ivl_expr_signal(vexpr),
rv.base, rv.wid,
View
109 tgt-vvp/eval_expr.c
@@ -174,6 +174,12 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
case IVL_EX_ULONG:
{
assert(number_is_immediate(expr, IMM_WID, 1));
+ if (number_is_unknown(expr)) {
+ /* We are loading a 'bx so mimic %ix/get. */
+ fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", ix);
+ fprintf(vvp_out, " %%mov 4, 1, 1;\n");
+ break;
+ }
long imm = get_number_immediate(expr);
if (imm >= 0) {
fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", ix, imm);
@@ -192,6 +198,7 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
unsigned word = 0;
if (ivl_signal_dimensions(sig) > 0) {
ivl_expr_t ixe;
+ char*type = ivl_expr_signed(expr) ? "/s" : "";
/* Detect the special case that this is a
variable array. In this case, the ix/getv
@@ -199,20 +206,21 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
if (ivl_signal_type(sig) == IVL_SIT_REG) {
struct vector_info rv;
rv = draw_eval_expr(expr, 0);
- fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
- ix, rv.base, rv.wid);
+ fprintf(vvp_out, " %%ix/get%s %u, %u, %u;\n",
+ type, ix, rv.base, rv.wid);
clr_vector(rv);
break;
}
ixe = ivl_expr_oper1(expr);
- if (number_is_immediate(ixe, IMM_WID, 0))
+ if (number_is_immediate(ixe, IMM_WID, 0)) {
+ assert(! number_is_unknown(ixe));
word = get_number_immediate(ixe);
- else {
+ } else {
struct vector_info rv;
rv = draw_eval_expr(expr, 0);
- fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
- ix, rv.base, rv.wid);
+ fprintf(vvp_out, " %%ix/get%s %u, %u, %u;\n",
+ type, ix, rv.base, rv.wid);
clr_vector(rv);
break;
}
@@ -226,8 +234,14 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
default: {
struct vector_info rv;
rv = draw_eval_expr(expr, 0);
- fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
- ix, rv.base, rv.wid);
+ /* Is this a signed expression? */
+ if (ivl_expr_signed(expr)) {
+ fprintf(vvp_out, " %%ix/get/s %u, %u, %u;\n",
+ ix, rv.base, rv.wid);
+ } else {
+ fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
+ ix, rv.base, rv.wid);
+ }
clr_vector(rv);
break;
}
@@ -274,7 +288,10 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
{
unsigned wid;
struct vector_info lv;
- unsigned long imm = get_number_immediate(re);
+ unsigned long imm;
+ assert(number_is_immediate(re, IMM_WID, 0));
+ assert(! number_is_unknown(re));
+ imm = get_number_immediate(re);
wid = ivl_expr_width(le);
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag);
@@ -991,6 +1008,8 @@ static struct vector_info draw_logic_immediate(ivl_expr_t exp,
unsigned wid)
{
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
+ assert(number_is_immediate(re, IMM_WID, 0));
+ assert(! number_is_unknown(re));
unsigned long imm = get_number_immediate(re);
assert(lv.base >= 4);
@@ -1241,8 +1260,10 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
int signed_flag)
{
struct vector_info lv;
- long imm = get_number_immediate(re);
+ long imm;
+ assert(! number_is_unknown(re));
assert(number_is_immediate(re, IMM_WID, 1));
+ imm = get_number_immediate(re);
lv.base = allocate_vector(wid);
lv.wid = wid;
if (lv.base == 0) {
@@ -1270,6 +1291,8 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(lv.wid == wid);
+ assert(! number_is_unknown(re));
+ assert(number_is_immediate(re, IMM_WID, 0));
imm = get_number_immediate(re);
/* This shouldn't generally happen, because the elaborator
@@ -1308,7 +1331,7 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
}
break;
- case 2: /* Left expression is X or Z */
+ case 2: /* Left expression is 'bx or 'bz */
case 3:
lv.base = 2;
break;
@@ -1335,6 +1358,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(lv.wid == wid);
+ assert(! number_is_unknown(re));
+ assert(number_is_immediate(re, IMM_WID, 0));
imm = get_number_immediate(re);
if (imm == 0)
return lv;
@@ -1379,6 +1404,8 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le,
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(lv.wid == wid);
+ assert(! number_is_unknown(re));
+ assert(number_is_immediate(re, IMM_WID, 0));
imm = get_number_immediate(re);
if (imm == 0)
return lv;
@@ -2253,7 +2280,7 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
unsigned bit_width,
unsigned wid)
{
- unsigned idx;
+ unsigned idx, label;
ivl_signal_t sig = ivl_expr_signal(sube);
/* unsigned sig_wid = ivl_expr_width(sube); */
ivl_expr_t ix = ivl_expr_oper1(sube);
@@ -2263,7 +2290,18 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
draw_eval_expr_into_integer(ix, 3);
- fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
+ label = local_count++;
+ /* We can safely skip the bit index load below if the array word
+ * index is undefined. We need to do this so that the bit index
+ * load does not reset bit 4 to zero by loading a defined value. */
+ fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, label);
+ if (ivl_expr_signed(bit_idx)) {
+ fprintf(vvp_out, " %%ix/get/s 0, %u, %u;\n", shiv.base,
+ shiv.wid);
+ } else {
+ fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
+ }
+ fprintf(vvp_out, "T_%d.%d ;\n", thread_count, label);
if (shiv.base >= 8)
clr_vector(shiv);
@@ -2294,7 +2332,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* Use this word of the signal. */
unsigned use_word = 0;
- unsigned use_wid;
+ unsigned use_wid, lab_x, lab_end;
/* If this is an access to an array, try to get the index as a
constant. If it is (and the array is not a reg array then
@@ -2311,6 +2349,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* The index is constant, so we can return to direct
readout with the specific word selected. */
+ assert(! number_is_unknown(ix));
use_word = get_number_immediate(ix);
}
@@ -2318,6 +2357,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
the signal (or the entire width). Just load the early bits
in one go. */
if (number_is_immediate(bit_idx, 32, 0)
+ && !number_is_unknown(bit_idx)
&& get_number_immediate(bit_idx) == 0
&& (ivl_expr_width(sube) >= bit_wid)) {
@@ -2343,6 +2383,12 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
res.wid = wid;
assert(res.base);
+ lab_x = local_count++;
+ lab_end = local_count++;
+
+ /* If the index is 'bx then we just return 'bx. */
+ fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_x);
+
use_wid = res.wid;
if (use_wid > bit_wid)
use_wid = bit_wid;
@@ -2353,6 +2399,11 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
res.base + use_wid, res.wid - use_wid);
+ fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end);
+ fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_x);
+ fprintf(vvp_out, " %%mov %u, 2, %u;\n", res.base, res.wid);
+ fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end);
+
return res;
}
@@ -2371,6 +2422,7 @@ static void draw_select_signal_dest(ivl_expr_t sube,
if ((ivl_signal_dimensions(sig) == 0)
&& (ivl_expr_width(sube) >= dest.wid)
&& number_is_immediate(bit_idx, 32, 0)
+ && ! number_is_unknown(bit_idx)
&& get_number_immediate(bit_idx) == 0) {
unsigned use_word = 0;
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Select %u out of %u bits\n",
@@ -2401,6 +2453,8 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
ivl_expr_t shift = ivl_expr_oper2(exp);
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1;
+ int cmp;
+ unsigned lab_l, lab_end;
res.wid = wid;
@@ -2444,7 +2498,12 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
return res;
}
- fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
+ if (ivl_expr_signed(shift)) {
+ fprintf(vvp_out, " %%ix/get/s 0, %u, %u;\n", shiv.base,
+ shiv.wid);
+ } else {
+ fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
+ }
clr_vector(shiv);
/* If the subv result is a magic constant, then make a copy in
@@ -2458,7 +2517,27 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
subv = res;
}
+ lab_l = local_count++;
+ lab_end = local_count++;
+ /* If we have an undefined index then just produce a 'bx result. */
+ fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_l);
+
+ cmp = allocate_word();
+ assert(subv.wid >= wid);
+ /* Determine if we need to shift a 'bx into the top. */
+ fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", cmp, subv.wid - wid);
+ fprintf(vvp_out, " %%cmp/ws %u, 0;\n", cmp);
+ clr_word(cmp);
+ fprintf(vvp_out, " %%jmp/1 T_%d.%d, 5;\n", thread_count, lab_l);
+ /* Clear the cmp bit if the two values are equal. */
+ fprintf(vvp_out, " %%mov 4, 0, 1;\n");
fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", subv.base, subv.wid);
+ fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end);
+ fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_l);
+ /* Multiply by -1. */
+ fprintf(vvp_out, " %%ix/mul 0, %u, %u;\n", 0xFFFFFFFF, 0xFFFFFFFF);
+ fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", subv.base, subv.wid);
+ fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end);
if (subv.wid > wid) {
res.base = subv.base;
View
9 tgt-vvp/vvp_scope.c
@@ -558,6 +558,9 @@ static void draw_delay(ivl_net_logic_t lptr)
assert(number_is_immediate(d0, 64, 0));
assert(number_is_immediate(d1, 64, 0));
assert(number_is_immediate(d2, 64, 0));
+ assert(! number_is_unknown(d0));
+ assert(! number_is_unknown(d1));
+ assert(! number_is_unknown(d2));
if (d0 == d1 && d1 == d2)
fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
@@ -874,6 +877,9 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
&& number_is_immediate(fall_exp,64,0)
&& number_is_immediate(decay_exp,64,0)) {
+ assert(! number_is_unknown(rise_exp));
+ assert(! number_is_unknown(fall_exp));
+ assert(! number_is_unknown(decay_exp));
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
lptr, get_number_immediate(rise_exp),
get_number_immediate(fall_exp),
@@ -1079,6 +1085,9 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
+ assert(! number_is_unknown(d_rise));
+ assert(! number_is_unknown(d_fall));
+ assert(! number_is_unknown(d_decay));
dly = "/d";
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise),
Please sign in to comment.
Something went wrong with that request. Please try again.