diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 2c3ed2100..c42e0f456 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -351,14 +351,18 @@ static void emit_expr_sfunc(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_signal(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)); - if (ivl_signal_dimensions(sig)) { - int lsb = ivl_signal_array_base(sig); - int msb = lsb + ivl_signal_array_count(sig); - fprintf(vlog_out, "["); - emit_scaled_expr(scope, ivl_expr_oper1(expr), msb, lsb); - fprintf(vlog_out, "]"); + if (ivl_signal_local(sig)) { + emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + } else { + emit_scope_module_path(scope, ivl_signal_scope(sig)); + fprintf(vlog_out, "%s", ivl_signal_basename(sig)); + if (ivl_signal_dimensions(sig)) { + int lsb = ivl_signal_array_base(sig); + int msb = lsb + ivl_signal_array_count(sig); + fprintf(vlog_out, "["); + emit_scaled_expr(scope, ivl_expr_oper1(expr), msb, lsb); + fprintf(vlog_out, "]"); + } } } @@ -411,6 +415,7 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) case 'i': case 'r': /* A cast is a noop. */ + emit_expr(scope, ivl_expr_oper1(expr), wid); break; default: fprintf(vlog_out, ""); diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 7da84fa7d..7416d2883 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -54,30 +54,45 @@ static void emit_strength(ivl_drive_t drive1, ivl_drive_t drive0, const char *file, unsigned lineno) { assert(strength_type <= 2); - if ((drive1 != IVL_DR_STRONG) || (drive0 != IVL_DR_STRONG)) { + if ((strength_type == 2) && + ((drive1 != IVL_DR_STRONG) || (drive0 != IVL_DR_STRONG))) { fprintf(vlog_out, " ("); - if (strength_type > 0) { - if (emit_drive(drive1)) { - fprintf(vlog_out, ""); - fprintf(stderr, "%s:%u: vlog95 error: Unsupported %s " - "1 drive (%d)\n", file, lineno, - type, (int)drive1); - vlog_errors += 1; - } - fprintf(vlog_out, "1"); + if (emit_drive(drive1)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unsupported %s " + "1 drive (%d)\n", file, lineno, + type, (int)drive1); + vlog_errors += 1; } - if (strength_type == 2) fprintf(vlog_out, ", "); - if ((strength_type & 0x01) == 0) { - if (emit_drive(drive0)) { - fprintf(vlog_out, ""); - fprintf(stderr, "%s:%u: vlog95 error: Unsupported %s " - "0 drive (%d)\n", file, lineno, - type, (int)drive1); - vlog_errors += 1; - } - fprintf(vlog_out, "0"); + fprintf(vlog_out, "1, "); + if (emit_drive(drive0)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unsupported %s " + "0 drive (%d)\n", file, lineno, + type, (int)drive0); + vlog_errors += 1; } - fprintf(vlog_out, ")"); + fprintf(vlog_out, "0)"); + } else if ((strength_type == 1) && (drive1 != IVL_DR_PULL)) { + fprintf(vlog_out, " ("); + if (emit_drive(drive1)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unsupported %s " + "1 drive (%d)\n", file, lineno, + type, (int)drive1); + vlog_errors += 1; + } + fprintf(vlog_out, "1)"); + } else if ((strength_type == 0) && (drive0 != IVL_DR_PULL)) { + fprintf(vlog_out, " ("); + if (emit_drive(drive0)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unsupported %s " + "0 drive (%d)\n", file, lineno, + type, (int)drive0); + vlog_errors += 1; + } + fprintf(vlog_out, "0)"); } } @@ -108,28 +123,28 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t rise, ivl_expr_t fall, /* If all three delays match then we only have a single delay. */ if ((rise == fall) && (rise == decay)) { fprintf(vlog_out, " #("); - emit_scaled_delayx(scope, rise); + emit_scaled_delayx(scope, rise, 0); 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); + emit_scaled_delayx(scope, rise, 0); fprintf(vlog_out, ", "); - emit_scaled_delayx(scope, fall); + emit_scaled_delayx(scope, fall, 0); fprintf(vlog_out, ")"); return; } /* What's left is a gate that supports three delays. */ fprintf(vlog_out, " #("); - emit_scaled_delayx(scope, rise); + emit_scaled_delayx(scope, rise, 0); fprintf(vlog_out, ", "); - emit_scaled_delayx(scope, fall); + emit_scaled_delayx(scope, fall, 0); if (decay) { fprintf(vlog_out, ", "); - emit_scaled_delayx(scope, decay); + emit_scaled_delayx(scope, decay, 0); } fprintf(vlog_out, ")"); } @@ -215,7 +230,7 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm) static void emit_logic_as_ca(ivl_scope_t scope, ivl_net_logic_t nlogic); static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm); -static void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) +void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) { /* If there is no nexus then there is nothing to print. */ if (! nex) return; @@ -857,11 +872,13 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) case IVL_LO_PULLDOWN: fprintf(vlog_out, "pulldown"); dly_count = 0; + outputs = 0; strength_type = 0; break; case IVL_LO_PULLUP: fprintf(vlog_out, "pullup"); dly_count = 0; + outputs = 0; strength_type = 1; break; case IVL_LO_RCMOS: @@ -919,7 +936,13 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx)); fprintf(vlog_out, ", "); } - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, count)); + if (strength_type == 2) { + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx)); + } else { + /* A pull gate only has a single output connection. */ + assert(count == 0); + emit_name_of_logic_nexus(scope, nlogic, ivl_logic_pin(nlogic, idx)); + } fprintf(vlog_out, ");"); emit_logic_file_line(nlogic); fprintf(vlog_out, "\n"); @@ -990,7 +1013,6 @@ void emit_tran(ivl_scope_t scope, ivl_switch_t tran) } fprintf(vlog_out, ");"); if (emit_file_line) { -assert(ivl_switch_lineno(tran)); fprintf(vlog_out, " /* %s:%u */", ivl_switch_file(tran), ivl_switch_lineno(tran)); diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 9388ac90c..7c54e5a34 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -65,7 +65,7 @@ void emit_scaled_delay(ivl_scope_t scope, uint64_t delay) * Emit a constant or variable delay that has been rescaled to the given * scopes timescale. */ -void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr) +void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt) { if (ivl_expr_type(expr) == IVL_EX_NUMBER) { assert(! ivl_expr_signed(expr)); @@ -109,6 +109,9 @@ void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr) emit_expr(scope, expr, 0); return; } else { +// HERE: If we have a statement delay then a real variable delay has already +// been encoded as int((real expr) * tu_tp_scale) * tp_sim_scale. So +// we need to look for that pattern as well. uint64_t scale_val, scale = 1; int rtype; assert(! ivl_expr_signed(expr)); @@ -154,7 +157,7 @@ void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr) scale *= 10; exponent -= 1; } - if (scale != scale_val) { + if (scale != scale_val) { fprintf(vlog_out, ""); fprintf(stderr, "%s:%u: vlog95 error: Variable time " "expression/value scale coefficient " diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index d7671fdcc..fe6648ca3 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -150,18 +150,20 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt) } /* - * Icarus translated = into + * Icarus translated = into * begin * = ; - * = ; + * = ; * end * This routine looks for this pattern and turns it back into the * appropriate blocking assignment. */ -static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt) +static unsigned find_delayed_or_event_assign(ivl_scope_t scope, + ivl_statement_t stmt) { unsigned wid; ivl_statement_t assign, delay, delayed_assign; + ivl_statement_type_t delay_type; ivl_lval_t lval; ivl_expr_t rval; ivl_signal_t lsig, rsig; @@ -173,7 +175,9 @@ static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt) if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0; /* The second must be a delayx. */ delay = ivl_stmt_block_stmt(stmt, 1); - if (ivl_statement_type(delay) != IVL_ST_DELAYX) return 0; + delay_type = ivl_statement_type(delay); + if ((delay_type != IVL_ST_DELAYX) && + (delay_type != IVL_ST_WAIT)) return 0; /* The statement for the delayx must be an assign. */ delayed_assign = ivl_stmt_sub_stmt(delay); if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0; @@ -201,8 +205,14 @@ 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, " = #("); - emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay)); + fprintf(vlog_out, " = "); + if (delay_type == IVL_ST_DELAYX) { + fprintf(vlog_out, "#("); + emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay), 1); + } else { + fprintf(vlog_out, "@("); + emit_event(scope, delay); + } fprintf(vlog_out, ") "); emit_expr(scope, ivl_stmt_rval(assign), wid); fprintf(vlog_out, ";"); @@ -213,16 +223,17 @@ static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt) } /* - * Icarus translated = into + * Icarus translated = repeat() into * begin * = ; - * ; + * repeat() ; * = ; * end * This routine looks for this pattern and turns it back into the * appropriate blocking assignment. */ -static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt) +static unsigned find_repeat_event_assign(ivl_scope_t scope, + ivl_statement_t stmt) { unsigned wid; ivl_statement_t assign, event, event_assign, repeat = 0; @@ -237,8 +248,7 @@ static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt) if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0; /* The second must be a repeat with an event or an event. */ event = ivl_stmt_block_stmt(stmt, 1); - if (ivl_statement_type(event) != IVL_ST_REPEAT && - ivl_statement_type(event) != IVL_ST_WAIT) return 0; + if (ivl_statement_type(event) != IVL_ST_REPEAT) return 0; if (ivl_statement_type(event) == IVL_ST_REPEAT) { repeat = event; event = ivl_stmt_sub_stmt(repeat); @@ -704,7 +714,7 @@ 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(), ' '); - emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt)); + emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt), 1); fprintf(vlog_out, ")"); emit_stmt_file_line(stmt); single_indent = 1; @@ -880,8 +890,8 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) if (ivl_stmt_block_scope(stmt)) { emit_stmt_block_named(scope, stmt); } else { - if (find_delayed_assign(scope, stmt)) break; - if (find_event_assign(scope, stmt)) break; + if (find_delayed_or_event_assign(scope, stmt)) break; + if (find_repeat_event_assign(scope, stmt)) break; if (find_wait(scope, stmt)) break; emit_stmt_block(scope, stmt); } diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index ecf22da6c..bdca9b6a8 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -69,7 +69,8 @@ extern void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt); extern void emit_tran(ivl_scope_t scope, ivl_switch_t tran); extern void emit_scaled_delay(ivl_scope_t scope, uint64_t delay); -extern void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr); +extern void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr, + unsigned is_stmt); extern void emit_scaled_expr(ivl_scope_t scope, ivl_expr_t expr, int msb, int lsb); extern void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, @@ -78,6 +79,7 @@ extern void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope); extern void emit_scope_variables(ivl_scope_t scope); extern void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope); extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex); +extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex); extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net); extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig); extern void emit_icarus_generated_udps();