vlog95: Add partial support for CA selects, emit for loop and other fixes.
This patch adds support for emitting fixed CA selects (zero based variable bit and array selects also work), emitting a for statement as a single statement and fixes for numerous little bugs. It also adds the start of emitting module port information.
This commit is contained in:
parent
1e3af45335
commit
f13fabab71
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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, "<missing>");
|
||||
} else {
|
||||
fprintf(stderr, "?:?: vlog95 error: Could not emit "
|
||||
"nexus as a CA.\n");
|
||||
vlog_errors += 1;
|
||||
fprintf(vlog_out, "<missing>");
|
||||
}
|
||||
} 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, "<unknown>");
|
||||
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, "<missing>");
|
||||
}
|
||||
} 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, "<missing>:<missing>");
|
||||
} 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. */
|
||||
|
|
|
|||
|
|
@ -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, "<missing>");
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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, "<unknown>");
|
||||
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, "<unknown>");
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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(<assign>; <cond>; <incr_assign>) <body> into
|
||||
*
|
||||
* begin
|
||||
* <assign>;
|
||||
* while (<cond>) begin
|
||||
* <body>
|
||||
* <incr_assign>
|
||||
* 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 <var> = repeat(<count>) <event> <value> 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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue