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,
|
||||
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,
|
||||
|
|
|
|||
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,
|
||||
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)
|
||||
lsv = lsv - wid + 1;
|
||||
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_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 (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();
|
||||
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;
|
||||
|
|
|
|||
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);
|
||||
|
||||
/* 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)
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in New Issue