diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 8dee51889..cd413c889 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -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 = ""; 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, ""); - 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, ""); - 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, " "); - 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, ""); diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 0fedabd63..1ca096bec 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -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); } } } diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index c7e2e9437..dd85a47eb 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -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) { diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index b68f4a6f0..dec174faf 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -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; diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index b79690014..d533e01e8 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -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);