Handle special case bit selects if unsized 0/-1.

Unsized constant 0 and -1 are pretty special, and part selects
of these values can be handled very specially.
This commit is contained in:
Stephen Williams 2010-03-05 19:36:54 -08:00
parent b48b833dab
commit 33e52c50c0
6 changed files with 107 additions and 9 deletions

View File

@ -662,6 +662,11 @@ extern ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx);
* IVL core figures all this out for you. At any rate, this method
* can be applied to any expression node.
*
* ivl_expr_sized
* This method returns false (0) if the expression node does not
* have a defined size. This is unusual, but may happen for
* constant expressions.
*
* ivl_expr_type
* Get the type of the expression node. Every expression node has a
* type, which can affect how some of the other expression methods
@ -782,6 +787,8 @@ extern ivl_scope_t ivl_expr_scope(ivl_expr_t net);
extern ivl_signal_t ivl_expr_signal(ivl_expr_t net);
/* any expression */
extern int ivl_expr_signed(ivl_expr_t net);
/* any expression */
extern int ivl_expr_sized(ivl_expr_t net);
/* IVL_EX_STRING */
extern const char* ivl_expr_string(ivl_expr_t net);
/* IVL_EX_ULONG */

View File

@ -518,6 +518,12 @@ extern "C" int ivl_expr_signed(ivl_expr_t net)
return net->signed_;
}
extern "C" int ivl_expr_sized(ivl_expr_t net)
{
assert(net);
return net->sized_;
}
extern "C" const char* ivl_expr_string(ivl_expr_t net)
{
assert(net->type_ == IVL_EX_STRING);

View File

@ -60,6 +60,7 @@ void dll_target::sub_off_from_expr_(long off)
tmpc->value_ = IVL_VT_VECTOR;
tmpc->width_ = expr_->width_;
tmpc->signed_ = expr_->signed_;
tmpc->sized_ = 1;
tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_);
for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) {
bits[idx] = (off & 1)? '1' : '0';
@ -74,6 +75,7 @@ void dll_target::sub_off_from_expr_(long off)
tmps->value_ = IVL_VT_VECTOR;
tmps->width_ = tmpc->width_;
tmps->signed_ = tmpc->signed_;
tmps->sized_ = 1;
tmps->u_.binary_.op_ = '-';
tmps->u_.binary_.lef_ = expr_;
tmps->u_.binary_.rig_ = tmpc;
@ -92,6 +94,7 @@ void dll_target::mul_expr_by_const_(long val)
tmpc->value_ = IVL_VT_VECTOR;
tmpc->width_ = expr_->width_;
tmpc->signed_ = expr_->signed_;
tmpc->sized_ = 1;
tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_);
for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) {
bits[idx] = (val & 1)? '1' : '0';
@ -106,6 +109,7 @@ void dll_target::mul_expr_by_const_(long val)
tmps->value_ = IVL_VT_VECTOR;
tmps->width_ = tmpc->width_;
tmps->signed_ = tmpc->signed_;
tmps->sized_ = 1;
tmps->u_.binary_.op_ = '*';
tmps->u_.binary_.lef_ = expr_;
tmps->u_.binary_.rig_ = tmpc;
@ -125,6 +129,7 @@ ivl_expr_t dll_target::expr_from_value_(const verinum&val)
expr->value_= IVL_VT_VECTOR;
expr->width_= val.len();
expr->signed_ = val.has_sign()? 1 : 0;
expr->sized_= 1;
expr->u_.number_.bits_ = bits = (char*)malloc(expr->width_ + 1);
for (idx = 0 ; idx < expr->width_ ; idx += 1)
switch (val.get(idx)) {
@ -160,6 +165,7 @@ void dll_target::expr_access_func(const NetEAccess*net)
expr_->lineno = net->get_lineno();
expr_->width_ = 1;
expr_->signed_= 1;
expr_->sized_ = 1;
expr_->u_.branch_.branch = net->get_branch()->target_obj();
expr_->u_.branch_.nature = net->get_nature();
@ -183,6 +189,7 @@ void dll_target::expr_binary(const NetEBinary*net)
expr_->value_= get_expr_type(net);
expr_->width_= net->expr_width();
expr_->signed_ = net->has_sign()? 1 : 0;
expr_->sized_= 1;
expr_->u_.binary_.op_ = net->op();
expr_->u_.binary_.lef_ = left;
@ -200,6 +207,7 @@ void dll_target::expr_concat(const NetEConcat*net)
cur->value_ = IVL_VT_VECTOR;
cur->width_ = net->expr_width();
cur->signed_ = net->has_sign() ? 1 : 0;
cur->sized_ = 1;
cur->u_.concat_.rept = net->repeat();
cur->u_.concat_.parms = net->nparms();
@ -236,6 +244,7 @@ void dll_target::expr_const(const NetEConst*net)
expr_->type_ = IVL_EX_NUMBER;
expr_->width_= net->expr_width();
expr_->signed_ = net->has_sign()? 1 : 0;
expr_->sized_= net->has_width()? 1 : 0;
expr_->u_.number_.bits_ = bits = (char*)malloc(expr_->width_);
for (idx = 0 ; idx < expr_->width_ ; idx += 1)
switch (val.get(idx)) {
@ -294,6 +303,7 @@ void dll_target::expr_creal(const NetECReal*net)
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
expr_->width_ = net->expr_width();
expr_->signed_ = 1;
expr_->sized_ = 1;
expr_->type_ = IVL_EX_REALNUM;
FILE_NAME(expr_, net);
expr_->value_= IVL_VT_REAL;
@ -358,6 +368,7 @@ void dll_target::expr_select(const NetESelect*net)
expr_->value_= IVL_VT_VECTOR;
expr_->width_= net->expr_width();
expr_->signed_ = net->has_sign()? 1 : 0;
expr_->sized_= 1;
expr_->u_.binary_.lef_ = left;
expr_->u_.binary_.rig_ = rght;
@ -375,6 +386,7 @@ void dll_target::expr_sfunc(const NetESFunc*net)
expr->value_= net->expr_type();
expr->width_= net->expr_width();
expr->signed_ = net->has_sign()? 1 : 0;
expr->sized_= 1;
/* system function names are lex_strings strings. */
expr->u_.sfunc_.name_ = net->name();
@ -405,6 +417,7 @@ void dll_target::expr_ternary(const NetETernary*net)
expr->value_= net->expr_type();
expr->width_ = net->expr_width();
expr->signed_ = net->has_sign()? 1 : 0;
expr->sized_ = 1;
net->cond_expr()->expr_scan(this);
assert(expr_);
@ -447,6 +460,7 @@ void dll_target::expr_signal(const NetESignal*net)
expr_->lineno= net->get_lineno();
expr_->width_= net->expr_width();
expr_->signed_ = net->has_sign()? 1 : 0;
expr_->sized_= 1;
expr_->u_.signal_.word = word_expr;
expr_->u_.signal_.sig = sig;
@ -474,6 +488,7 @@ void dll_target::expr_ufunc(const NetEUFunc*net)
expr->value_= net->expr_type();
expr->width_= net->expr_width();
expr->signed_ = net->has_sign()? 1 : 0;
expr->sized_= 1;
expr->u_.ufunc_.def = lookup_scope_(net->func());
assert(expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION);
@ -507,6 +522,7 @@ void dll_target::expr_unary(const NetEUnary*net)
expr_->value_= net->expr_type();
expr_->width_ = net->expr_width();
expr_->signed_ = net->has_sign()? 1 : 0;
expr_->sized_ = 1;
expr_->u_.unary_.op_ = net->op();
expr_->u_.unary_.sub_ = sub;
}

View File

@ -213,6 +213,7 @@ struct ivl_expr_s {
unsigned width_;
unsigned signed_ : 1;
unsigned sized_ : 1;
union {
struct {

View File

@ -257,6 +257,7 @@ void show_expression(ivl_expr_t net, unsigned ind)
ivl_parameter_t par = ivl_expr_parameter(net);
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
const char*sized = ivl_expr_sized(net)? "sized" : "unsized";
const char*vt = vt_type_string(net);
switch (code) {
@ -292,7 +293,7 @@ void show_expression(ivl_expr_t net, unsigned ind)
for (idx = width ; idx > 0 ; idx -= 1)
fprintf(out, "%c", bits[idx-1]);
fprintf(out, ", %s %s", sign, vt);
fprintf(out, ", %s %s %s", sign, sized, vt);
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));

View File

@ -2479,26 +2479,93 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
/* Evaluate the sub-expression. */
subv = draw_eval_expr(sube, 0);
/* Any bit select of a constant zero is another constant zero,
so short circuit and return the value we know. */
if (subv.base == 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;
}
/* Evaluate the bit select base expression and store the
result into index register 0. */
/* 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);
/* Detect and handle the special case that the shift is a
constant 0. Skip the shift, and return the subexpression
with the width trimmed down to the desired width. */
/* 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 && !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)) {
fprintf(vvp_out, " %%ix/get/s 0, %u, %u;\n", shiv.base,
shiv.wid);