vlog95: more functionality and some bug fixes.

This patch adds support for emitting an array as an expression. This is
used as a system task/function argument.

It partially reworks the real display code to print an appropriate
expression for NaN, inf and -inf. To get other real numbers to always
display correctly we need to build a custom printing routine that adjusts
what is displayed based on the actual bits in the double.

Add the ability to print a real variable delay. They are not scaled by
the compiler.

Since a delayx delay may be variable we must always enclose this type of
delay with parenthesis.

Fix the L-value concatenation to be in the correct order.

Handle the special case that an if with a single if as the true statement
does not loose any associated else clause to the enclosed if. Basically
add a begin/end pair as needed to make things work out correctly.
This commit is contained in:
Cary R 2011-01-28 14:52:32 -08:00 committed by Stephen Williams
parent 72ede358ad
commit 424fba819e
4 changed files with 91 additions and 21 deletions

View File

@ -68,6 +68,13 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
return 1; return 1;
} }
static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
ivl_signal_t sig = ivl_expr_signal(expr);
emit_scope_module_path(scope, ivl_signal_scope(sig));
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
}
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)
{ {
char *oper = "<invalid>"; char *oper = "<invalid>";
@ -271,6 +278,27 @@ static void emit_expr_number(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
} }
} }
static void emit_expr_real_number(ivl_scope_t scope, ivl_expr_t expr,
unsigned wid)
{
double value = ivl_expr_dvalue(expr);
/* Check for NaN. */
if (value != value) {
fprintf(vlog_out, "(0.0/0.0)");
return;
}
/* Check for the infinities. */
if (value && value == 0.5*value) {
if (value > 0) fprintf(vlog_out, "(1.0/0.0)");
else fprintf(vlog_out, "(-1.0/0.0)");
return;
}
// HERE: This needs to be reworked. We must have a trailing digit after the
// decimal point and we want to print all the significant digits.
// I think the will require our own printing routine.
fprintf(vlog_out, "%#.16g", ivl_expr_dvalue(expr));
}
static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{ {
fprintf(vlog_out, "%s", ivl_scope_name(ivl_expr_scope(expr))); fprintf(vlog_out, "%s", ivl_scope_name(ivl_expr_scope(expr)));
@ -409,6 +437,9 @@ 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) void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{ {
switch(ivl_expr_type(expr)) { switch(ivl_expr_type(expr)) {
case IVL_EX_ARRAY:
emit_expr_array(scope, expr, wid);
break;
case IVL_EX_BINARY: case IVL_EX_BINARY:
emit_expr_binary(scope, expr, wid); emit_expr_binary(scope, expr, wid);
break; break;
@ -422,7 +453,7 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
emit_expr_number(scope, expr, wid); emit_expr_number(scope, expr, wid);
break; break;
case IVL_EX_REALNUM: case IVL_EX_REALNUM:
fprintf(vlog_out, "%#g", ivl_expr_dvalue(expr)); emit_expr_real_number(scope, expr, wid);
break; break;
case IVL_EX_SCOPE: case IVL_EX_SCOPE:
emit_expr_scope(scope, expr, wid); emit_expr_scope(scope, expr, wid);

View File

@ -67,8 +67,8 @@ void emit_scaled_delay(ivl_scope_t scope, uint64_t delay)
*/ */
void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr) void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr)
{ {
assert(! ivl_expr_signed(expr));
if (ivl_expr_type(expr) == IVL_EX_NUMBER) { if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
assert(! ivl_expr_signed(expr));
int rtype; int rtype;
uint64_t value = get_uint64_from_number(expr, &rtype); uint64_t value = get_uint64_from_number(expr, &rtype);
if (rtype > 0) { if (rtype > 0) {
@ -94,9 +94,24 @@ void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr)
int exponent = ivl_scope_time_units(scope) - sim_precision; int exponent = ivl_scope_time_units(scope) - sim_precision;
assert(exponent >= 0); assert(exponent >= 0);
if (exponent == 0) emit_expr(scope, expr, 0); if (exponent == 0) emit_expr(scope, expr, 0);
else { /* A real delay variable is not scaled by the compiler. */
else if (ivl_expr_type(expr) == IVL_EX_SIGNAL) {
ivl_signal_t sig = ivl_expr_signal(expr);
if (ivl_signal_data_type(sig) != IVL_VT_REAL) {
fprintf(vlog_out, "<invalid>");
fprintf(stderr, "%s:%u: vlog95 error: Only real "
"delay variables are scaled at run "
"time.\n", ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
return;
}
emit_expr(scope, expr, 0);
return;
} else {
uint64_t scale_val, scale = 1; uint64_t scale_val, scale = 1;
int rtype; int rtype;
assert(! ivl_expr_signed(expr));
/* This is as easy as removing the multiple that was /* This is as easy as removing the multiple that was
* added to scale the value to the simulation time, * added to scale the value to the simulation time,
* but we need to verify that the scaling value is * but we need to verify that the scaling value is

View File

@ -257,15 +257,16 @@ static void emit_gate_delay(ivl_scope_t scope, ivl_net_logic_t nlogic,
} }
/* If all three delays match then we only have a single delay. */ /* If all three delays match then we only have a single delay. */
if ((rise == fall) && (rise == decay)) { if ((rise == fall) && (rise == decay)) {
fprintf(vlog_out, " #"); fprintf(vlog_out, " #(");
emit_scaled_delayx(scope, rise); emit_scaled_delayx(scope, rise);
fprintf(vlog_out, ")");
return; return;
} }
/* If we have a gate that only supports two delays then print them. */ /* If we have a gate that only supports two delays then print them. */
if (dly_count == 2) { if (dly_count == 2) {
fprintf(vlog_out, " #("); fprintf(vlog_out, " #(");
emit_scaled_delayx(scope, rise); emit_scaled_delayx(scope, rise);
fprintf(vlog_out, ","); fprintf(vlog_out, ", ");
emit_scaled_delayx(scope, fall); emit_scaled_delayx(scope, fall);
fprintf(vlog_out, ")"); fprintf(vlog_out, ")");
return; return;
@ -274,10 +275,10 @@ static void emit_gate_delay(ivl_scope_t scope, ivl_net_logic_t nlogic,
/* What's left is a gate that supports three delays. */ /* What's left is a gate that supports three delays. */
fprintf(vlog_out, " #("); fprintf(vlog_out, " #(");
emit_scaled_delayx(scope, rise); emit_scaled_delayx(scope, rise);
fprintf(vlog_out, ","); fprintf(vlog_out, ", ");
emit_scaled_delayx(scope, fall); emit_scaled_delayx(scope, fall);
if (decay) { if (decay) {
fprintf(vlog_out, ","); fprintf(vlog_out, ", ");
emit_scaled_delayx(scope, decay); emit_scaled_delayx(scope, decay);
} }
fprintf(vlog_out, ")"); fprintf(vlog_out, ")");
@ -381,6 +382,8 @@ static void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic)
} }
emit_gate_strength(nlogic); emit_gate_strength(nlogic);
if (dly_count) emit_gate_delay(scope, nlogic, dly_count); if (dly_count) emit_gate_delay(scope, nlogic, dly_count);
// HERE: The name has the location information encoded in it. We need to
// remove this and rebuild the instance array.
fprintf(vlog_out, " %s(", ivl_logic_basename(nlogic)); fprintf(vlog_out, " %s(", ivl_logic_basename(nlogic));
count = ivl_logic_pins(nlogic); count = ivl_logic_pins(nlogic);
count -= 1; count -= 1;

View File

@ -117,16 +117,17 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt)
unsigned wid = 0; unsigned wid = 0;
if (count > 1) { if (count > 1) {
unsigned idx; unsigned idx;
ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_lval_t lval;
wid += ivl_lval_width(lval);
fprintf(vlog_out, "{"); fprintf(vlog_out, "{");
emit_stmt_lval_piece(scope, lval); for (idx = count - 1; idx > 0; idx -= 1) {
for (idx = 1; idx < count; idx += 1) {
fprintf(vlog_out, ", ");
lval = ivl_stmt_lval(stmt, idx); lval = ivl_stmt_lval(stmt, idx);
wid += ivl_lval_width(lval); wid += ivl_lval_width(lval);
emit_stmt_lval_piece(scope, lval); emit_stmt_lval_piece(scope, lval);
fprintf(vlog_out, ", ");
} }
lval = ivl_stmt_lval(stmt, 0);
wid += ivl_lval_width(lval);
emit_stmt_lval_piece(scope, lval);
fprintf(vlog_out, "}"); fprintf(vlog_out, "}");
} else { } else {
ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
@ -188,9 +189,9 @@ static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
// HERE: Do we need to calculate the width? The compiler should have already // HERE: Do we need to calculate the width? The compiler should have already
// done this for us. // done this for us.
wid = emit_stmt_lval(scope, delayed_assign); wid = emit_stmt_lval(scope, delayed_assign);
fprintf(vlog_out, " = #"); fprintf(vlog_out, " = #(");
emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay)); emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay));
fprintf(vlog_out, " "); fprintf(vlog_out, ") ");
emit_expr(scope, ivl_stmt_rval(assign), wid); emit_expr(scope, ivl_stmt_rval(assign), wid);
fprintf(vlog_out, ";\n"); fprintf(vlog_out, ";\n");
@ -494,19 +495,38 @@ static void emit_stmt_cassign(ivl_scope_t scope, ivl_statement_t stmt)
static void emit_stmt_condit(ivl_scope_t scope, ivl_statement_t stmt) static void emit_stmt_condit(ivl_scope_t scope, ivl_statement_t stmt)
{ {
ivl_statement_t true_stmt = ivl_stmt_cond_true(stmt);
ivl_statement_t false_stmt = ivl_stmt_cond_false(stmt);
unsigned nest = 0;
fprintf(vlog_out, "%*cif (", get_indent(), ' '); fprintf(vlog_out, "%*cif (", get_indent(), ' ');
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0); emit_expr(scope, ivl_stmt_cond_expr(stmt), 0);
fprintf(vlog_out, ")"); fprintf(vlog_out, ")");
if (ivl_stmt_cond_true(stmt)) { if (true_stmt) {
single_indent = 1; /* If we have a false statement and the true statement is a
emit_stmt(scope, ivl_stmt_cond_true(stmt)); * condition that does not have a false clause then we need
* to add a begin/end pair to keep the else clause attached
* to this condition. */
if (false_stmt &&
(ivl_statement_type(true_stmt) == IVL_ST_CONDIT) &&
(! ivl_stmt_cond_false(true_stmt))) nest = 1;
if (nest) {
fprintf(vlog_out, " begin\n");
indent += indent_incr;
} else single_indent = 1;
emit_stmt(scope, true_stmt);
} else { } else {
fprintf(vlog_out, ";\n"); fprintf(vlog_out, ";\n");
} }
if (ivl_stmt_cond_false(stmt)) { if (false_stmt) {
fprintf(vlog_out, "%*celse", get_indent(), ' '); if (nest) {
assert(indent >= indent_incr);
indent -= indent_incr;
}
fprintf(vlog_out, "%*c", get_indent(), ' ');
if (nest) fprintf(vlog_out, "end ");
fprintf(vlog_out, "else");
single_indent = 1; single_indent = 1;
emit_stmt(scope, ivl_stmt_cond_false(stmt)); emit_stmt(scope, false_stmt);
} }
} }
@ -527,8 +547,9 @@ static void emit_stmt_delay(ivl_scope_t scope, ivl_statement_t stmt)
static void emit_stmt_delayx(ivl_scope_t scope, ivl_statement_t stmt) static void emit_stmt_delayx(ivl_scope_t scope, ivl_statement_t stmt)
{ {
fprintf(vlog_out, "%*c#", get_indent(), ' '); fprintf(vlog_out, "%*c#(", get_indent(), ' ');
emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt)); emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt));
fprintf(vlog_out, ")");
single_indent = 1; single_indent = 1;
emit_stmt(scope, ivl_stmt_sub_stmt(stmt)); emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
} }