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;
|
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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue