vlog95: more procedural $signed()/$unsigned() support

Add support for detecting when to add a $signed() or $unsigned() to
create a self-determined context. This makes the test in the test suite
pass, but there could still be issues
This commit is contained in:
Cary R 2013-07-09 17:52:20 -07:00
parent 91ad8a72c6
commit 3e76f6d656
5 changed files with 231 additions and 118 deletions

View File

@ -34,13 +34,9 @@ typedef enum expr_sign_e {
NEED_UNSIGNED = 2
} expr_sign_t;
// HERE: Do we need to use wid in the following emit routines? We should
// probably use it to verify that the expressions have the expected
// width. For now it is not being used, but is passed.
static expr_sign_t get_binary_sign_type(ivl_expr_t expr)
{
ivl_expr_t expr1, expr2;
ivl_expr_t oper1, oper2;
int opr_sign = 0;
int expr_sign = ivl_expr_signed(expr);
expr_sign_t rtn = NO_SIGN;
@ -68,12 +64,12 @@ static expr_sign_t get_binary_sign_type(ivl_expr_t expr)
/* For the rest of the opcodes the operator is considered to
* be signed if either argument is real or if both arguments
* are signed. */
expr1 = ivl_expr_oper1(expr);
expr2 = ivl_expr_oper2(expr);
if ((ivl_expr_value(expr1) == IVL_VT_REAL) ||
(ivl_expr_value(expr2) == IVL_VT_REAL)) {
oper1 = ivl_expr_oper1(expr);
oper2 = ivl_expr_oper2(expr);
if ((ivl_expr_value(oper1) == IVL_VT_REAL) ||
(ivl_expr_value(oper2) == IVL_VT_REAL)) {
opr_sign = 1;
} else if (ivl_expr_signed(expr1) && ivl_expr_signed(expr2)) {
} else if (ivl_expr_signed(oper1) && ivl_expr_signed(oper2)) {
opr_sign = 1;
}
break;
@ -96,7 +92,11 @@ static expr_sign_t get_select_sign_type(ivl_expr_t expr,
/* If there is no select expression then the sign is determined by
* the expression that is being selected (padded). */
if (! ivl_expr_oper2(expr)) {
opr_sign = ivl_expr_signed(ivl_expr_oper1(expr));
ivl_expr_t oper1 = ivl_expr_oper1(expr);
opr_sign = ivl_expr_signed(oper1);
/* If the expression being padded is not a signal then don't
* skip a soft $unsigned() (from the binary operator). */
if (ivl_expr_type(oper1) != IVL_EX_SIGNAL) can_skip_unsigned -= 1;
}
/* Check to see if a $signed() or $unsigned() are needed. */
@ -173,17 +173,53 @@ static expr_sign_t get_unary_sign_type(ivl_expr_t expr)
return rtn;
}
/*
* This routine is used to determine if the expression is a binary operator
* where the width could be different to create a self-determined context.
*/
static unsigned is_binary_self_det(ivl_expr_t expr)
{
unsigned rtn = 0;
if (ivl_expr_type(expr) == IVL_EX_BINARY) {
switch (ivl_expr_opcode(expr)) {
case '+':
case '-':
case '*':
case '/':
case '%':
case '&':
case '|':
case '^':
case 'X':
case 'A':
case 'O':
case 'R':
case 'l':
case 'r':
rtn = 1;
break;
default:
break;
}
}
return rtn;
}
/*
* Determine if a $signed() or $unsigned() system function is needed to get
* the expression sign information correct. can_skip_unsigned may be set for
* the binary/ternary operators if one of the operands will implicitly cast
* the expression to unsigned. See calc_can_skip_unsigned() for the details.
*/
static expr_sign_t get_sign_type(ivl_expr_t expr, unsigned can_skip_unsigned)
static expr_sign_t get_sign_type(ivl_expr_t expr, unsigned wid,
unsigned can_skip_unsigned,
unsigned is_full_prec)
{
unsigned expr_wid = ivl_expr_width(expr);
expr_sign_t rtn = NO_SIGN;
ivl_expr_type_t type = ivl_expr_type(expr);
switch (ivl_expr_type(expr)) {
switch (type) {
case IVL_EX_BINARY:
rtn = get_binary_sign_type(expr);
break;
@ -194,6 +230,15 @@ static expr_sign_t get_sign_type(ivl_expr_t expr, unsigned can_skip_unsigned)
break;
case IVL_EX_SELECT:
rtn = get_select_sign_type(expr, can_skip_unsigned);
/* If there is no select expression then this is padding so use
* the actual expressions width if it is a binary operator that
* could create a self-determined context. */
if (! ivl_expr_oper2(expr)) {
ivl_expr_t oper1 = ivl_expr_oper1(expr);
if (is_binary_self_det(oper1)) {
expr_wid = ivl_expr_width(oper1);
}
}
break;
case IVL_EX_SIGNAL:
rtn = get_signal_sign_type(expr, can_skip_unsigned);
@ -221,6 +266,14 @@ static expr_sign_t get_sign_type(ivl_expr_t expr, unsigned can_skip_unsigned)
default:
break;
}
/* Check for a self-determined context. */
if ((rtn == NO_SIGN) && (wid != expr_wid) &&
! (is_full_prec && ((expr_wid < wid) || (type = IVL_EX_SIGNAL)))) {
if (ivl_expr_signed(expr)) rtn = NEED_SIGNED;
else rtn = NEED_UNSIGNED;
}
return rtn;
}
@ -249,7 +302,7 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
if (value % 2) return 0;
/* Generate the appropriate conversion. */
if (ivl_expr_signed(rval)) {
emit_expr(scope, rval, 0, 0);
emit_expr(scope, rval, 0, 0, 0, 0);
fprintf(vlog_out, " < 0 ? ");
if (is_signed_expr) {
if (expr_wid == 32) {
@ -294,7 +347,7 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
}
fprintf(vlog_out, " * ");
}
emit_expr(scope, rval, 0, 0);
emit_expr(scope, rval, 0, 0, 0, 0);
if (scale != 1) fprintf(vlog_out, ")");
if (is_signed_rval) fprintf(vlog_out, ")");
return 1;
@ -307,6 +360,19 @@ static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
emit_id(ivl_signal_basename(sig));
}
/*
* Some of the operators can do an implicit cast to real so for them emit
* the non-real argument in a self-determined context.
*/
static unsigned get_cast_width(ivl_expr_t expr, ivl_expr_t oper, unsigned wid)
{
ivl_variable_type_t expr_type = ivl_expr_value(expr);
if ((expr_type == IVL_VT_REAL) && (expr_type != ivl_expr_value(oper))) {
wid = 0;
}
return wid;
}
static unsigned calc_can_skip_unsigned(ivl_expr_t oper1, ivl_expr_t oper2)
{
unsigned oper1_signed, oper2_signed;
@ -331,7 +397,8 @@ static unsigned calc_can_skip_unsigned(ivl_expr_t oper1, ivl_expr_t oper2)
return ! oper1_signed || ! oper2_signed;
}
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
unsigned is_full_prec)
{
char *oper = "<invalid>";
ivl_expr_t oper1 = ivl_expr_oper1(expr);
@ -364,8 +431,8 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
case 'l': oper = "<<"; break;
case 'r': oper = ">>"; break;
case 'R': oper = ">>>"; break;
case 'm': oper = "<"; break;
case 'M': oper = ">"; break;
case 'm': oper = "min"; break;
case 'M': oper = "max"; break;
}
fprintf(vlog_out, "(");
@ -381,6 +448,20 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
case '-':
case '*':
case '/':
emit_expr(scope, oper1, get_cast_width(expr, oper1, wid), 0,
can_skip_unsigned, is_full_prec);
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, get_cast_width(expr, oper2, wid), 0,
can_skip_unsigned, is_full_prec);
break;
case '&':
case '|':
case '^':
case 'X':
emit_expr(scope, oper1, wid, 0, can_skip_unsigned, is_full_prec);
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, wid, 0, can_skip_unsigned, is_full_prec);
break;
case 'E':
case 'e':
case 'N':
@ -389,19 +470,17 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
case 'L':
case '>':
case 'G':
case '&':
case '|':
case '^':
case 'X':
emit_expr(scope, oper1, wid, can_skip_unsigned);
emit_expr(scope, oper1, ivl_expr_width(oper1), 0,
can_skip_unsigned, 0);
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, wid, can_skip_unsigned);
emit_expr(scope, oper2, ivl_expr_width(oper2), 0,
can_skip_unsigned, 0);
break;
case 'a':
case 'o':
emit_expr(scope, oper1, 0, can_skip_unsigned);
emit_expr(scope, oper1, ivl_expr_width(oper1), 0, 1, 0);
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, 0, can_skip_unsigned);
emit_expr(scope, oper2, ivl_expr_width(oper2), 0, 1, 0);
break;
case 'R':
if (! allow_signed) {
@ -412,23 +491,23 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
case 'l':
case 'r':
emit_expr(scope, oper1, wid, 0);
emit_expr(scope, oper1, wid, 0, 0, 0);
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, 0, 1);
emit_expr(scope, oper2, ivl_expr_width(oper2), 0, 2, 0);
break;
case 'A':
case 'O':
fprintf(vlog_out, "~(");
emit_expr(scope, oper1, wid, can_skip_unsigned);
emit_expr(scope, oper1, wid, 0, can_skip_unsigned, is_full_prec);
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, wid, can_skip_unsigned);
emit_expr(scope, oper2, wid, 0, can_skip_unsigned, is_full_prec);
fprintf(vlog_out, ")");
break;
case 'p':
if (! emit_power_as_shift(scope, expr, wid)) {
emit_expr(scope, oper1, wid, can_skip_unsigned);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, " ** ");
emit_expr(scope, oper2, 0, can_skip_unsigned);
emit_expr(scope, oper2, ivl_expr_width(oper2), 0, 0, 0);
fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
"supported.\n",
ivl_expr_file(expr), ivl_expr_lineno(expr));
@ -442,27 +521,27 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
/* For a real expression use the $min()/$max() function. */
if (ivl_expr_opcode(expr) == 'm') fprintf(vlog_out, "$min(");
else fprintf(vlog_out, "$max(");
emit_expr(scope, oper1, wid, 0);
emit_expr(scope, oper1, wid, 0, 0, 0);
fprintf(vlog_out, ",");
emit_expr(scope, oper2, wid, 0);
emit_expr(scope, oper2, wid, 0, 0, 0);
fprintf(vlog_out, ")");
} else {
/* This only works when the argument has no side effect. */
fprintf(vlog_out, "((");
emit_expr(scope, oper1, wid, 0);
emit_expr(scope, oper1, wid, 0, 0, 0);
fprintf(vlog_out, ") %s (", oper);
emit_expr(scope, oper2, wid, 0);
emit_expr(scope, oper2, wid, 0, 0, 0);
fprintf(vlog_out, ") ? (");
emit_expr(scope, oper1, wid, 0);
emit_expr(scope, oper1, wid, 0, 0, 0);
fprintf(vlog_out, ") : (");
emit_expr(scope, oper2, wid, 0);
emit_expr(scope, oper2, wid, 0, 0, 0);
fprintf(vlog_out, "))");
}
break;
default:
emit_expr(scope, oper1, wid, 0);
emit_expr(scope, oper1, wid, 0, can_skip_unsigned, 0);
fprintf(vlog_out, "<unknown>");
emit_expr(scope, oper2, wid, 0);
emit_expr(scope, oper2, wid, 0, can_skip_unsigned, 0);
fprintf(stderr, "%s:%u: vlog95 error: Unknown expression "
"operator (%c).\n",
ivl_expr_file(expr),
@ -483,10 +562,10 @@ static void emit_expr_concat(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
fprintf(vlog_out, "{");
count -= 1;
for (idx = 0; idx < count; idx += 1) {
emit_expr(scope, ivl_expr_parm(expr, idx), 0, 0);
emit_expr(scope, ivl_expr_parm(expr, idx), 0, 0, 0, 0);
fprintf(vlog_out, ", ");
}
emit_expr(scope, ivl_expr_parm(expr, count), 0, 0);
emit_expr(scope, ivl_expr_parm(expr, count), 0, 0, 0, 0);
fprintf(vlog_out, "}");
if (repeat != 1) fprintf(vlog_out, "}");
}
@ -567,7 +646,7 @@ static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
emit_expr_scope_piece(ivl_expr_scope(expr));
}
static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr)
{
/* A select of a number is really a parameter select. */
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
@ -583,7 +662,7 @@ static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
vlog_errors += 1;
}
} else {
emit_expr(scope, expr, wid, 0);
emit_expr(scope, expr, 0, 0, 0, 0);
}
}
@ -597,14 +676,14 @@ static void emit_expr_packed(ivl_scope_t scope, ivl_expr_t sig_expr,
assert(wid > 0);
fprintf(vlog_out, "{");
for (idx = wid - 1; idx > 0; idx -= 1) {
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0, 0);
emit_expr(scope, sel_expr, 0, 0, 0, 1);
fprintf(vlog_out, " + %u], ", idx);
}
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0, 0);
emit_expr(scope, sel_expr, 0, 0, 0, 1);
fprintf(vlog_out, "]}");
}
@ -633,13 +712,13 @@ static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr,
if ((sel_type == IVL_SEL_IDX_DOWN) && ! is_param) {
lsb += wid - 1;
msb += wid - 1;
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]");
for (idx = 1; idx < wid; idx += 1) {
fprintf(vlog_out, ", ");
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, " - %u]", idx);
@ -649,12 +728,12 @@ static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr,
assert((sel_type == IVL_SEL_IDX_UP) ||
(is_param && (sel_type == IVL_SEL_IDX_DOWN)));
for (idx = wid - 1; idx > 0; idx -= 1) {
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, " + %u], ", idx);
}
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]}");
@ -663,13 +742,13 @@ static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr,
if ((sel_type == IVL_SEL_IDX_UP) && ! is_param) {
lsb -= wid - 1;
msb -= wid - 1;
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]");
for (idx = 1; idx < wid; idx += 1) {
fprintf(vlog_out, ", ");
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, " + %u]", idx);
@ -679,12 +758,12 @@ static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr,
assert((sel_type == IVL_SEL_IDX_DOWN) ||
(is_param && (sel_type == IVL_SEL_IDX_UP)));
for (idx = wid - 1; idx > 0; idx -= 1) {
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, " - %u], ", idx);
}
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]}");
@ -695,7 +774,8 @@ static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr,
static void check_select_signed(ivl_expr_t sig_expr, ivl_expr_t sel_expr,
int msb, int lsb)
{
expr_sign_t sign_type = get_sign_type(sel_expr, 0);
expr_sign_t sign_type = get_sign_type(sel_expr,
ivl_expr_width(sel_expr), 0, 1);
char msg[64];
snprintf(msg, sizeof(msg), "%s:%u",
ivl_expr_file(sel_expr),
@ -762,9 +842,9 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) &&
(ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_DARRAY)) {
assert(sel_expr);
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0, 0);
emit_expr(scope, sel_expr, 0, 0, 0, 1);
fprintf(vlog_out, "]");
return;
}
@ -775,7 +855,7 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
/* The compiler uses selects for some shifts. */
if (type != IVL_EX_NUMBER && type != IVL_EX_SIGNAL) {
fprintf(vlog_out, "(" );
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, " >> " );
emit_scaled_expr(scope, sel_expr, 1, 0);
fprintf(vlog_out, ")" );
@ -791,14 +871,14 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
/* A bit select. */
if (width == 1) {
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
fprintf(vlog_out, "[");
check_select_signed(sig_expr, sel_expr, msb, lsb);
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]");
} else if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
/* A constant part select. */
emit_select_name(scope, sig_expr, wid);
emit_select_name(scope, sig_expr);
emit_scaled_range(scope, sel_expr, width, msb, lsb);
} else if (sel_type == IVL_SEL_OTHER) {
/* A packed array access. */
@ -813,17 +893,18 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
} else {
// HERE: Should this sign extend if the expression is signed?
emit_expr(scope, sig_expr, wid, 0);
unsigned width = ivl_expr_width(expr);
unsigned sig_wid = ivl_expr_width(sig_expr);
emit_expr(scope, sig_expr, sig_wid, 0, 0, 0);
/* Select part of a signal when needed. */
if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) &&
(ivl_expr_width(expr) < ivl_expr_width(sig_expr))) {
(width < sig_wid)) {
int msb, lsb;
int64_t value;
unsigned e_wid = ivl_expr_width(expr) - 1;
get_sig_msb_lsb(ivl_expr_signal(sig_expr), &msb, &lsb);
value = lsb;
if (msb >= lsb) value += e_wid;
else value -= e_wid;
if (msb >= lsb) value += width - 1;
else value -= width - 1;
fprintf(vlog_out, "[%"PRId64":%u]", value, lsb);
}
}
@ -840,10 +921,12 @@ static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
fprintf(vlog_out, "(");
count -= 1;
for (idx = 0; idx < count; idx += 1) {
emit_expr(scope, ivl_expr_parm(expr, idx), 0, 0);
// HERE: For a user function should the argument width be used here.
emit_expr(scope, ivl_expr_parm(expr, idx), 0, 1, 0, 0);
fprintf(vlog_out, ", ");
}
emit_expr(scope, ivl_expr_parm(expr, count), 0, 0);
// HERE: For a user function should the argument width be used here.
emit_expr(scope, ivl_expr_parm(expr, count), 0, 1, 0, 0);
fprintf(vlog_out, ")");
/* User functions without arguments are not supported. */
} else if (ivl_expr_type(expr) == IVL_EX_UFUNC) {
@ -865,23 +948,28 @@ static void emit_expr_signal(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
}
static void emit_expr_ternary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
static void emit_expr_ternary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
unsigned is_full_prec)
{
ivl_expr_t oper2 = ivl_expr_oper2(expr);
ivl_expr_t oper3 = ivl_expr_oper3(expr);
unsigned can_skip_unsigned = calc_can_skip_unsigned(oper2, oper3);
fprintf(vlog_out, "(");
emit_expr(scope, ivl_expr_oper1(expr), 0, 1);
emit_expr(scope, ivl_expr_oper1(expr), 0, 0, 0, 0);
fprintf(vlog_out, " ? ");
emit_expr(scope, oper2, wid, can_skip_unsigned);
// HERE: Do these two emits need to use get_cast_width() like the binary
// arithmetic operators?
emit_expr(scope, oper2, wid, 0, can_skip_unsigned, is_full_prec);
fprintf(vlog_out, " : ");
emit_expr(scope, oper3, wid, can_skip_unsigned);
emit_expr(scope, oper3, wid, 0, can_skip_unsigned, is_full_prec);
fprintf(vlog_out, ")");
}
static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
unsigned is_full_prec)
{
char *oper = "invalid";
ivl_expr_t oper1 = ivl_expr_oper1(expr);
switch (ivl_expr_opcode(expr)) {
case '-': oper = "-"; break;
case '~': oper = "~"; break;
@ -896,6 +984,10 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
switch (ivl_expr_opcode(expr)) {
case '-':
case '~':
fprintf(vlog_out, "(%s", oper);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, ")");
break;
case '&':
case '|':
case '^':
@ -904,18 +996,18 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
case 'X':
case '!':
fprintf(vlog_out, "(%s", oper);
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, 0, 0, 0, 0);
fprintf(vlog_out, ")");
break;
case '2':
case 'v':
case 'r':
/* A cast is a noop. */
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, 0, 0, 0, 0);
break;
case 'I':
fprintf(vlog_out, "(++");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment "
"operator is not currently translated.\n",
@ -925,7 +1017,7 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
break;
case 'i':
fprintf(vlog_out, "(");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, "++)");
fprintf(stderr, "%s:%u: vlog95 sorry: Post-increment "
"operator is not currently translated.\n",
@ -935,7 +1027,7 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
break;
case 'D':
fprintf(vlog_out, "(--");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement "
"operator is not currently translated.\n",
@ -945,7 +1037,7 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
break;
case 'd':
fprintf(vlog_out, "(");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, "--)");
fprintf(stderr, "%s:%u: vlog95 sorry: Post-decrement "
"operator is not currently translated.\n",
@ -958,22 +1050,22 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
if (ivl_expr_value(expr) == IVL_VT_REAL) {
/* For a real expression use the $abs() function. */
fprintf(vlog_out, "$abs(");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, ")");
} else {
/* This only works when the argument has no side effect. */
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, ") > 0 ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, ") : -(");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, is_full_prec);
fprintf(vlog_out, "))");
}
break;
default:
fprintf(vlog_out, "<unknown>");
emit_expr(scope, ivl_expr_oper1(expr), wid, 0);
emit_expr(scope, oper1, wid, 0, 0, 0);
fprintf(stderr, "%s:%u: vlog95 error: Unknown unary "
"operator (%c).\n",
ivl_expr_file(expr),
@ -985,9 +1077,20 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
unsigned can_skip_unsigned)
unsigned is_lval_width, unsigned can_skip_unsigned,
unsigned is_full_prec)
{
expr_sign_t sign_type = get_sign_type(expr, can_skip_unsigned);
expr_sign_t sign_type;
/* If the width is from an L-value (assignment) then the actual
* expression width can be larger. */
if (is_lval_width) {
unsigned expr_wid = ivl_expr_width(expr);
if (wid < expr_wid) wid = expr_wid;
}
/* In a self-determined context the expression set the width. */
if (! wid) wid = ivl_expr_width(expr);
sign_type = get_sign_type(expr, wid, can_skip_unsigned,
is_full_prec);
/* Check to see if a $signed() or $unsigned() needs to be emitted
* before the expression. */
@ -999,6 +1102,10 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
ivl_expr_file(expr), ivl_expr_lineno(expr));
vlog_errors += 1;
}
/* A $signed() creates a self-determined context. */
wid = 0;
/* It also clears the full precision flag. */
is_full_prec = 0;
}
if (sign_type == NEED_UNSIGNED) {
fprintf(vlog_out, "$unsigned(");
@ -1008,6 +1115,10 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
ivl_expr_file(expr), ivl_expr_lineno(expr));
vlog_errors += 1;
}
/* A $unsigned() creates a self-determined context. */
wid = 0;
/* It also clears the full precision flag. */
is_full_prec = 0;
}
/* Emit the expression. */
switch (ivl_expr_type(expr)) {
@ -1015,7 +1126,7 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
emit_expr_array(scope, expr, wid);
break;
case IVL_EX_BINARY:
emit_expr_binary(scope, expr, wid);
emit_expr_binary(scope, expr, wid, is_full_prec);
break;
case IVL_EX_CONCAT:
emit_expr_concat(scope, expr, wid);
@ -1071,7 +1182,7 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
break;
case IVL_EX_SHALLOWCOPY:
fprintf(vlog_out, "<new> ");
emit_expr(scope, ivl_expr_oper2(expr), wid, 0);
emit_expr(scope, ivl_expr_oper2(expr), wid, 0, 0, 0);
fprintf(stderr, "%s:%u: vlog95 error: New operator "
"is not supported.\n",
ivl_expr_file(expr),
@ -1085,14 +1196,14 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
emit_string(ivl_expr_string(expr));
break;
case IVL_EX_TERNARY:
emit_expr_ternary(scope, expr, wid);
emit_expr_ternary(scope, expr, wid, is_full_prec);
break;
case IVL_EX_UFUNC:
emit_scope_path(scope, ivl_expr_def(expr));
emit_expr_func(scope, expr, wid);
break;
case IVL_EX_UNARY:
emit_expr_unary(scope, expr, wid);
emit_expr_unary(scope, expr, wid, is_full_prec);
break;
default:
fprintf(vlog_out, "<unknown>");

View File

@ -74,7 +74,7 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt)
return;
}
}
emit_expr(scope, expr, 0, 0);
emit_expr(scope, expr, 0, 0, 0, 1);
}
/*
@ -396,10 +396,10 @@ void emit_scaled_expr(ivl_scope_t scope, ivl_expr_t expr, int msb, int lsb)
fprintf(vlog_out, "%"PRId64, value);
} else if (lsb == 0) {
/* If the LSB is zero then there is no scale. */
emit_expr(scope, expr, 0, 0);
emit_expr(scope, expr, 0, 0, 0, 1);
} else {
if (is_scaled_expr(expr, msb, lsb)) {
emit_expr(scope, ivl_expr_oper1(expr), 0, 0);
emit_expr(scope, ivl_expr_oper1(expr), 0, 0, 0, 1);
}
}
} else {
@ -413,7 +413,7 @@ void emit_scaled_expr(ivl_scope_t scope, ivl_expr_t expr, int msb, int lsb)
fprintf(vlog_out, "%"PRId64, value);
} else {
if (is_scaled_expr(expr, msb, lsb)) {
emit_expr(scope, ivl_expr_oper2(expr), 0, 0);
emit_expr(scope, ivl_expr_oper2(expr), 0, 0, 0, 1);
}
}
}

