diff --git a/tgt-vlog95/event.c b/tgt-vlog95/event.c index 0be1ce673..cc8b169c9 100644 --- a/tgt-vlog95/event.c +++ b/tgt-vlog95/event.c @@ -62,6 +62,8 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) /* We have a named event if there were no edge events. */ if (!had_edge) { ivl_scope_t ev_scope = ivl_event_scope(event); + if (first) first = 0; + else fprintf(vlog_out, " or "); emit_scope_module_path(scope, ev_scope); fprintf(vlog_out, "%s", ivl_event_basename(event)); } diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index e5bad93e1..ede1c7da3 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -72,7 +72,7 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr, 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)); + emit_scope_call_path(scope, ivl_signal_scope(sig)); fprintf(vlog_out, "%s", ivl_signal_basename(sig)); } @@ -142,9 +142,13 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) fprintf(vlog_out, " %s ", oper); emit_expr(scope, ivl_expr_oper2(expr), 0); break; + case 'R': + fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not " + "supported.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr)); + vlog_errors += 1; case 'l': case 'r': - case 'R': emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, " %s ", oper); emit_expr(scope, ivl_expr_oper2(expr), 0); @@ -215,7 +219,7 @@ static void emit_expr_event(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) assert(! ivl_event_nany(event)); assert(! ivl_event_npos(event)); assert(! ivl_event_nneg(event)); - emit_scope_module_path(scope, ev_scope); + emit_scope_call_path(scope, ev_scope); fprintf(vlog_out, "%s", ivl_event_basename(event)); } @@ -439,7 +443,7 @@ 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)); + emit_scope_call_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); diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 1feffb16d..e1a5819af 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -239,6 +239,7 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) /* A local nexus only has a single driver. */ if (is_local_nexus(scope, nex)) { unsigned idx, count = ivl_nexus_ptrs(nex); + unsigned must_be_sig = 0; ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; ivl_net_logic_t net_logic = 0; @@ -246,7 +247,13 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && - (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) { + /* If we only have a single input then we want + * the nexus this signal is driven by. */ + if (count == 1) { + must_be_sig = 1; + } else continue; + } ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); @@ -272,23 +279,29 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) assert(! net_const); assert(! net_logic); assert(! sig); - fprintf(vlog_out, "("); + assert(! must_be_sig); emit_lpm_as_ca(scope, lpm); - fprintf(vlog_out, ")"); } else if (net_const) { assert( !net_logic); assert(! sig); + assert(! must_be_sig); emit_const_nexus(scope, net_const); } else if (net_logic) { assert(! sig); - fprintf(vlog_out, "("); + assert(! must_be_sig); emit_logic_as_ca(scope, net_logic); - fprintf(vlog_out, ")"); } else if (sig) { - emit_name_of_nexus(scope, nex); + if (must_be_sig) { + emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + } else emit_name_of_nexus(scope, nex); // HERE: The assert causes pr1703959 to fail. // } else assert(0); - } else fprintf(vlog_out, ""); + } else { + fprintf(stderr, "?:?: vlog95 error: Could not emit " + "nexus as a CA.\n"); + vlog_errors += 1; + fprintf(vlog_out, ""); + } } else { emit_name_of_nexus(scope, nex); } @@ -300,9 +313,11 @@ static void emit_logic_as_ca(ivl_scope_t scope, ivl_net_logic_t nlogic) switch (ivl_logic_type(nlogic)) { case IVL_LO_AND: assert(inputs == 2); + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); fprintf(vlog_out, " & "); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + fprintf(vlog_out, ")"); break; case IVL_LO_BUF: // case IVL_LO_BUFT: @@ -312,42 +327,54 @@ static void emit_logic_as_ca(ivl_scope_t scope, ivl_net_logic_t nlogic) break; case IVL_LO_NAND: assert(inputs == 2); + fprintf(vlog_out, "~("); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); - fprintf(vlog_out, " ~& "); + fprintf(vlog_out, " & "); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + fprintf(vlog_out, ")"); break; case IVL_LO_NOR: assert(inputs == 2); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); - fprintf(vlog_out, " ~| "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); - break; - case IVL_LO_NOT: - assert(inputs == 1); - fprintf(vlog_out, "~ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); - break; - case IVL_LO_OR: - assert(inputs == 2); + fprintf(vlog_out, "~("); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); fprintf(vlog_out, " | "); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + fprintf(vlog_out, ")"); + break; + case IVL_LO_NOT: + assert(inputs == 1); + fprintf(vlog_out, "(~ "); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + fprintf(vlog_out, ")"); + break; + case IVL_LO_OR: + assert(inputs == 2); + fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + fprintf(vlog_out, " | "); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + fprintf(vlog_out, ")"); break; case IVL_LO_XNOR: assert(inputs == 2); + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); fprintf(vlog_out, " ~^ "); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + fprintf(vlog_out, ")"); break; case IVL_LO_XOR: assert(inputs == 2); + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); fprintf(vlog_out, " ^ "); emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + fprintf(vlog_out, ")"); break; default: fprintf(vlog_out, ""); - fprintf(stderr, "%s:%u: vlog95 error: Unknown logic type (%d).\n", + fprintf(stderr, "%s:%u: vlog95 error: Unknown CA logic type " + "(%d).\n", ivl_logic_file(nlogic), ivl_logic_lineno(nlogic), (int)ivl_logic_type(nlogic)); vlog_errors += 1; @@ -359,48 +386,153 @@ static void emit_lpm_array(ivl_scope_t scope, ivl_lpm_t lpm) ivl_signal_t sig = ivl_lpm_array(lpm); emit_scope_module_path(scope, ivl_signal_scope(sig)); fprintf(vlog_out, "%s[", ivl_signal_basename(sig)); -// HERE: Need to scale this to match array base. +// HERE: Need to remove the scale to match array base. emit_nexus_as_ca(scope, ivl_lpm_select(lpm)); - fprintf(vlog_out, "]"); + fprintf(vlog_out, " + %d]", ivl_signal_array_base(sig)); } static void emit_lpm_concat(ivl_scope_t scope, ivl_lpm_t lpm) { unsigned idx, count= ivl_lpm_size(lpm); + ivl_nexus_t nex; fprintf(vlog_out, "{"); - for (idx = count-1; idx > 0; idx -= 1) { - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx)); - fprintf(vlog_out, ", "); +// HERE: Need to check for a zero repeat that was dropped from the concat. + /* Check to see if this is a repeat. */ + nex = ivl_lpm_data(lpm, 0); + for (idx = 1; idx < count; idx += 1) { + if (nex != ivl_lpm_data(lpm, idx)) break; + } + /* If all the nexus match then we have a repeat. */ + if ((idx == count) && (count > 1)) { + fprintf(vlog_out, "%u{", count); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, "}"); + } else { + for (idx = count-1; idx > 0; idx -= 1) { + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx)); + fprintf(vlog_out, ", "); + } + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); } - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, "}"); } -static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex) +static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex, + int*base, int*array_word) { -// HERE: check to see if this is a signal, an array word or parameter. - return 0; + unsigned idx, count = ivl_nexus_ptrs(nex); + ivl_lpm_t lpm = 0; + ivl_net_const_t net_const = 0; + ivl_net_logic_t net_logic = 0; + ivl_signal_t sig = 0; + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; + ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); + ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); + ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (t_lpm) { + assert(! lpm); + /* The real signal could be hidden behind a select. */ + if (ivl_lpm_type(t_lpm) == IVL_LPM_PART_VP) { + t_sig = nexus_is_signal(scope, ivl_lpm_data(t_lpm, 0), + base, array_word); + if (t_sig) *base += ivl_lpm_base(t_lpm); + } else lpm = t_lpm; + } + if (t_net_const) { + assert(! net_const); + net_const = t_net_const; + } + if (t_net_logic) { + assert(! net_logic); + /* The real signal could be hidden behind a BUFZ gate. */ + if (ivl_logic_type(t_net_logic) == IVL_LO_BUFZ) { + assert(ivl_logic_pins(t_net_logic) == 2); + t_sig = nexus_is_signal(scope, + ivl_logic_pin(t_net_logic, 1), + base, array_word); + } else net_logic = t_net_logic; + } + if (t_sig) { + assert(! sig); + sig = t_sig; + /* This could be an array word so save the word. */ + *array_word = ivl_nexus_ptr_pin(nex_ptr); + } + } + if (sig) { + assert(! lpm); + assert(! net_const); + assert(! net_logic); + } + return sig; } static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) { unsigned width = ivl_lpm_width(lpm); - unsigned base = ivl_lpm_base(lpm); - ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0)); + int array_word = 0; + int base = ivl_lpm_base(lpm); + int msb, lsb; + ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0), + &base, &array_word); // HERE: variable parameter select needs to be rebuilt. - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); - if (! sig) return; -// HERE: We need the signal MSB/LSB to scale the select correctly. + if (! sig) { + /* Check if the compiler used a select for a shift. */ + assert(base >= 0); + if (base) fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + if (base) fprintf(vlog_out, " >> %d)", base); + return; + } + fprintf(vlog_out, "%s", ivl_signal_basename(sig)); + if (ivl_signal_dimensions(sig)) { + array_word += ivl_signal_array_base(sig); + fprintf(vlog_out, "[%d]", array_word); + } + msb = ivl_signal_msb(sig); + lsb = ivl_signal_lsb(sig); fprintf(vlog_out, "["); if (width == 1) { ivl_nexus_t sel = ivl_lpm_data(lpm, 1); - if (sel) emit_nexus_as_ca(scope, sel); - else fprintf(vlog_out, "%u", base); + if (sel) { +// HERE: Need to scale the select nexus. + if ((msb >= lsb) && (lsb == 0)) { + emit_nexus_as_ca(scope, sel); + } else { + fprintf(stderr, "%s:%u: vlog95 sorry: Non-zero based " + "variable part selects are not " + "supported.\n", ivl_lpm_file(lpm), + ivl_lpm_lineno(lpm)); + vlog_errors += 1; + fprintf(vlog_out, ""); + } + } else { + if (msb >= lsb) base += lsb; + else base = lsb - base; + fprintf(vlog_out, "%d", base); + } } else { -// HERE: No support for a variable select. - fprintf(vlog_out, "%u", base+width-1); - fprintf(vlog_out, ":"); - fprintf(vlog_out, "%u", base); +// HERE: No support for an indexed part select. + ivl_nexus_t sel = ivl_lpm_data(lpm, 1); + if (sel) { + fprintf(stderr, "%s:%u: vlog95 sorry: Variable indexed part " + "selects are not supported.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + fprintf(vlog_out, ":"); + } else { + if (msb >= lsb) { + base += lsb; + fprintf(vlog_out, "%d:%d", base+(int)width-1, base); + } else { + base = lsb - base; + fprintf(vlog_out, "%d:%d", base-(int)width+1, base); + } + } } fprintf(vlog_out, "]"); } @@ -422,9 +554,11 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " + "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_ARRAY: emit_lpm_array(scope, lpm); @@ -435,42 +569,56 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); break; case IVL_LPM_CMP_EEQ: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " === "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_EQ: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " == "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_GE: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " >= "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_GT: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " > "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_NE: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " != "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_NEE: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " !== "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_CONCAT: emit_lpm_concat(scope, lpm); break; case IVL_LPM_DIVIDE: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " / "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_MOD: // HERE: Need to check if this LPM is IVL_VT_REAL. @@ -480,21 +628,27 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); vlog_errors += 1; } + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " %% "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_MULT: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " * "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_MUX: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_select(lpm)); fprintf(vlog_out, " ? "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); fprintf(vlog_out, " : "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_PART_PV: emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); @@ -503,28 +657,34 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) emit_lpm_part_select(scope, lpm); break; case IVL_LPM_RE_AND: - fprintf(vlog_out, " & "); + fprintf(vlog_out, "(&"); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_RE_NAND: - fprintf(vlog_out, " ~& "); + fprintf(vlog_out, "(~&"); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_RE_NOR: - fprintf(vlog_out, " ~| "); + fprintf(vlog_out, "(~|"); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_RE_OR: - fprintf(vlog_out, " | "); + fprintf(vlog_out, "(|"); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_RE_XOR: - fprintf(vlog_out, " ^ "); + fprintf(vlog_out, "(^"); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_RE_XNOR: - fprintf(vlog_out, " ~^ "); + fprintf(vlog_out, "(~^"); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, ")"); break; case IVL_LPM_REPEAT: fprintf(vlog_out, "{%u{", ivl_lpm_size(lpm)); @@ -535,23 +695,29 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) emit_lpm_func(scope, lpm, ivl_lpm_string(lpm)); break; case IVL_LPM_SHIFTL: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " << "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_SHIFTR: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " >> "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_SIGN_EXT: // HERE: Do we need to extend here? emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); break; case IVL_LPM_SUB: + fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); fprintf(vlog_out, " - "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + fprintf(vlog_out, ")"); break; case IVL_LPM_UFUNC: emit_lpm_func(scope, lpm, ivl_scope_name(ivl_lpm_define(lpm))); @@ -658,8 +824,7 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) unsigned emitted, have_data, have_sset; const char *aset_bits = 0; const char *sset_bits = 0; - /* For now we and the compiler only support a width of 1. */ - assert(ivl_lpm_width(lpm) == 1); + /* For now we only support a width of 1 for these bits. */ if (aset_expr) { assert(ivl_expr_width(aset_expr) == 1); aset_bits = ivl_expr_bits(aset_expr); @@ -679,7 +844,11 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) } emit_lpm_strength(lpm); /* The lpm FF does not support any delays. */ - /* The FF name is a temporary so we don't bother to print it. */ + /* The FF name is a temporary so we don't bother to print it unless + * we have a range. Then we need to use a made up name. */ + if (ivl_lpm_width(lpm) > 1) { + fprintf(vlog_out, " synth_%p [%u:0]", lpm, ivl_lpm_width(lpm)-1U); + } fprintf(vlog_out, " ("); /* Emit the q pin. */ emit_name_of_nexus(scope, ivl_lpm_q(lpm)); @@ -760,13 +929,102 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) need_posedge_dff_prim = 1; } +static ivl_signal_t get_output_from_nexus(ivl_scope_t scope, ivl_nexus_t nex, + int64_t*array_idx) +{ + ivl_signal_t use_sig = 0; + unsigned is_array = 0; + unsigned idx, count; + count = ivl_nexus_ptrs(nex); + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); + if (! sig) continue; + if (ivl_signal_local(sig)) { + /* If the local signal is another receiver skip it. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) { + continue; + } + assert(0); + } + /* The signal must be in the correct scope. */ + if (scope != ivl_signal_scope(sig)) continue; + /* Since we are looking for the output signal it is a receiver. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) { + continue; + } + if (use_sig) { +// HERE: Which one should we use? For now it's the first one found. +// I believe this needs to be solved (see the inout.v test). + fprintf(stderr, "%s:%u: vlog95 warning: Duplicate name (%s", + ivl_signal_file(sig), ivl_signal_lineno(sig), + ivl_signal_basename(sig)); + if (ivl_signal_dimensions(sig) > 0) { + int64_t tmp_idx = ivl_nexus_ptr_pin(nex_ptr); + tmp_idx += ivl_signal_array_base(sig); + fprintf(stderr, "[%"PRId64"]", tmp_idx); + } + fprintf(stderr, ") found for nexus "); + fprintf(stderr, "(%s", ivl_signal_basename(use_sig)); + if (is_array) fprintf(stderr, "[%"PRId64"]", *array_idx); + fprintf(stderr, ")\n"); + } else { + /* We have a signal that can be used to find the name. */ + use_sig = sig; + if (ivl_signal_dimensions(sig) > 0) { + is_array = 1; + *array_idx = ivl_nexus_ptr_pin(nex_ptr); + *array_idx += ivl_signal_array_base(sig); + } + } + } + + return use_sig; +} + +static void emit_lpm_part_pv(ivl_scope_t scope, ivl_lpm_t lpm) +{ + unsigned width = ivl_lpm_width(lpm); + int64_t array_word = 0; + int base = ivl_lpm_base(lpm); + int msb, lsb; + ivl_signal_t sig = get_output_from_nexus(scope, ivl_lpm_q(lpm), + &array_word); + assert(sig); + assert(ivl_lpm_data(lpm, 1) == 0); + fprintf(vlog_out, "%s", ivl_signal_basename(sig)); + if (ivl_signal_dimensions(sig)) { + fprintf(vlog_out, "[%"PRId64"]", array_word); + } + msb = ivl_signal_msb(sig); + lsb = ivl_signal_lsb(sig); + fprintf(vlog_out, "["); + if (width == 1) { + if (msb >= lsb) base += lsb; + else base = lsb - base; + fprintf(vlog_out, "%d", base); + } else { + if (msb >= lsb) { + base += lsb; + fprintf(vlog_out, "%d:%d", base+(int)width-1, base); + } else { + base = lsb - base; + fprintf(vlog_out, "%d:%d", base-(int)width+1, base); + } + } + fprintf(vlog_out, "]"); +} + void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) { ivl_nexus_t output = get_lpm_output(scope, lpm); + ivl_lpm_type_t type = ivl_lpm_type(lpm); /* If the output is local then someone else will output this lpm. */ if (! output) return; /* If the LPM is a D-FF then we need to emit it as a UDP. */ - if (ivl_lpm_type(lpm) == IVL_LPM_FF) { + if (type == IVL_LPM_FF) { emit_lpm_ff(scope, lpm); return; } @@ -778,8 +1036,8 @@ void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) ivl_lpm_delay(lpm, 2), 3); fprintf(vlog_out, " "); -// HERE: No support for an L-value concatenation. - emit_name_of_nexus(scope, output); + if (type == IVL_LPM_PART_PV) emit_lpm_part_pv(scope, lpm); + else emit_name_of_nexus(scope, output); fprintf(vlog_out, " = "); emit_lpm_as_ca(scope, lpm); fprintf(vlog_out, ";"); @@ -1094,12 +1352,17 @@ void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig) { ivl_nexus_t nex = ivl_signal_nex(sig, 0); unsigned idx, count = ivl_nexus_ptrs(nex); + unsigned emitted = (unsigned) ivl_nexus_get_private(nex); for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); if (! net_const) continue; if (scope != ivl_const_scope(net_const)) continue; - /* Found the constant so emit it. */ + /* Found the constant so emit it if it has not been emitted. */ + if (emitted) { + --emitted; + continue; + } fprintf(vlog_out, "%*cassign", indent, ' '); emit_strength(ivl_nexus_ptr_drive1(nex_ptr), ivl_nexus_ptr_drive0(nex_ptr), @@ -1115,6 +1378,9 @@ void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig) fprintf(vlog_out, ";"); emit_sig_file_line(sig); fprintf(vlog_out, "\n"); + /* Increment the emitted constant count by one. */ + ivl_nexus_set_private(nex, + (void *) ((unsigned) ivl_nexus_get_private(nex) + 1U)); return; } /* We must find the constant in the nexus. */ diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index e9a947a13..53173ba37 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -474,7 +474,6 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex) } } -// HERE: Check bit, part, etc. selects to make sure they work as well. if (use_sig) { fprintf(vlog_out, "%s", ivl_signal_basename(use_sig)); if (is_array) fprintf(vlog_out, "[%"PRId64"]", array_idx); @@ -545,6 +544,8 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) // Then look for down scopes and then any scope. For all this warn if // multiples are found in a given scope. This all needs to be before // the constant code. + fprintf(stderr, "?:?: vlog95 sorry: Unable to find nexus name.\n"); + vlog_errors += 1; fprintf(vlog_out, ""); } @@ -575,6 +576,7 @@ void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope) { ivl_scope_t mod_scope = get_module_scope(scope); ivl_scope_t call_mod_scope = get_module_scope(call_scope); + if (mod_scope != call_mod_scope) { /* Trim off the top of the call name if it exactly matches * the module scope of the caller. */ @@ -599,6 +601,55 @@ void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope) } } +/* This is the same as emit_scope_module_path() except we need to add down + * references for variables, etc. */ +void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope) +{ + ivl_scope_t mod_scope = get_module_scope(scope); + ivl_scope_t call_mod_scope = get_module_scope(call_scope); + + if (mod_scope != call_mod_scope) { + /* Trim off the top of the call name if it exactly matches + * the module scope of the caller. */ + char *sc_name = strdup(ivl_scope_name(mod_scope)); + const char *sc_ptr = sc_name; + char *call_name = strdup(ivl_scope_name(call_mod_scope)); + const char *call_ptr = call_name; + while ((*sc_ptr == *call_ptr) && + (*sc_ptr != 0) && (*call_ptr != 0)) { + sc_ptr += 1; + call_ptr += 1; + } + if (*sc_ptr == 0) { + assert(*call_ptr == '.'); + call_ptr += 1; + } else { + call_ptr = call_name; + } + fprintf(vlog_out, "%s.", call_ptr); + free(sc_name); + free(call_name); + } else if (scope != call_scope) { + /* Look for a down reference that is local to the module scope. */ + char *sc_name = strdup(ivl_scope_name(scope)); + const char *sc_ptr = sc_name; + char *call_name = strdup(ivl_scope_name(call_scope)); + const char *call_ptr = call_name; + while ((*sc_ptr == *call_ptr) && + (*sc_ptr != 0) && (*call_ptr != 0)) { + sc_ptr += 1; + call_ptr += 1; + } + if (*sc_ptr == 0) { + assert(*call_ptr == '.'); + call_ptr += 1; + fprintf(vlog_out, "%s.", call_ptr); + } + free(sc_name); + free(call_name); + } +} + /* * This routine emits the appropriate string to call the call_scope from the * given scope. If the module scopes for the two match then just return the @@ -611,6 +662,7 @@ void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope) { ivl_scope_t mod_scope = get_module_scope(scope); ivl_scope_t call_mod_scope = get_module_scope(call_scope); + if (mod_scope == call_mod_scope) { fprintf(vlog_out, "%s", ivl_scope_basename(call_scope)); } else { diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index eba4fac0f..146574950 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -339,6 +339,75 @@ static void emit_scope_file_line(ivl_scope_t scope) } } +static void emit_module_ports(ivl_scope_t scope) +{ + unsigned idx, count = ivl_scope_ports(scope); + + if (count == 0) return; + + fprintf(stderr, "%s:%u: vlog95 sorry: Modules with port are not " + "currently supported.\n", ivl_scope_file(scope), + ivl_scope_lineno(scope)); + vlog_errors += 1; + fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0)); + for (idx = 1; idx < count; idx += 1) { + fprintf(vlog_out, ", "); + emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx)); +// HERE: Save the signals that are connected to the nexi and use those +// in the port_def code below. + } + fprintf(vlog_out, ")"); +} + +static void emit_module_port_defs(ivl_scope_t scope) +{ + unsigned idx, count = ivl_scope_ports(scope); + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_t port = ivl_scope_mod_port(scope, idx); + fprintf(vlog_out, "%*c", indent, ' '); +// HERE: Need port type/size information. + emit_nexus_as_ca(scope, port); +// emit_sig_file_line(port); + fprintf(vlog_out, " \n"); + } + if (count) fprintf(vlog_out, "\n"); +} + +static void emit_task_func_port_defs(ivl_scope_t scope) +{ + unsigned idx, count = ivl_scope_ports(scope); + unsigned start = ivl_scope_type(scope) == IVL_SCT_FUNCTION; + for (idx = start; idx < count; idx += 1) { + ivl_signal_t port = ivl_scope_port(scope, idx); + fprintf(vlog_out, "%*c", indent, ' '); + switch (ivl_signal_port(port)) { + case IVL_SIP_INPUT: + fprintf(vlog_out, "input"); + break; + case IVL_SIP_OUTPUT: + fprintf(vlog_out, "output"); + break; + case IVL_SIP_INOUT: + fprintf(vlog_out, "inout"); + break; + default: + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unknown port " + "direction (%d) for signal %s.\n", + ivl_signal_file(port), ivl_signal_lineno(port), + (int)ivl_signal_port(port), + ivl_signal_basename(port)); + vlog_errors += 1; + break; + } + fprintf(vlog_out, " %s;", ivl_signal_basename(port)); + emit_sig_file_line(port); + fprintf(vlog_out, " \n"); + } + if (count) fprintf(vlog_out, "\n"); +} + /* * This search method may be slow for a large structural design with a * large number of gate types. That's not what this converter was built @@ -384,7 +453,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) { ivl_scope_type_t sc_type = ivl_scope_type(scope); unsigned is_auto = ivl_scope_is_auto(scope); - unsigned idx, count, start = 0; + unsigned idx, count; char *name; /* Output the scope definition. */ @@ -424,7 +493,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) ivl_scope_def_lineno(scope)); fprintf(vlog_out, "module %s", name); free(name); -// HERE: Still need to add port information. + emit_module_ports(scope); break; case IVL_SCT_FUNCTION: assert(indent != 0); @@ -432,7 +501,6 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) assert(ivl_scope_ports(scope) >= 2); /* The function return information is the zero port. */ emit_func_return(ivl_scope_port(scope, 0)); - start = 1; fprintf(vlog_out, " %s", ivl_scope_tname(scope)); if (is_auto) { fprintf(stderr, "%s:%u: vlog95 error: Automatic functions " @@ -470,35 +538,11 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) indent += indent_incr; /* Output the scope ports for this scope. */ - count = ivl_scope_ports(scope); - for (idx = start; idx < count; idx += 1) { - fprintf(vlog_out, "%*c", indent, ' '); - ivl_signal_t port = ivl_scope_port(scope, idx); - switch (ivl_signal_port(port)) { - case IVL_SIP_INPUT: - fprintf(vlog_out, "input"); - break; - case IVL_SIP_OUTPUT: - fprintf(vlog_out, "output"); - break; - case IVL_SIP_INOUT: - fprintf(vlog_out, "inout"); - break; - default: - fprintf(vlog_out, ""); - fprintf(stderr, "%s:%u: vlog95 error: Unknown port " - "direction (%d) for signal %s.\n", - ivl_signal_file(port), ivl_signal_lineno(port), - (int)ivl_signal_port(port), - ivl_signal_basename(port)); - vlog_errors += 1; - break; - } - fprintf(vlog_out, " %s;", ivl_signal_basename(port)); - emit_sig_file_line(port); - fprintf(vlog_out, " \n"); + if (sc_type == IVL_SCT_MODULE) { + emit_module_port_defs(scope); + } else { + emit_task_func_port_defs(scope); } - if (count) fprintf(vlog_out, "\n"); emit_scope_variables(scope); diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 9740fdbbb..b09c4cfaf 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -90,7 +90,7 @@ static void emit_stmt_lval_name(ivl_scope_t scope, ivl_lval_t lval, ivl_signal_t sig) { ivl_expr_t array_idx = ivl_lval_idx(lval); - emit_scope_module_path(scope, ivl_signal_scope(sig)); + emit_scope_call_path(scope, ivl_signal_scope(sig)); fprintf(vlog_out, "%s", ivl_signal_basename(sig)); if (array_idx) { int msb, lsb; @@ -184,7 +184,8 @@ static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) assert(width > 0); /* If there are no selects then just print the name. */ - if (width == ivl_signal_width(sig)) { + sel_expr = ivl_lval_part_off(lval); + if (! sel_expr && (width == ivl_signal_width(sig))) { emit_stmt_lval_name(scope, lval, sig); return; } @@ -192,7 +193,6 @@ static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) /* We have some kind of select. */ lsb = ivl_signal_lsb(sig); msb = ivl_signal_msb(sig); - sel_expr = ivl_lval_part_off(lval); sel_type = ivl_lval_sel_type(lval); assert(sel_expr); /* A bit select. */ @@ -319,6 +319,80 @@ static unsigned is_delayed_or_event_assign(ivl_scope_t scope, return 1; } +/* + * Icarus translated for(; ; ) into + * + * begin + * ; + * while () begin + * + * + * end + * end + * This routine looks for this pattern and turns it back into the + * appropriate for loop. + */ +static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt) +{ + unsigned wid; + ivl_statement_t assign, while_lp, while_blk, body, incr_assign; + + /* We must have two block elements. */ + if (ivl_stmt_block_count(stmt) != 2) return 0; + /* The first must be an assign. */ + assign = ivl_stmt_block_stmt(stmt, 0); + if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0; + /* The second must be a while. */ + while_lp = ivl_stmt_block_stmt(stmt, 1); + if (ivl_statement_type(while_lp) != IVL_ST_WHILE) return 0; + /* The while statement must be a block. */ + while_blk = ivl_stmt_sub_stmt(while_lp); + if (ivl_statement_type(while_blk) != IVL_ST_BLOCK) return 0; + /* It must not be a named block. */ + if (ivl_stmt_block_scope(while_blk)) return 0; + /* It must have two elements. */ + if (ivl_stmt_block_count(while_blk) != 2) return 0; + /* The first block element (the body) can be anything. */ + body = ivl_stmt_block_stmt(while_blk, 0); + /* The second block element must be the increment assign. */ + incr_assign = ivl_stmt_block_stmt(while_blk, 1); + if (ivl_statement_type(incr_assign) != IVL_ST_ASSIGN) return 0; + /* And finally the for statements must have the same line number + * as the block. */ + if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) || + (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_lp)) || + (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_blk)) || + (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(incr_assign))) { + return 0; + } + + /* The pattern matched so generate the appropriate code. */ + fprintf(vlog_out, "%*cfor(", get_indent(), ' '); + /* Emit the initialization statement. */ +// HERE: Do we need to calculate the width? The compiler should have already +// done this for us. + wid = emit_stmt_lval(scope, assign); + fprintf(vlog_out, " = "); + emit_expr(scope, ivl_stmt_rval(assign), wid); + fprintf(vlog_out, "; "); + /* Emit the condition. */ + emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0); + fprintf(vlog_out, "; "); + /* Emit in increment statement. */ +// HERE: Do we need to calculate the width? The compiler should have already +// done this for us. + wid = emit_stmt_lval(scope, incr_assign); + fprintf(vlog_out, " = "); + emit_expr(scope, ivl_stmt_rval(incr_assign), wid); + fprintf(vlog_out, ")"); + emit_stmt_file_line(stmt); + /* Now emit the body. */ + single_indent = 1; + emit_stmt(scope, body); + + return 1; +} + /* * Icarus translated = repeat() into * begin @@ -1001,6 +1075,7 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) emit_stmt_block_named(scope, stmt); } else { if (is_delayed_or_event_assign(scope, stmt)) break; + if (is_for_loop(scope, stmt)) break; if (is_repeat_event_assign(scope, stmt)) break; if (is_wait(scope, stmt)) break; if (is_utask_call_with_args(scope, stmt)) break; diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index bdca9b6a8..97c832150 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -77,6 +77,7 @@ extern void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width, int msb, int lsb); 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_call_path(ivl_scope_t scope, ivl_scope_t call_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);