Fix procedural concatenation/repetition problems
This patch evaluates the whole concatenation expression and
makes the concatenation padding sign aware. This is needed
when $signed({...}) is passed as an argument.
A repetition is just N copies of the base expression not N
evaluations of the base expression. This is only a problem
when functions have side effects. It's also faster to copy.
The evaluation must also be done when the replication count
is zero (see 1364-2005).
This commit is contained in:
parent
c5ee1fdbf5
commit
e362a86b16
10
eval_tree.cc
10
eval_tree.cc
|
|
@ -1161,16 +1161,6 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
|
||||
if (local_errors > 0) return 0;
|
||||
|
||||
// Handle the special case that the repeat expression is
|
||||
// zero. In this case, just return a 0 value with the expected
|
||||
// width.
|
||||
if (repeat_val == 0) {
|
||||
verinum val (verinum::V0, expr_width());
|
||||
NetEConst*res = new NetEConst(val);
|
||||
res->set_width(val.len());
|
||||
return res;
|
||||
}
|
||||
|
||||
// At this point, the "gap" is the width of a single repeat of
|
||||
// the concatenation. The total width of the result is the gap
|
||||
// times the repeat count.
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ void dll_target::expr_concat(const NetEConcat*net)
|
|||
cur->type_ = IVL_EX_CONCAT;
|
||||
cur->value_ = IVL_VT_VECTOR;
|
||||
cur->width_ = net->expr_width();
|
||||
cur->signed_ = 0;
|
||||
cur->signed_ = net->has_sign() ? 1 : 0;
|
||||
|
||||
cur->u_.concat_.rept = net->repeat();
|
||||
cur->u_.concat_.parms = net->nparms();
|
||||
|
|
|
|||
|
|
@ -1619,82 +1619,118 @@ static struct vector_info draw_binary_expr(ivl_expr_t exp,
|
|||
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
|
||||
int stuff_ok_flag)
|
||||
{
|
||||
unsigned off, rep;
|
||||
unsigned off, rep, expr_wid, concat_wid, num_sube, idx;
|
||||
struct vector_info res;
|
||||
|
||||
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
|
||||
|
||||
/* Allocate a vector to hold the result. */
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of concatenation.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
/* Find out how wide the base concatenation expression is. */
|
||||
num_sube = ivl_expr_parms(exp);
|
||||
expr_wid = 0;
|
||||
for (idx = 0 ; idx < num_sube; idx += 1) {
|
||||
expr_wid += ivl_expr_width(ivl_expr_parm(exp, idx));
|
||||
}
|
||||
|
||||
/* Get the repeat count. This must be a constant that has been
|
||||
evaluated at compile time. The operands will be repeated to
|
||||
form the result. */
|
||||
rep = ivl_expr_repeat(exp);
|
||||
|
||||
/* Allocate a vector to hold the result. */
|
||||
if (rep == 0) {
|
||||
/* If the replication is zero we need to allocate temporary
|
||||
* space to build the concatenation. */
|
||||
res.base = allocate_vector(expr_wid);
|
||||
res.wid = expr_wid;
|
||||
} else {
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
}
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of concatenation.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp),
|
||||
rep ? wid : expr_wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
/* If the result is the right size we can just build this in place. */
|
||||
concat_wid = rep*expr_wid;
|
||||
if (concat_wid <= wid) {
|
||||
off = 0;
|
||||
|
||||
while (rep > 0) {
|
||||
|
||||
/* Each repeat, evaluate the sub-expressions, from lsb
|
||||
to msb, and copy each into the result vector. The
|
||||
expressions are arranged in the concatenation from
|
||||
MSB to LSB, to go through them backwards.
|
||||
|
||||
Abort the loop if the result vector gets filled up. */
|
||||
|
||||
unsigned idx = ivl_expr_parms(exp);
|
||||
while ((idx > 0) && (off < wid)) {
|
||||
/* Evaluate the base expression. */
|
||||
for (idx = num_sube; idx > 0; idx -= 1) {
|
||||
ivl_expr_t arg = ivl_expr_parm(exp, idx-1);
|
||||
unsigned awid = ivl_expr_width(arg);
|
||||
|
||||
unsigned trans;
|
||||
struct vector_info avec;
|
||||
|
||||
assert(awid+off <= expr_wid);
|
||||
|
||||
/* Try to locate the subexpression in the
|
||||
lookaside map. */
|
||||
* lookaside map and use it when available. */
|
||||
avec.base = allocate_vector_exp(arg, awid, alloc_exclusive);
|
||||
avec.wid = awid;
|
||||
|
||||
trans = awid;
|
||||
if ((off + awid) > wid)
|
||||
trans = wid - off;
|
||||
|
||||
if (avec.base != 0) {
|
||||
assert(awid == avec.wid);
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse calculated expression\n",
|
||||
res.base+off,
|
||||
avec.base, trans);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse "
|
||||
"calculated expression.\n",
|
||||
res.base+off, avec.base, awid);
|
||||
clr_vector(avec);
|
||||
|
||||
} else {
|
||||
struct vector_info dest;
|
||||
|
||||
dest.base = res.base+off;
|
||||
dest.wid = trans;
|
||||
dest.wid = awid;
|
||||
draw_eval_expr_dest(arg, dest, 0);
|
||||
}
|
||||
|
||||
|
||||
idx -= 1;
|
||||
off += trans;
|
||||
assert(off <= wid);
|
||||
off += awid;
|
||||
}
|
||||
|
||||
/* Now repeat the expression as needed. */
|
||||
if (rep != 0) {
|
||||
rep -= 1;
|
||||
} else {
|
||||
/* Clear the temporary space and return nothing.
|
||||
* This will be caught in draw_eval_expr_dest()
|
||||
* and dropped. */
|
||||
clr_vector(res);
|
||||
res.base = 0;
|
||||
res.wid = 0;
|
||||
}
|
||||
while (rep > 0) {
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u; Repetition %u\n",
|
||||
res.base+expr_wid*rep, res.base, expr_wid,
|
||||
rep+1);
|
||||
rep -= 1;
|
||||
}
|
||||
|
||||
/* Pad the result with 0, if necessary. */
|
||||
if (off < wid) {
|
||||
/* Pad the expression when needed. */
|
||||
if (wid > concat_wid) {
|
||||
/* We can get a signed concatenation with $signed({...}). */
|
||||
if (ivl_expr_signed(exp)) {
|
||||
unsigned base = res.base+concat_wid-1;
|
||||
for (idx = 1; idx <= wid-concat_wid; idx += 1) {
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
|
||||
base+idx, base);
|
||||
}
|
||||
} else {
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
res.base+off, wid-off);
|
||||
res.base+concat_wid, wid-concat_wid);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The concatenation is too big for the result so draw it
|
||||
* at full width and then copy the bits that are needed. */
|
||||
struct vector_info full_res;
|
||||
full_res = draw_concat_expr(exp, concat_wid, stuff_ok_flag);
|
||||
assert(full_res.base);
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
|
||||
full_res.base, wid);
|
||||
clr_vector(full_res);
|
||||
}
|
||||
|
||||
/* Save the accumulated result in the lookaside map. */
|
||||
|
|
@ -2843,7 +2879,8 @@ static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
|
|||
tmp = draw_eval_expr_wid(exp, dest.wid, stuff_ok_flag);
|
||||
assert(tmp.wid == dest.wid);
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
/* If the replication is 0 we can have a zero width, so skip it. */
|
||||
if (dest.wid) fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
dest.base, tmp.base, dest.wid);
|
||||
|
||||
if (tmp.base >= 8)
|
||||
|
|
|
|||
Loading…
Reference in New Issue