diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 7475142fd..db931024b 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -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 = ""; @@ -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); diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index dd6258ecc..885145a12 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -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, ""); + 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 diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 4927948b3..90f7c39ca 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -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; diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 5ad50cc2b..48051ca61 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -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)); }