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:
parent
72ede358ad
commit
424fba819e
|
|
@ -68,6 +68,13 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
switch(ivl_expr_type(expr)) {
|
||||
case IVL_EX_ARRAY:
|
||||
emit_expr_array(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_BINARY:
|
||||
emit_expr_binary(scope, expr, wid);
|
||||
break;
|
||||
|
|
@ -422,7 +453,7 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
emit_expr_number(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_REALNUM:
|
||||
fprintf(vlog_out, "%#g", ivl_expr_dvalue(expr));
|
||||
emit_expr_real_number(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_SCOPE:
|
||||
emit_expr_scope(scope, expr, wid);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
assert(! ivl_expr_signed(expr));
|
||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||
assert(! ivl_expr_signed(expr));
|
||||
int rtype;
|
||||
uint64_t value = get_uint64_from_number(expr, &rtype);
|
||||
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;
|
||||
assert(exponent >= 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;
|
||||
int rtype;
|
||||
assert(! ivl_expr_signed(expr));
|
||||
/* This is as easy as removing the multiple that was
|
||||
* added to scale the value to the simulation time,
|
||||
* but we need to verify that the scaling value is
|
||||
|
|
|
|||
|
|
@ -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 ((rise == fall) && (rise == decay)) {
|
||||
fprintf(vlog_out, " #");
|
||||
fprintf(vlog_out, " #(");
|
||||
emit_scaled_delayx(scope, rise);
|
||||
fprintf(vlog_out, ")");
|
||||
return;
|
||||
}
|
||||
/* If we have a gate that only supports two delays then print them. */
|
||||
if (dly_count == 2) {
|
||||
fprintf(vlog_out, " #(");
|
||||
emit_scaled_delayx(scope, rise);
|
||||
fprintf(vlog_out, ",");
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_scaled_delayx(scope, fall);
|
||||
fprintf(vlog_out, ")");
|
||||
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. */
|
||||
fprintf(vlog_out, " #(");
|
||||
emit_scaled_delayx(scope, rise);
|
||||
fprintf(vlog_out, ",");
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_scaled_delayx(scope, fall);
|
||||
if (decay) {
|
||||
fprintf(vlog_out, ",");
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_scaled_delayx(scope, decay);
|
||||
}
|
||||
fprintf(vlog_out, ")");
|
||||
|
|
@ -381,6 +382,8 @@ static void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic)
|
|||
}
|
||||
emit_gate_strength(nlogic);
|
||||
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));
|
||||
count = ivl_logic_pins(nlogic);
|
||||
count -= 1;
|
||||
|
|
|
|||
|
|
@ -117,16 +117,17 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
unsigned wid = 0;
|
||||
if (count > 1) {
|
||||
unsigned idx;
|
||||
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
|
||||
wid += ivl_lval_width(lval);
|
||||
ivl_lval_t lval;
|
||||
fprintf(vlog_out, "{");
|
||||
emit_stmt_lval_piece(scope, lval);
|
||||
for (idx = 1; idx < count; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
for (idx = count - 1; idx > 0; idx -= 1) {
|
||||
lval = ivl_stmt_lval(stmt, idx);
|
||||
wid += ivl_lval_width(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, "}");
|
||||
} else {
|
||||
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
|
||||
// done this for us.
|
||||
wid = emit_stmt_lval(scope, delayed_assign);
|
||||
fprintf(vlog_out, " = #");
|
||||
fprintf(vlog_out, " = #(");
|
||||
emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay));
|
||||
fprintf(vlog_out, " ");
|
||||
fprintf(vlog_out, ") ");
|
||||
emit_expr(scope, ivl_stmt_rval(assign), wid);
|
||||
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)
|
||||
{
|
||||
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(), ' ');
|
||||
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0);
|
||||
fprintf(vlog_out, ")");
|
||||
if (ivl_stmt_cond_true(stmt)) {
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, ivl_stmt_cond_true(stmt));
|
||||
if (true_stmt) {
|
||||
/* If we have a false statement and the true statement is a
|
||||
* 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 {
|
||||
fprintf(vlog_out, ";\n");
|
||||
}
|
||||
if (ivl_stmt_cond_false(stmt)) {
|
||||
fprintf(vlog_out, "%*celse", get_indent(), ' ');
|
||||
if (false_stmt) {
|
||||
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;
|
||||
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)
|
||||
{
|
||||
fprintf(vlog_out, "%*c#", get_indent(), ' ');
|
||||
fprintf(vlog_out, "%*c#(", get_indent(), ' ');
|
||||
emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt));
|
||||
fprintf(vlog_out, ")");
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue