Handle selects unsized literal values accounting for bit extension.

When selecting bits from unsized literals, we do not put a limit
on the size of the literal, so there is no top above which we
stop getting literal bits.
This commit is contained in:
Stephen Williams 2010-03-06 16:21:10 -08:00
parent 72b4332b02
commit 3927917133
1 changed files with 185 additions and 73 deletions

View File

@ -2446,6 +2446,186 @@ static void draw_select_signal_dest(ivl_expr_t exp,
}
}
static struct vector_info draw_select_unsized_literal(ivl_expr_t exp,
unsigned wid,
int stuff_ok_flag)
{
struct vector_info subv, shiv, res;
ivl_expr_t sube = ivl_expr_oper1(exp);
ivl_expr_t shift = ivl_expr_oper2(exp);
assert(!ivl_expr_sized(sube));
res.wid = wid;
/* Evaluate the sub-expression. */
subv = draw_eval_expr(sube, 0);
/* Special case: Any bit/part select of an unsized constant
zero by an unsigned base is another constant zero, so short
circuit and return the value we know. */
if (subv.base == 0 && !ivl_expr_signed(shift)) {
fprintf(vvp_out, "; Part select of unsized zero with unsigned shift is zero.\n");
subv.wid = wid;
return subv;
}
/* Special case: Any bit/part select of an unsized constant -1
by an unsigned base is another constant -1, so short
circuit and return the value we know. */
if (subv.base == 1 && ivl_expr_signed(sube) && !ivl_expr_signed(shift)) {
fprintf(vvp_out, "; Part select of unsized -1 with unsigned shift is -1.\n");
subv.wid = wid;
return subv;
}
/* Evaluate the bit select base expression. */
shiv = draw_eval_expr(shift, STUFF_OK_XZ);
/* Special case: If the shift is a constant 0, skip the shift
and return the subexpression with the width trimmed down to
the part select width. */
if (shiv.base == 0) {
fprintf(vvp_out, "; Part select with shift==0 skips shift.\n");
assert(subv.wid >= wid);
res.base = subv.base;
return res;
}
/* Special case: If the expression is an unsized zero (and we
know that the shift is signed) then the expression value is
0 if the shift is >= 0, and x otherwise. The trickery in
this special case assumes the output width is 1. */
if (subv.base==0 && wid==1) {
assert(ivl_expr_signed(shift));
if (shiv.base < 4) {
assert(shiv.base != 0);
res.base = 2;
res.wid = wid;
return res;
}
/* Test if the shift is <0 by looking at the sign
bit. If the sign bit is 1, then it is negative and
the result is 1'bx. If the sign bit is 0, then the
result is 1'b0. */
clr_vector(shiv);
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%mov %u, 2, 1;\n", res.base);
fprintf(vvp_out, " %%and %u, %u, 1; x if shift<0, 0 otherwise\n",
res.base, shiv.base+shiv.wid-1);
return res;
}
/* Special case: If the expression is an unsized -1 (and we
know that the shift is signed) then the expression value is
1 if the shift is >= 0, and x otherwise. The trickery in
this special case assumes the output width is 1. */
if (subv.base==1 && ivl_expr_signed(sube) && wid==1) {
assert(ivl_expr_signed(shift));
if (shiv.base < 4) {
assert(shiv.base != 0);
res.base = 2;
res.wid = wid;
return res;
}
/* Test if the shift is <0 by looking at the sign
bit. If the sign bit is 1, then it is negative and
the result is 1'bx. If the sign bit is 0, then the
result is 1'b1. */
clr_vector(shiv);
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%mov %u, 2, 1;\n", res.base);
fprintf(vvp_out, " %%nand %u, %u, 1; x if shift<0, 1 otherwise\n",
res.base, shiv.base+shiv.wid-1);
return res;
}
/* Fall back to doing it the hard way. */
unsigned lab_end = local_count++;
unsigned lab_x = local_count++;
/* Store the bit select base into index register 0, in
preparation for doing a shift. */
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 we have an undefined index then just produce a 'bx result. */
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_x);
/* If the subv result is a magic constant, then make a copy in
writable vector space and work from there instead. */
if (subv.base < 4) {
res.base = allocate_vector(subv.wid);
res.wid = subv.wid;
assert(res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
subv.base, res.wid);
subv = res;
}
/* If the subv result is narrower then the select width, then
copy it into a wider vector. */
if (subv.wid < wid && ivl_expr_signed(sube)) {
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
fprintf(vvp_out, " %%mov %u, %u, %u; Pad sub-expression to match width\n",
res.base, subv.base, subv.wid);
if (ivl_expr_signed(sube)) {
int idx;
for (idx = subv.wid ; idx < res.wid ; idx += 1) {
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
res.base+idx, subv.base+subv.wid-1);
}
} else {
fprintf(vvp_out, " %%mov %u, 0, %u\n",
res.base+subv.wid, wid-subv.wid);
}
subv = res;
}
if (ivl_expr_signed(sube))
fprintf(vvp_out, " %%shiftr/s/i0 %u, %u; Sign-extending pad\n", subv.base, subv.wid);
else
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 ; Return 'bx value\n", thread_count, lab_x);
fprintf(vvp_out, " %%mov %u, 2, %u;\n", subv.base, wid);
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end);
/* DONE */
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end);
if (subv.wid > wid) {
res.base = subv.base;
res.wid = wid;
subv.base += wid;
subv.wid -= wid;
clr_vector(subv);
} else {
assert(subv.wid == wid);
res = subv;
}
return res;
}
static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
int stuff_ok_flag)
{
@ -2476,27 +2656,13 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
return res;
}
/* Evaluate the sub-expression. */
if (! ivl_expr_sized(sube)) {
res = draw_select_unsized_literal(exp, wid, stuff_ok_flag);
return res;
}
subv = draw_eval_expr(sube, 0);
/* Special case: Any bit/part select of an unsized constant
zero by an unsigned base is another constant zero, so short
circuit and return the value we know. */
if (subv.base == 0 && !ivl_expr_sized(sube) && !ivl_expr_signed(shift)) {
fprintf(vvp_out, "; Part select of unsized zero with unsized shift is zero.\n");
subv.wid = wid;
return subv;
}
/* Special case: Any bit/part select of an unsized constant -1
by an unsigned base is another constant -1, so short
circuit and return the value we know. */
if (subv.base == 1 && ivl_expr_signed(sube) && !ivl_expr_sized(sube) && !ivl_expr_signed(shift)) {
fprintf(vvp_out, "; Part select of unsized -1 with unsized shift is -1.\n");
subv.wid = wid;
return subv;
}
/* Evaluate the bit select base expression. */
shiv = draw_eval_expr(shift, STUFF_OK_XZ);
@ -2510,60 +2676,6 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
return res;
}
/* Special case: If the expression is an unsized zero (and we
know that the shift is signed) then the expression value is
0 if the shift is >= 0, and x otherwise. The trickery in
this special case assumes the output width is 1. */
if (subv.base==0 && !ivl_expr_sized(sube) && wid==1) {
assert(ivl_expr_signed(shift));
if (shiv.base < 4) {
assert(shiv.base != 0);
res.base = 2;
res.wid = wid;
return res;
}
/* Test if the shift is <0 by looking at the sign
bit. If the sign bit is 1, then it is negative and
the result is 1'bx. If the sign bit is 0, then the
result is 1'b0. */
clr_vector(shiv);
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%mov %u, 2, 1;\n", res.base);
fprintf(vvp_out, " %%and %u, %u, 1; x if shift<0, 0 otherwise\n",
res.base, shiv.base+shiv.wid-1);
return res;
}
/* Special case: If the expression is an unsized -1 (and we
know that the shift is signed) then the expression value is
1 if the shift is >= 0, and x otherwise. The trickery in
this special case assumes the output width is 1. */
if (subv.base==1 && ivl_expr_signed(sube) && !ivl_expr_sized(sube) && wid==1) {
assert(ivl_expr_signed(shift));
if (shiv.base < 4) {
assert(shiv.base != 0);
res.base = 2;
res.wid = wid;
return res;
}
/* Test if the shift is <0 by looking at the sign
bit. If the sign bit is 1, then it is negative and
the result is 1'bx. If the sign bit is 0, then the
result is 1'b1. */
clr_vector(shiv);
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%mov %u, 2, 1;\n", res.base);
fprintf(vvp_out, " %%nand %u, %u, 1; x if shift<0, 1 otherwise\n",
res.base, shiv.base+shiv.wid-1);
return res;
}
/* Store the bit select base into index register 0, in
preparation for doing a shift. */
if (ivl_expr_signed(shift)) {