View File

@ -314,7 +314,7 @@ void emit_scope_variables(ivl_scope_t scope)
fprintf(vlog_out, " = ");
/* Need to emit the parameters value not its name. */
emitting_param = par;
emit_expr(scope, pex, 0, 0);
emit_expr(scope, pex, ivl_expr_width(pex), 1, 0, 0);
emitting_param = 0;
fprintf(vlog_out, ";");
if (emit_file_line) {

View File

@ -69,7 +69,7 @@ static void emit_stmt_inter_delay(ivl_scope_t scope, ivl_statement_t stmt)
}
} else {
fprintf(vlog_out, "repeat(");
emit_expr(scope, count, 0, 0);
emit_expr(scope, count, 0, 0, 0, 0);
fprintf(vlog_out, ") ");
}
}
@ -115,12 +115,12 @@ static void emit_stmt_lval_packed(ivl_scope_t scope, ivl_lval_t lval,
for (idx = wid - 1; idx > 0; idx -= 1) {
emit_stmt_lval_name(scope, lval, sig);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0, 0);
emit_expr(scope, sel_expr, 0, 0, 0, 1);
fprintf(vlog_out, " + %u], ", idx);
}
emit_stmt_lval_name(scope, lval, sig);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0, 0);
emit_expr(scope, sel_expr, 0, 0, 0, 1);
fprintf(vlog_out, "]}");
}
@ -205,7 +205,7 @@ static void emit_stmt_lval_darray(ivl_scope_t scope, ivl_lval_t lval,
emit_id(ivl_signal_basename(sig));
if (idx) {
fprintf(vlog_out, "[");
emit_expr(scope, idx, 0, 0);
emit_expr(scope, idx, 0, 0, 0, 1);
fprintf(vlog_out, "]");
}
}
@ -375,7 +375,7 @@ static unsigned is_delayed_or_event_assign(ivl_scope_t scope,
emit_event(scope, delay);
}
fprintf(vlog_out, ") ");
emit_expr(scope, ivl_stmt_rval(assign), wid, 0);
emit_expr(scope, ivl_stmt_rval(assign), wid, 1, 0, 0);
fprintf(vlog_out, ";");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -442,7 +442,7 @@ static void emit_assign_and_opt_opcode(ivl_scope_t scope, ivl_statement_t stmt,
vlog_errors += 1;
}
}
emit_expr(scope, ivl_stmt_rval(stmt), wid, 0);
emit_expr(scope, ivl_stmt_rval(stmt), wid, 1, 0, 0);
}
/*
@ -497,7 +497,7 @@ static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt)
emit_assign_and_opt_opcode(scope, assign, 0);
fprintf(vlog_out, "; ");
/* Emit the condition. */
emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0, 0);
emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0, 0, 0, 0);
fprintf(vlog_out, "; ");
/* Emit the increment statement (an opcode is allowed). */
emit_assign_and_opt_opcode(scope, incr_assign, 1);
@ -575,13 +575,13 @@ static unsigned is_repeat_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
fprintf(vlog_out, " =");
if (repeat) {
fprintf(vlog_out, " repeat (");
emit_expr(scope, ivl_stmt_cond_expr(repeat), 0, 0);
emit_expr(scope, ivl_stmt_cond_expr(repeat), 0, 0, 0, 0);
fprintf(vlog_out, ")");
}
fprintf(vlog_out, " @(");
emit_event(scope, event);
fprintf(vlog_out, ") ");
emit_expr(scope, ivl_stmt_rval(assign), wid, 0);
emit_expr(scope, ivl_stmt_rval(assign), wid, 1, 0, 0);
fprintf(vlog_out, ";");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -634,7 +634,7 @@ static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
/* The pattern matched so generate the appropriate code. */
fprintf(vlog_out, "%*cwait(", get_indent(), ' ');
emit_expr(scope, ivl_expr_oper1(while_expr), 0, 0);
emit_expr(scope, ivl_expr_oper1(while_expr), 0, 0, 0, 0);
fprintf(vlog_out, ")");
emit_stmt_file_line(stmt);
single_indent = 1;
@ -740,7 +740,8 @@ typedef struct port_expr_s {
static void emit_port(ivl_scope_t scope, struct port_expr_s port_expr)
{
if (port_expr.type == IVL_SIP_INPUT) {
emit_expr(scope, port_expr.expr.rval, 0, 0);
// HERE: For a user should the argument width be used here.
emit_expr(scope, port_expr.expr.rval, 0, 1, 0, 0);
} else {
/* This is a self-determined context so we don't care about
* the width of the L-value. */
@ -894,7 +895,7 @@ static void emit_stmt_assign_nb(ivl_scope_t scope, ivl_statement_t stmt)
wid = emit_stmt_lval(scope, stmt);
fprintf(vlog_out, " <= ");
emit_stmt_inter_delay(scope, stmt);
emit_expr(scope, ivl_stmt_rval(stmt), wid, 0);
emit_expr(scope, ivl_stmt_rval(stmt), wid, 1, 0, 0);
fprintf(vlog_out, ";");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -940,7 +941,7 @@ static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt)
assert(0);
}
fprintf(vlog_out, "%*c%s (", get_indent(), ' ', case_type);
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0);
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0, 0, 0);
fprintf(vlog_out, ")");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -955,7 +956,7 @@ static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt)
continue;
}
fprintf(vlog_out, "%*c", get_indent(), ' ');
emit_expr(scope, expr, 0, 0);
emit_expr(scope, expr, 0, 0, 0, 0);
fprintf(vlog_out, ":");
single_indent = 1;
emit_stmt(scope, ivl_stmt_case_stmt(stmt, idx));
@ -978,7 +979,7 @@ static void emit_stmt_cassign(ivl_scope_t scope, ivl_statement_t stmt)
// done this for us.
wid = emit_stmt_lval(scope, stmt);
fprintf(vlog_out, " = ");
emit_expr(scope, ivl_stmt_rval(stmt), wid, 0);
emit_expr(scope, ivl_stmt_rval(stmt), wid, 1, 0, 0);
fprintf(vlog_out, ";");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -990,7 +991,7 @@ static void emit_stmt_condit(ivl_scope_t scope, ivl_statement_t stmt)
ivl_statement_t false_stmt = ivl_stmt_cond_false(stmt);
unsigned nest = 0;
fprintf(vlog_out, "%*cif (", get_indent(), ' ');
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0);
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0, 0, 0);
fprintf(vlog_out, ")");
emit_stmt_file_line(stmt);
if (true_stmt) {
@ -1068,7 +1069,7 @@ static void emit_stmt_force(ivl_scope_t scope, ivl_statement_t stmt)
// done this for us.
wid = emit_stmt_lval(scope, stmt);
fprintf(vlog_out, " = ");
emit_expr(scope, ivl_stmt_rval(stmt), wid, 0);
emit_expr(scope, ivl_stmt_rval(stmt), wid, 1, 0, 0);
fprintf(vlog_out, ";");
emit_stmt_file_line(stmt);
fprintf(vlog_out, "\n");
@ -1115,7 +1116,7 @@ static void emit_stmt_release(ivl_scope_t scope, ivl_statement_t stmt)
static void emit_stmt_repeat(ivl_scope_t scope, ivl_statement_t stmt)
{
fprintf(vlog_out, "%*crepeat (", get_indent(), ' ');
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0);
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0, 0, 0);
fprintf(vlog_out, ")");
emit_stmt_file_line(stmt);
single_indent = 1;
@ -1132,10 +1133,10 @@ static void emit_stmt_stask(ivl_scope_t scope, ivl_statement_t stmt)
count -= 1;
for (idx = 0; idx < count; idx += 1) {
ivl_expr_t expr = ivl_stmt_parm(stmt, idx);
if (expr) emit_expr(scope, expr, 0, 0);
if (expr) emit_expr(scope, expr, 0, 0, 0, 0);
fprintf(vlog_out, ", ");
}
emit_expr(scope, ivl_stmt_parm(stmt, count), 0, 0);
emit_expr(scope, ivl_stmt_parm(stmt, count), 0, 0, 0, 0);
fprintf(vlog_out, ")");
}
fprintf(vlog_out, ";");
@ -1183,7 +1184,7 @@ static void emit_stmt_wait(ivl_scope_t scope, ivl_statement_t stmt)
static void emit_stmt_while(ivl_scope_t scope, ivl_statement_t stmt)
{
fprintf(vlog_out, "%*cwhile (", get_indent(), ' ');
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0);
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0, 0, 0);
fprintf(vlog_out, ")");
emit_stmt_file_line(stmt);
single_indent = 1;

View File

@ -73,7 +73,8 @@ extern unsigned allow_signed;
*/
extern void emit_event(ivl_scope_t scope, ivl_statement_t stmt);
extern void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned width,
unsigned can_skip_unsigned);
unsigned is_lval_width, unsigned can_skip_unsigned,
unsigned is_full_prec);
extern void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic);
extern void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm);
extern void emit_process(ivl_scope_t scope, ivl_process_t proc);