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.
This commit is contained in:
parent
8623f804f2
commit
2b17366ad5
6
PExpr.h
6
PExpr.h
|
|
@ -339,6 +339,12 @@ class PEIdent : public PExpr {
|
||||||
NetScope*found,
|
NetScope*found,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb) const;
|
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,
|
NetExpr*elaborate_expr_net(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetNet*net,
|
NetNet*net,
|
||||||
|
|
|
||||||
311
elab_expr.cc
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,
|
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);
|
verinum result (verinum::Vx, wid, true);
|
||||||
|
|
||||||
for (long idx = 0 ; idx < wid ; idx += 1) {
|
for (long idx = 0 ; idx < wid ; idx += 1) {
|
||||||
long off = idx + lsv - par_lsv;
|
long off = idx + lsv;
|
||||||
if (off < 0)
|
if (off < 0)
|
||||||
result.set(idx, verinum::Vx);
|
result.set(idx, verinum::Vx);
|
||||||
else if (off < (long)par_val.len())
|
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
|
// If the input is a string, and the part select is working on
|
||||||
// byte boundaries, then make the result into a string.
|
// 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.as_string();
|
||||||
|
|
||||||
return result;
|
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);
|
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||||
ivl_assert(*this, par_ex);
|
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);
|
NetEConst*result_ex = new NetEConst(result);
|
||||||
result_ex->set_line(*this);
|
result_ex->set_line(*this);
|
||||||
|
|
||||||
return result_ex;
|
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,
|
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*found_in,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb) const
|
const NetExpr*par_lsb) const
|
||||||
{
|
{
|
||||||
|
|
||||||
long par_msv, par_lsv;
|
long par_msv, par_lsv;
|
||||||
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
if(! calculate_param_range_(des, scope, par_msb, par_msv,
|
||||||
if (!flag)
|
par_lsb, par_lsv)) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||||
if (base == 0)
|
if (base == 0) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned long wid = 0;
|
unsigned long wid = 0;
|
||||||
calculate_up_do_width_(des, scope, wid);
|
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
|
// Handle the special case that the base is constant. In this
|
||||||
// case, just precalculate the entire constant result.
|
// case, just precalculate the entire constant result.
|
||||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
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 lsv = base_c->value().as_long();
|
||||||
|
long par_base = par_lsv;
|
||||||
|
|
||||||
// Watch out for reversed bit numbering. We're making
|
// Watch out for reversed bit numbering. We're making
|
||||||
// the part select from LSB to MSB.
|
// the part select from LSB to MSB.
|
||||||
if (par_msv < par_lsv)
|
if (par_msv < par_lsv) {
|
||||||
lsv = lsv - wid + 1;
|
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,
|
verinum result = param_part_select_bits(par_ex->value(), wid,
|
||||||
lsv, par_lsv);
|
lsv-par_base);
|
||||||
NetEConst*result_ex = new NetEConst(result);
|
NetEConst*result_ex = new NetEConst(result);
|
||||||
result_ex->set_line(*this);
|
result_ex->set_line(*this);
|
||||||
return result_ex;
|
return result_ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((par_msv < par_lsv) && (wid>1))
|
if (par_msv >= par_lsv) {
|
||||||
base = make_add_expr(base, 1-(long)wid);
|
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) {
|
||||||
|
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_base);
|
||||||
|
NetEConst*result_ex = new NetEConst(result);
|
||||||
|
result_ex->set_line(*this);
|
||||||
|
return result_ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
NetExpr*tmp = par->dup_expr();
|
||||||
tmp = new NetESelect(tmp, base, wid);
|
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,
|
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
|
||||||
par_msb, par_lsb);
|
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
|
// NOTE TO SELF (continued): The code below should be
|
||||||
// rewritten in the above format, as I get to it.
|
// rewritten in the above format, as I get to it.
|
||||||
|
|
||||||
NetExpr*tmp = par->dup_expr();
|
NetExpr*tmp = par->dup_expr();
|
||||||
|
|
||||||
if (use_sel == index_component_t::SEL_IDX_DO) {
|
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);
|
|
||||||
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) {
|
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
ivl_assert(*this, !name_tail.index.empty());
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
const index_component_t&index_tail = name_tail.index.back();
|
||||||
ivl_assert(*this, index_tail.msb);
|
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 &&
|
if (net->sig()->sb_to_idx(lsv) == 0 &&
|
||||||
wid == net->vector_width()) {
|
wid == net->vector_width()) {
|
||||||
delete base;
|
delete base;
|
||||||
|
net->cast_signed(false);
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long offset = 0;
|
||||||
|
if (net->msi() < net->lsi()) {
|
||||||
|
offset = -wid + 1;
|
||||||
|
}
|
||||||
// Otherwise, make a part select that covers the right
|
// Otherwise, make a part select that covers the right
|
||||||
// range.
|
// 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 {
|
} else {
|
||||||
// Return 'bx for an undefined base.
|
// 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);
|
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||||
ss->set_line(*this);
|
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 (net->msi() > net->lsi()) {
|
||||||
if (long offset = net->lsi())
|
if (long offset = net->lsi())
|
||||||
base = make_add_expr(base, 0-offset);
|
base = make_add_expr(base, -offset);
|
||||||
} else {
|
} else {
|
||||||
long vwid = net->lsi() - net->msi() + 1;
|
base = make_sub_expr(net->lsi()-wid+1, base);
|
||||||
long offset = net->msi();
|
|
||||||
base = make_sub_expr(vwid-offset-wid, base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetESelect*ss = new NetESelect(net, base, wid);
|
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) &&
|
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
|
||||||
wid == net->vector_width()) {
|
wid == net->vector_width()) {
|
||||||
delete base;
|
delete base;
|
||||||
|
net->cast_signed(false);
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long offset = 0;
|
||||||
|
if (net->msi() > net->lsi()) {
|
||||||
|
offset = -wid + 1;
|
||||||
|
}
|
||||||
// Otherwise, make a part select that covers the right
|
// Otherwise, make a part select that covers the right
|
||||||
// range.
|
// 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 {
|
} else {
|
||||||
// Return 'bx for an undefined base.
|
// 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);
|
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
@ -2847,16 +3021,19 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
long offset = net->lsi();
|
if (net->msi() > net->lsi()) {
|
||||||
NetExpr*base_adjusted = wid > 1
|
if (long offset = net->lsi()+wid-1)
|
||||||
? make_add_expr(base,1-(long)wid-offset)
|
base = make_add_expr(base, -offset);
|
||||||
: (offset == 0? base : make_add_expr(base, 0-offset));
|
} else {
|
||||||
NetESelect*ss = new NetESelect(net, base_adjusted, wid);
|
base = make_sub_expr(net->lsi(), base);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetESelect*ss = new NetESelect(net, base, wid);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
||||||
if (debug_elaborate) {
|
if (debug_elaborate) {
|
||||||
cerr << get_fileline() << ": debug: Elaborate part "
|
cerr << get_fileline() << ": debug: Elaborate part "
|
||||||
<< "select base="<< *base_adjusted << ", wid="<< wid << endl;
|
<< "select base="<< *base << ", wid="<< wid << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
|
|
|
||||||
80
elab_lval.cc
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);
|
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||||
|
|
||||||
/* Correct the mux for the range of the vector. */
|
// Handle the special case that the base is constant. For this
|
||||||
if (reg->msb() < reg->lsb())
|
// case we can reduce the expression.
|
||||||
base = make_sub_expr(reg->lsb(), base);
|
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||||
else if (reg->lsb() != 0)
|
// For the undefined case just let the constant pass and
|
||||||
base = make_add_expr(base, - reg->lsb());
|
// we will handle it in the code generator.
|
||||||
|
if (base_c->value().is_defined()) {
|
||||||
if (use_sel == index_component_t::SEL_IDX_DO && wid > 1 ) {
|
long lsv = base_c->value().as_long();
|
||||||
base = make_add_expr(base, 1-(long)wid);
|
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)
|
if (debug_elaborate)
|
||||||
|
|
|
||||||
46
elab_net.cc
46
elab_net.cc
|
|
@ -238,15 +238,33 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
return 0;
|
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. */
|
/* The width (a constant) is calculated here. */
|
||||||
unsigned long wid = 0;
|
unsigned long wid = 0;
|
||||||
bool flag = calculate_up_do_width_(des, scope, wid);
|
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;
|
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)
|
if (index_tail.sel == index_component_t::SEL_IDX_UP)
|
||||||
lidx = sig->sb_to_idx(midx_val+wid-1);
|
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. */
|
/* Warn about an indexed part select that is out of range. */
|
||||||
if (midx >= (long)sig->vector_width() || lidx < 0) {
|
if (warn_ob_select && (lidx < 0)) {
|
||||||
cerr << get_fileline() << ": warning: Indexed part "
|
cerr << get_fileline() << ": warning: " << sig->name();
|
||||||
"select " << 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) {
|
if (sig->array_dimensions() > 0) {
|
||||||
cerr << "[]";
|
cerr << "[]";
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +300,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
} else {
|
} else {
|
||||||
cerr << "-:";
|
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. */
|
/* This is completely out side the signal so just skip it. */
|
||||||
|
|
|
||||||
|
|
@ -914,9 +914,8 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
|
||||||
pin(1).set_dir(Link::INPUT);
|
pin(1).set_dir(Link::INPUT);
|
||||||
break;
|
break;
|
||||||
case NetPartSelect::PV:
|
case NetPartSelect::PV:
|
||||||
pin(0).set_dir(Link::INPUT);
|
/* Only a vector to part can be a variable select. */
|
||||||
pin(1).set_dir(Link::OUTPUT);
|
assert(0);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
pin(2).set_dir(Link::INPUT);
|
pin(2).set_dir(Link::INPUT);
|
||||||
|
|
||||||
|
|
@ -2349,12 +2348,12 @@ NetNet* NetESignal::sig()
|
||||||
return net_;
|
return net_;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NetESignal::lsi() const
|
long NetESignal::lsi() const
|
||||||
{
|
{
|
||||||
return net_->lsb();
|
return net_->lsb();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NetESignal::msi() const
|
long NetESignal::msi() const
|
||||||
{
|
{
|
||||||
return net_->msb();
|
return net_->msb();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3829,8 +3829,8 @@ class NetESignal : public NetExpr {
|
||||||
const NetNet* sig() const;
|
const NetNet* sig() const;
|
||||||
NetNet* sig();
|
NetNet* sig();
|
||||||
// Declared vector dimensions for the signal.
|
// Declared vector dimensions for the signal.
|
||||||
unsigned msi() const;
|
long msi() const;
|
||||||
unsigned lsi() const;
|
long lsi() const;
|
||||||
|
|
||||||
virtual ivl_variable_type_t expr_type() const;
|
virtual ivl_variable_type_t expr_type() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||||
if (word_ex) {
|
if (word_ex) {
|
||||||
/* Some array select have been evaluated. */
|
/* Some array select have been evaluated. */
|
||||||
if (number_is_immediate(word_ex,IMM_WID, 0)) {
|
if (number_is_immediate(word_ex,IMM_WID, 0)) {
|
||||||
|
assert(! number_is_unknown(word_ex));
|
||||||
use_word = get_number_immediate(word_ex);
|
use_word = get_number_immediate(word_ex);
|
||||||
word_ex = 0;
|
word_ex = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -130,6 +131,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||||
if (word_ex) {
|
if (word_ex) {
|
||||||
/* Some array select have been evaluated. */
|
/* Some array select have been evaluated. */
|
||||||
if (number_is_immediate(word_ex, IMM_WID, 0)) {
|
if (number_is_immediate(word_ex, IMM_WID, 0)) {
|
||||||
|
assert(! number_is_unknown(word_ex));
|
||||||
use_word = get_number_immediate(word_ex);
|
use_word = get_number_immediate(word_ex);
|
||||||
use_word_defined = 1;
|
use_word_defined = 1;
|
||||||
word_ex = 0;
|
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. */
|
/* This is a constant bit/part select. */
|
||||||
if (number_is_immediate(bexpr, 64, 1)) {
|
if (number_is_immediate(bexpr, 64, 1)) {
|
||||||
|
assert(! number_is_unknown(bexpr));
|
||||||
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
|
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
|
||||||
ivl_expr_signal(vexpr),
|
ivl_expr_signal(vexpr),
|
||||||
get_number_immediate(bexpr),
|
get_number_immediate(bexpr),
|
||||||
|
|
@ -206,9 +209,19 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Fallback case: evaluate the expression. */
|
/* Fallback case: evaluate the expression. */
|
||||||
struct vector_info rv;
|
struct vector_info rv;
|
||||||
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
|
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>",
|
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
|
||||||
ivl_expr_signal(vexpr),
|
ivl_expr_signal(vexpr),
|
||||||
rv.base, rv.wid,
|
rv.base, rv.wid,
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,12 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
||||||
case IVL_EX_ULONG:
|
case IVL_EX_ULONG:
|
||||||
{
|
{
|
||||||
assert(number_is_immediate(expr, IMM_WID, 1));
|
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);
|
long imm = get_number_immediate(expr);
|
||||||
if (imm >= 0) {
|
if (imm >= 0) {
|
||||||
fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", ix, imm);
|
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;
|
unsigned word = 0;
|
||||||
if (ivl_signal_dimensions(sig) > 0) {
|
if (ivl_signal_dimensions(sig) > 0) {
|
||||||
ivl_expr_t ixe;
|
ivl_expr_t ixe;
|
||||||
|
char*type = ivl_expr_signed(expr) ? "/s" : "";
|
||||||
|
|
||||||
/* Detect the special case that this is a
|
/* Detect the special case that this is a
|
||||||
variable array. In this case, the ix/getv
|
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) {
|
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
||||||
struct vector_info rv;
|
struct vector_info rv;
|
||||||
rv = draw_eval_expr(expr, 0);
|
rv = draw_eval_expr(expr, 0);
|
||||||
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
fprintf(vvp_out, " %%ix/get%s %u, %u, %u;\n",
|
||||||
ix, rv.base, rv.wid);
|
type, ix, rv.base, rv.wid);
|
||||||
clr_vector(rv);
|
clr_vector(rv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ixe = ivl_expr_oper1(expr);
|
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);
|
word = get_number_immediate(ixe);
|
||||||
else {
|
} else {
|
||||||
struct vector_info rv;
|
struct vector_info rv;
|
||||||
rv = draw_eval_expr(expr, 0);
|
rv = draw_eval_expr(expr, 0);
|
||||||
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
fprintf(vvp_out, " %%ix/get%s %u, %u, %u;\n",
|
||||||
ix, rv.base, rv.wid);
|
type, ix, rv.base, rv.wid);
|
||||||
clr_vector(rv);
|
clr_vector(rv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -226,8 +234,14 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
||||||
default: {
|
default: {
|
||||||
struct vector_info rv;
|
struct vector_info rv;
|
||||||
rv = draw_eval_expr(expr, 0);
|
rv = draw_eval_expr(expr, 0);
|
||||||
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
/* Is this a signed expression? */
|
||||||
ix, rv.base, rv.wid);
|
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);
|
clr_vector(rv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -274,7 +288,10 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
|
||||||
{
|
{
|
||||||
unsigned wid;
|
unsigned wid;
|
||||||
struct vector_info lv;
|
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);
|
wid = ivl_expr_width(le);
|
||||||
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag);
|
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)
|
unsigned wid)
|
||||||
{
|
{
|
||||||
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
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);
|
unsigned long imm = get_number_immediate(re);
|
||||||
|
|
||||||
assert(lv.base >= 4);
|
assert(lv.base >= 4);
|
||||||
|
|
@ -1241,8 +1260,10 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
|
||||||
int signed_flag)
|
int signed_flag)
|
||||||
{
|
{
|
||||||
struct vector_info lv;
|
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));
|
assert(number_is_immediate(re, IMM_WID, 1));
|
||||||
|
imm = get_number_immediate(re);
|
||||||
lv.base = allocate_vector(wid);
|
lv.base = allocate_vector(wid);
|
||||||
lv.wid = wid;
|
lv.wid = wid;
|
||||||
if (lv.base == 0) {
|
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);
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||||
assert(lv.wid == wid);
|
assert(lv.wid == wid);
|
||||||
|
|
||||||
|
assert(! number_is_unknown(re));
|
||||||
|
assert(number_is_immediate(re, IMM_WID, 0));
|
||||||
imm = get_number_immediate(re);
|
imm = get_number_immediate(re);
|
||||||
|
|
||||||
/* This shouldn't generally happen, because the elaborator
|
/* This shouldn't generally happen, because the elaborator
|
||||||
|
|
@ -1308,7 +1331,7 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* Left expression is X or Z */
|
case 2: /* Left expression is 'bx or 'bz */
|
||||||
case 3:
|
case 3:
|
||||||
lv.base = 2;
|
lv.base = 2;
|
||||||
break;
|
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);
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||||
assert(lv.wid == wid);
|
assert(lv.wid == wid);
|
||||||
|
|
||||||
|
assert(! number_is_unknown(re));
|
||||||
|
assert(number_is_immediate(re, IMM_WID, 0));
|
||||||
imm = get_number_immediate(re);
|
imm = get_number_immediate(re);
|
||||||
if (imm == 0)
|
if (imm == 0)
|
||||||
return lv;
|
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);
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||||
assert(lv.wid == wid);
|
assert(lv.wid == wid);
|
||||||
|
|
||||||
|
assert(! number_is_unknown(re));
|
||||||
|
assert(number_is_immediate(re, IMM_WID, 0));
|
||||||
imm = get_number_immediate(re);
|
imm = get_number_immediate(re);
|
||||||
if (imm == 0)
|
if (imm == 0)
|
||||||
return lv;
|
return lv;
|
||||||
|
|
@ -2253,7 +2280,7 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
|
||||||
unsigned bit_width,
|
unsigned bit_width,
|
||||||
unsigned wid)
|
unsigned wid)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx, label;
|
||||||
ivl_signal_t sig = ivl_expr_signal(sube);
|
ivl_signal_t sig = ivl_expr_signal(sube);
|
||||||
/* unsigned sig_wid = ivl_expr_width(sube); */
|
/* unsigned sig_wid = ivl_expr_width(sube); */
|
||||||
ivl_expr_t ix = ivl_expr_oper1(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);
|
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
|
||||||
draw_eval_expr_into_integer(ix, 3);
|
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)
|
if (shiv.base >= 8)
|
||||||
clr_vector(shiv);
|
clr_vector(shiv);
|
||||||
|
|
||||||
|
|
@ -2294,7 +2332,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||||
|
|
||||||
/* Use this word of the signal. */
|
/* Use this word of the signal. */
|
||||||
unsigned use_word = 0;
|
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
|
/* 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
|
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
|
/* The index is constant, so we can return to direct
|
||||||
readout with the specific word selected. */
|
readout with the specific word selected. */
|
||||||
|
assert(! number_is_unknown(ix));
|
||||||
use_word = get_number_immediate(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
|
the signal (or the entire width). Just load the early bits
|
||||||
in one go. */
|
in one go. */
|
||||||
if (number_is_immediate(bit_idx, 32, 0)
|
if (number_is_immediate(bit_idx, 32, 0)
|
||||||
|
&& !number_is_unknown(bit_idx)
|
||||||
&& get_number_immediate(bit_idx) == 0
|
&& get_number_immediate(bit_idx) == 0
|
||||||
&& (ivl_expr_width(sube) >= bit_wid)) {
|
&& (ivl_expr_width(sube) >= bit_wid)) {
|
||||||
|
|
||||||
|
|
@ -2343,6 +2383,12 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||||
res.wid = wid;
|
res.wid = wid;
|
||||||
assert(res.base);
|
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;
|
use_wid = res.wid;
|
||||||
if (use_wid > bit_wid)
|
if (use_wid > bit_wid)
|
||||||
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",
|
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
||||||
res.base + use_wid, res.wid - use_wid);
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2371,6 +2422,7 @@ static void draw_select_signal_dest(ivl_expr_t sube,
|
||||||
if ((ivl_signal_dimensions(sig) == 0)
|
if ((ivl_signal_dimensions(sig) == 0)
|
||||||
&& (ivl_expr_width(sube) >= dest.wid)
|
&& (ivl_expr_width(sube) >= dest.wid)
|
||||||
&& number_is_immediate(bit_idx, 32, 0)
|
&& number_is_immediate(bit_idx, 32, 0)
|
||||||
|
&& ! number_is_unknown(bit_idx)
|
||||||
&& get_number_immediate(bit_idx) == 0) {
|
&& get_number_immediate(bit_idx) == 0) {
|
||||||
unsigned use_word = 0;
|
unsigned use_word = 0;
|
||||||
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Select %u out of %u bits\n",
|
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);
|
ivl_expr_t shift = ivl_expr_oper2(exp);
|
||||||
|
|
||||||
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1;
|
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1;
|
||||||
|
int cmp;
|
||||||
|
unsigned lab_l, lab_end;
|
||||||
|
|
||||||
res.wid = wid;
|
res.wid = wid;
|
||||||
|
|
||||||
|
|
@ -2444,7 +2498,12 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
|
||||||
return res;
|
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);
|
clr_vector(shiv);
|
||||||
|
|
||||||
/* If the subv result is a magic constant, then make a copy in
|
/* 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;
|
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, " %%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) {
|
if (subv.wid > wid) {
|
||||||
res.base = subv.base;
|
res.base = subv.base;
|
||||||
|
|
|
||||||
|
|
@ -558,6 +558,9 @@ static void draw_delay(ivl_net_logic_t lptr)
|
||||||
assert(number_is_immediate(d0, 64, 0));
|
assert(number_is_immediate(d0, 64, 0));
|
||||||
assert(number_is_immediate(d1, 64, 0));
|
assert(number_is_immediate(d1, 64, 0));
|
||||||
assert(number_is_immediate(d2, 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)
|
if (d0 == d1 && d1 == d2)
|
||||||
fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
|
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(fall_exp,64,0)
|
||||||
&& number_is_immediate(decay_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",
|
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
||||||
lptr, get_number_immediate(rise_exp),
|
lptr, get_number_immediate(rise_exp),
|
||||||
get_number_immediate(fall_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_rise, 64, 0));
|
||||||
assert(number_is_immediate(d_fall, 64, 0));
|
assert(number_is_immediate(d_fall, 64, 0));
|
||||||
assert(number_is_immediate(d_decay, 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";
|
dly = "/d";
|
||||||
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
||||||
net, get_number_immediate(d_rise),
|
net, get_number_immediate(d_rise),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue