Pad and sign convert array index expressions as needed.
This patch mimics what was done for vectors, but is simpler since arrays don't use the endian information. It also needs to address the fact that .array/port assumes the expression is unsigned so any signed expression must be padded to make it larger than the maximum array word when it is converted to unsigned.
This commit is contained in:
parent
fabde6d1b5
commit
f522ca8a9c
|
|
@ -2839,7 +2839,8 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
|||
// expression to calculate the canonical address.
|
||||
if (long base = net->array_first()) {
|
||||
|
||||
word_index = make_add_expr(word_index, 0-base);
|
||||
word_index = normalize_variable_array_base(
|
||||
word_index, base, net->array_count());
|
||||
eval_expr(word_index);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,7 +269,8 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
|||
// expression to calculate the canonical address.
|
||||
if (long base = reg->array_first()) {
|
||||
|
||||
word = make_add_expr(word, 0-base);
|
||||
word = normalize_variable_array_base(word, base,
|
||||
reg->array_count());
|
||||
eval_expr(word);
|
||||
}
|
||||
|
||||
|
|
|
|||
99
netmisc.cc
99
netmisc.cc
|
|
@ -156,6 +156,40 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a signed constant to an existing expression. Generate a new
|
||||
* NetEBAdd node that has the input expression and an expression made
|
||||
* from the constant value.
|
||||
*/
|
||||
static NetExpr* make_add_expr(NetExpr*expr, long val)
|
||||
{
|
||||
if (val == 0)
|
||||
return expr;
|
||||
|
||||
// If the value to be added is <0, then instead generate a
|
||||
// SUBTRACT node and turn the value positive.
|
||||
char add_op = '+';
|
||||
if (val < 0) {
|
||||
add_op = '-';
|
||||
val = -val;
|
||||
}
|
||||
|
||||
verinum val_v (val);
|
||||
val_v.has_sign(true);
|
||||
|
||||
if (expr->has_width()) {
|
||||
val_v = verinum(val_v, expr->expr_width());
|
||||
}
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBAdd*res = new NetEBAdd(add_op, expr, val_c);
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract an existing expression from a signed constant.
|
||||
*/
|
||||
|
|
@ -271,37 +305,50 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
|
|||
}
|
||||
|
||||
/*
|
||||
* Add a signed constant to an existing expression. Generate a new
|
||||
* NetEBAdd node that has the input expression and an expression made
|
||||
* from the constant value.
|
||||
* This routine generates the normalization expression needed for a variable
|
||||
* array word select.
|
||||
*/
|
||||
NetExpr* make_add_expr(NetExpr*expr, long val)
|
||||
NetExpr *normalize_variable_array_base(NetExpr *base, long offset,
|
||||
unsigned count)
|
||||
{
|
||||
if (val == 0)
|
||||
return expr;
|
||||
assert(offset != 0);
|
||||
/* Calculate the space needed for the offset. */
|
||||
unsigned min_wid = num_bits(-offset);
|
||||
/* We need enough space for the larger of the offset or the base
|
||||
* expression. */
|
||||
if (min_wid < base->expr_width()) min_wid = base->expr_width();
|
||||
/* Now that we have the minimum needed width increase it by one
|
||||
* to make room for the normalization calculation. */
|
||||
min_wid += 1;
|
||||
/* Pad the base expression to the correct width. */
|
||||
base = pad_to_width(base, min_wid, *base);
|
||||
/* If the offset is greater than zero then we need to do signed
|
||||
* math to get the location value correct. */
|
||||
if (offset > 0 && ! base->has_sign()) {
|
||||
/* We need this extra select to hide the signed property
|
||||
* from the padding above. It will be removed automatically
|
||||
* during code generation. */
|
||||
NetESelect *tmp = new NetESelect(base, 0 , min_wid);
|
||||
tmp->set_line(*base);
|
||||
tmp->cast_signed(true);
|
||||
base = tmp;
|
||||
}
|
||||
/* Normalize the expression. */
|
||||
base = make_add_expr(base, -offset);
|
||||
|
||||
// If the value to be added is <0, then instead generate a
|
||||
// SUBTRACT node and turn the value positive.
|
||||
char add_op = '+';
|
||||
if (val < 0) {
|
||||
add_op = '-';
|
||||
val = -val;
|
||||
/* We should not need to do this, but .array/port does not
|
||||
* handle a small signed index correctly and it is a major
|
||||
* effort to fix it. For now we will just pad the expression
|
||||
* enough so that any negative value when converted to
|
||||
* unsigned is larger than the maximum array word. */
|
||||
if (base->has_sign()) {
|
||||
unsigned range_wid = num_bits(count-1) + 1;
|
||||
if (min_wid < range_wid) {
|
||||
base = pad_to_width(base, range_wid, *base);
|
||||
}
|
||||
}
|
||||
|
||||
verinum val_v (val);
|
||||
val_v.has_sign(true);
|
||||
|
||||
if (expr->has_width()) {
|
||||
val_v = verinum(val_v, expr->expr_width());
|
||||
}
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBAdd*res = new NetEBAdd(add_op, expr, val_c);
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
return base;
|
||||
}
|
||||
|
||||
NetEConst* make_const_x(unsigned long wid)
|
||||
|
|
|
|||
14
netmisc.h
14
netmisc.h
|
|
@ -92,11 +92,13 @@ extern NetExpr*condition_reduce(NetExpr*expr);
|
|||
extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
|
||||
|
||||
/*
|
||||
* This function generates an equation to normalize an expression using
|
||||
* the provided array/vector information.
|
||||
* These functions generate an equation to normalize an expression using
|
||||
* the provided vector/array information.
|
||||
*/
|
||||
extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
|
||||
unsigned long wid, bool is_up);
|
||||
extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
|
||||
unsigned count);
|
||||
|
||||
/*
|
||||
* This function takes as input a NetNet signal and adds a constant
|
||||
|
|
@ -106,14 +108,6 @@ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
|
|||
extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
|
||||
extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
|
||||
|
||||
/*
|
||||
* make_add_expr
|
||||
* Make a NetEBAdd expression with <expr> the first argument and
|
||||
* <val> the second. This may get turned into a subtract if <val> is
|
||||
* less than zero. If val is exactly zero, then return <expr> as is.
|
||||
*/
|
||||
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
||||
|
||||
/*
|
||||
* Make a NetEConst object that contains only X bits.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue