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:
parent
b48b833dab
commit
33e52c50c0
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
1
t-dll.h
1
t-dll.h
|
|
@ -213,6 +213,7 @@ struct ivl_expr_s {
|
|||
|
||||
unsigned width_;
|
||||
unsigned signed_ : 1;
|
||||
unsigned sized_ : 1;
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue