vlog95: convert real Verilog-A abs/min/max to $abs/$min/$max

Converting these Verilog-A functions to use the $ version allows nan
to be handled correct. This still needs to be done for the LPM code.
This commit is contained in:
Cary R 2013-02-19 20:02:05 -08:00
parent c4386da666
commit 27b8738d06
2 changed files with 40 additions and 25 deletions

View File

@ -176,19 +176,29 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
vlog_errors += 1;
}
break;
/* Convert Verilog-A min() or max() functions. This only works
* when the arguments have no side effect. */
/* Convert the Verilog-A min() or max() functions. */
case 'm':
case 'M':
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") %s (", oper);
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, ") ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : (");
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, "))");
if (ivl_expr_value(expr) == IVL_VT_REAL) {
/* 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, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ",");
emit_expr(scope, ivl_expr_oper2(expr), wid);
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);
fprintf(vlog_out, ") %s (", oper);
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, ") ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : (");
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, "))");
}
break;
default:
emit_expr(scope, ivl_expr_oper1(expr), wid);
@ -587,19 +597,23 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
/* Convert Verilog-A abs() function. This only works when the
* argument has no side effect. */
/* Convert the Verilog-A abs() function. */
case 'm':
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") > ");
if (ivl_expr_value(expr) == IVL_VT_REAL) fprintf(vlog_out, "0.0");
else fprintf(vlog_out, "0");
fprintf(vlog_out, " ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : -(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, "))");
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);
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);
fprintf(vlog_out, ") > 0 ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : -(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, "))");
}
break;
default:
fprintf(vlog_out, "<unknown>");

View File

@ -818,13 +818,14 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm)
static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm)
{
switch (ivl_lpm_type(lpm)) {
/* Convert Verilog-A abs() function. This only works when the
/* Convert the Verilog-A abs() function. This only works when the
* argument has no side effect. */
case IVL_LPM_ABS:
// HERE: If this is a real net then use the $abs() function to get nan to
// work correctly. See the expr code.
fprintf(vlog_out, "((");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
fprintf(vlog_out, ") > ");
// HERE: If this is a real net then use 0.0. See the expr code.
fprintf(vlog_out, "0 ? (");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
fprintf(vlog_out, ") : -(");