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:
parent
72b4332b02
commit
3927917133
|
|
@ -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,
|
static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
|
||||||
int stuff_ok_flag)
|
int stuff_ok_flag)
|
||||||
{
|
{
|
||||||
|
|
@ -2476,27 +2656,13 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
|
||||||
return res;
|
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);
|
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. */
|
/* Evaluate the bit select base expression. */
|
||||||
shiv = draw_eval_expr(shift, STUFF_OK_XZ);
|
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;
|
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
|
/* Store the bit select base into index register 0, in
|
||||||
preparation for doing a shift. */
|
preparation for doing a shift. */
|
||||||
if (ivl_expr_signed(shift)) {
|
if (ivl_expr_signed(shift)) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue