diff --git a/tgt-vlog95/Makefile.in b/tgt-vlog95/Makefile.in index e1108ace9..c53e7ef9c 100644 --- a/tgt-vlog95/Makefile.in +++ b/tgt-vlog95/Makefile.in @@ -44,7 +44,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = vlog95.o expr.o misc.o scope.o stmt.o +O = vlog95.o event.o expr.o misc.o scope.o stmt.o all: dep vlog95.tgt diff --git a/tgt-vlog95/event.c b/tgt-vlog95/event.c new file mode 100644 index 000000000..d125386ba --- /dev/null +++ b/tgt-vlog95/event.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +# include +# include +# include "config.h" +# include "vlog95_priv.h" + +void emit_event(ivl_scope_t scope, ivl_statement_t stmt) +{ + unsigned eidx, nevents, first = 1; + + nevents = ivl_stmt_nevent(stmt); + for (eidx = 0; eidx < nevents; eidx += 1) { + unsigned idx, count, had_edge = 0; + ivl_event_t event = ivl_stmt_events(stmt, eidx); + + /* Check for any edge events. */ + count = ivl_event_nany(event); + if (count) had_edge = 1; + for (idx = 0; idx < count; idx += 1) { + if (first) first = 0; + else fprintf(vlog_out, " or "); + emit_name_of_nexus(ivl_event_any(event, idx)); + } + + /* Check for positive edge events. */ + count = ivl_event_npos(event); + if (count) had_edge = 1; + for (idx = 0; idx < count; idx += 1) { + if (first) first = 0; + else fprintf(vlog_out, " or "); + fprintf(vlog_out, "posedge "); + emit_name_of_nexus(ivl_event_pos(event, idx)); + } + + /* Check for negative edge events. */ + count = ivl_event_nneg(event); + if (count) had_edge = 1; + for (idx = 0; idx < count; idx += 1) { + if (first) first = 0; + else fprintf(vlog_out, " or "); + fprintf(vlog_out, "negedge "); + emit_name_of_nexus(ivl_event_neg(event, idx)); + } + + /* We have a named event if there were no edge events. */ + if (!had_edge) { + ivl_scope_t ev_scope = ivl_event_scope(event); + 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 0f201b080..2d7be3884 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -14,11 +14,6 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * - * This is the vlog95 target module. It generates a 1364-1995 compliant - * netlist from the input netlist. The generated netlist is expected to - * be simulation equivalent to the original. */ # include "config.h" @@ -153,52 +148,63 @@ static void emit_expr_number(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) * represented as an integer. We can trim any matching MSB bits * to make it fit. We do not support undefined bits. */ if (ivl_expr_signed(expr)) { - unsigned trim_wid = nbits - 1; - const char msb = bits[trim_wid]; - for (/* none */; trim_wid > 0; trim_wid -= 1) { - if (msb != bits[trim_wid]) { - trim_wid += 1; + int rtype; + int32_t value = get_int32_from_number(expr, &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Signed number is " + "greater than 32 bits (%u) and cannot be " + "safely represented.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr), + rtype); + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Signed number has " + "an undefined bit and cannot be " + "represented.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + fprintf(vlog_out, "%"PRId32, value); + /* An unsigned number is represented in hex if all the bits are + * defined and it is more than a single bit otherwise it is + * represented in binary form to preserve all the information. */ + } else { + int idx; + unsigned has_undef = 0; + for (idx = (int)nbits -1; idx >= 0; idx -= 1) { + if ((bits[idx] != '0') && (bits[idx] != '1')) { + has_undef = 1; break; } } - trim_wid += 1; - if (trim_wid > 32U) { - fprintf(vlog_out, ""); - fprintf(stderr, "%s:%u: vlog95 error: Signed number is " - "greater than 32 bits (%u) and cannot be safely " - "represented.\n", - ivl_expr_file(expr), ivl_expr_lineno(expr), trim_wid); - vlog_errors += 1; - return; + if (has_undef || (nbits < 2)) { + fprintf(vlog_out, "%u'b", nbits); + for (idx = (int)nbits-1; idx >= 0; idx -= 1) { + fprintf(vlog_out, "%c", bits[idx]); + } } else { - unsigned idx; - int32_t value = 0; - for (idx = 0; idx < trim_wid; idx += 1) { - if (bits[idx] == '1') value |= 1U << idx; - else if (bits[idx] != '0') { - fprintf(vlog_out, ""); - fprintf(stderr, "%s:%u: vlog95 error: Signed " - "number has an undefined bit " - "and cannot be represented.\n", - ivl_expr_file(expr), - ivl_expr_lineno(expr)); - vlog_errors += 1; - return; + int start = 4*(nbits/4); + unsigned result = 0; + fprintf(vlog_out, "%u'h", nbits); + /* The first digit may not be a full hex digit. */ + if (start < nbits) { + for (idx = start; idx < nbits; idx += 1) { + if (bits[idx] == '1') result |= 1U << (idx%4); } + fprintf(vlog_out, "%1x", result); } - /* Sign extend as needed. */ - if (msb == '1' && trim_wid < 32U) { - value |= ~((1U << trim_wid) - 1U); + /* Now print the full hex digits. */ + for (idx = start-1; idx >= 0; idx -= 4) { + result = 0; + if (bits[idx] == '1') result |= 0x8; + if (bits[idx-1] == '1') result |= 0x4; + if (bits[idx-2] == '1') result |= 0x2; + if (bits[idx-3] == '1') result |= 0x1; + fprintf(vlog_out, "%1x", result); } - fprintf(vlog_out, "%"PRId32, value); - } - /* An unsigned number is always represented in binary form to - * preserve all the information. */ - } else { - int idx; - fprintf(vlog_out, "%u'b", nbits); - for (idx = (int)nbits-1; idx >= 0; idx -= 1) { - fprintf(vlog_out, "%c", bits[idx]); } } } @@ -210,12 +216,29 @@ static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { - if (ivl_expr_oper2(expr)) { - assert(0); -// HERE: Not finished. + ivl_expr_t sel_expr = ivl_expr_oper2(expr); + ivl_expr_t sub_expr = ivl_expr_oper1(expr); + if (sel_expr) { + ivl_signal_t sig = ivl_expr_signal(sub_expr); + int msb = 1; + int lsb = 0; + unsigned width = ivl_expr_width(expr); + assert(width > 0); + if (ivl_expr_type(sub_expr) == IVL_EX_SIGNAL) { + msb = ivl_signal_msb(sig); + lsb = ivl_signal_lsb(sig); + } + emit_expr(scope, sub_expr, wid); + if (width == 1) { + fprintf(vlog_out, "["); + emit_scaled_expr(scope, sel_expr, msb, lsb); + fprintf(vlog_out, "]"); + } else { + emit_scaled_range(scope, sel_expr, width, msb, lsb); + } } else { // HERE: Should this sign extend if the expression is signed? - emit_expr(scope, ivl_expr_oper1(expr), wid); + emit_expr(scope, sub_expr, wid); } } @@ -231,6 +254,8 @@ static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, const char* name) count -= 1; for (idx = 0; idx < count; idx += 1) { emit_expr(scope, ivl_expr_parm(expr, idx), 0); +// HERE: Do we need to support a NULL argument for the system functions? +// See what was done system tasks. fprintf(vlog_out, ", "); } emit_expr(scope, ivl_expr_parm(expr, count), 0); @@ -246,9 +271,15 @@ 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); -// HERE: Need support for an array select and an out of scope reference. -// Also pad a signed value to the given width. + 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, "]"); + } } static void emit_expr_ternary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) @@ -265,6 +296,8 @@ static void emit_expr_ternary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_ufunc(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_scope_t ufunc_def = ivl_expr_def(expr); +// HERE: I think we need to also consider the scope of the func relative +// to the calling scope to get the correct name. emit_expr_func(scope, expr, ivl_scope_tname(ufunc_def)); } diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 855f6914f..87cddaa7f 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -14,24 +14,23 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * - * This is the vlog95 target module. It generates a 1364-1995 compliant - * netlist from the input netlist. The generated netlist is expected to - * be simulation equivalent to the original. */ # include +# include # include "config.h" # include "vlog95_priv.h" # include "ivl_alloc.h" +/* + * Emit a constant delay that has been rescaled to the given scopes timescale. + */ void emit_scaled_delay(ivl_scope_t scope, uint64_t delay) { int scale = ivl_scope_time_units(scope) - sim_precision; int pre = ivl_scope_time_units(scope) - ivl_scope_time_precision(scope); char *frac; - uint8_t real_dly = 0; + unsigned real_dly = 0; assert(scale >= 0); assert(pre >= 0); assert(scale >= pre); @@ -50,9 +49,577 @@ void emit_scaled_delay(ivl_scope_t scope, uint64_t delay) } delay /= 10; } +// HERE: If there is no frac then this has to fit into 31 bits like any +// other integer. fprintf(vlog_out, "%"PRIu64, delay); if (real_dly) { fprintf(vlog_out, ".%s", frac); } free(frac); } + +/* + * 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) +{ + assert(! ivl_expr_signed(expr)); + if (ivl_expr_type(expr) == IVL_EX_NUMBER) { + int rtype; + uint64_t value = get_uint64_from_number(expr, &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Time value is " + "greater than 64 bits (%u) and cannot be " + "safely represented.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr), + rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Time value has an " + "undefined bit and cannot be represented.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + emit_scaled_delay(scope, value); + } else { + int exp = ivl_scope_time_units(scope) - sim_precision; + uint64_t scale = 1; + assert(exp >= 0); + if (exp == 0) emit_expr(scope, expr, 0); + else { + uint64_t scale_val; + int rtype; + /* This is as easy as removing the multiple that was + * added to scale the value to the simulation time, + * but we need to verify that the scaling value is + * correct first. */ + if ((ivl_expr_type(expr) != IVL_EX_BINARY) || + (ivl_expr_opcode(expr) != '*') || + (ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_NUMBER)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Variable time " + "expression/value cannot be scaled.\n ", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + scale_val = get_uint64_from_number(ivl_expr_oper2(expr), + &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Variable time " + "expression/value scale coefficient " + "was greater then 64 bits (%d).\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), + rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Variable time " + "expression/value scale coefficient " + "has an undefined bit.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + while (exp > 0) { + scale *= 10; + exp -= 1; + } + if (scale != scale_val) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Variable time " + "expression/value scale coefficient " + "did not match expected value " + "(%"PRIu64" != %"PRIu64").\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), + scale, scale_val); + vlog_errors += 1; + return; + } + emit_expr(scope, ivl_expr_oper1(expr), 0); + } + } +} + +void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width, + int msb, int lsb) +{ + if (msb >= lsb) { + if (ivl_expr_type(expr) == IVL_EX_NUMBER) { + int rtype; + int64_t value = get_int64_from_number(expr, &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled range is " + "greater than 64 bits (%u) and cannot " + "be safely represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled range " + "has an undefined bit and cannot be " + "represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + value += lsb; + fprintf(vlog_out, "[%"PRId64":%"PRId64"]", + value + (int64_t)(width - 1), value); + } else { + fprintf(vlog_out, "[:]"); + fprintf(stderr, "%s:%u: vlog95 error: Indexed part-selects " + "are not currently supported.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr)); + vlog_errors += 1; + } + } else { + if (ivl_expr_type(expr) == IVL_EX_NUMBER) { + int rtype; + int64_t value = get_int64_from_number(expr, &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value is " + "greater than 64 bits (%u) and cannot " + "be safely represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "has an undefined bit and cannot be " + "represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + value = (int64_t)lsb - value; + fprintf(vlog_out, "[%"PRId64":%"PRId64"]", + value - (int64_t)(width - 1), value); + } else { + fprintf(vlog_out, "[:]"); + fprintf(stderr, "%s:%u: vlog95 error: Indexed part-selects " + "are not currently supported.\n", + ivl_expr_file(expr), ivl_expr_lineno(expr)); + vlog_errors += 1; + } + } +} + +void emit_scaled_expr(ivl_scope_t scope, ivl_expr_t expr, int msb, int lsb) +{ + if (msb >= lsb) { + if (ivl_expr_type(expr) == IVL_EX_NUMBER) { + int rtype; + int64_t value = get_int64_from_number(expr, &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value is " + "greater than 64 bits (%u) and cannot " + "be safely represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "has an undefined bit and cannot be " + "represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + value += lsb; + fprintf(vlog_out, "%"PRId64, value); + } else { + int64_t scale_val; + int rtype; + /* This is as easy as removing the addition/subtraction + * that was added to scale the value to be zero based, + * but we need to verify that the scaling value is + * correct first. */ + if ((ivl_expr_type(expr) != IVL_EX_BINARY) || + ((ivl_expr_opcode(expr) != '+') && + (ivl_expr_opcode(expr) != '-')) || + (ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_NUMBER)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value cannot be scaled.\n ", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + scale_val = get_int64_from_number(ivl_expr_oper2(expr), + &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value scale coefficient " + "was greater then 64 bits (%d).\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), + rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value scale coefficient " + "has an undefined bit.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + if (ivl_expr_opcode(expr) == '+') scale_val *= -1; + if (lsb != scale_val) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value scale coefficient " + "did not match expected value " + "(%d != %"PRIu64").\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), + lsb, scale_val); + vlog_errors += 1; + return; + } + emit_expr(scope, ivl_expr_oper1(expr), 0); + } + } else { + if (ivl_expr_type(expr) == IVL_EX_NUMBER) { + int rtype; + int64_t value = get_int64_from_number(expr, &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value is " + "greater than 64 bits (%u) and cannot " + "be safely represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "has an undefined bit and cannot be " + "represented.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + value = (int64_t)lsb - value; + fprintf(vlog_out, "%"PRId64, value); + } else { + int64_t scale_val; + int rtype; + /* This is as easy as removing the addition/subtraction + * that was added to scale the value to be zero based, + * but we need to verify that the scaling value is + * correct first. */ + if ((ivl_expr_type(expr) != IVL_EX_BINARY) || + ((ivl_expr_opcode(expr) != '+') && + (ivl_expr_opcode(expr) != '-')) || + (ivl_expr_type(ivl_expr_oper1(expr)) != IVL_EX_NUMBER)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value cannot be scaled.\n ", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + scale_val = get_int64_from_number(ivl_expr_oper1(expr), + &rtype); + if (rtype > 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value scale coefficient " + "was greater then 64 bits (%d).\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), + rtype); + vlog_errors += 1; + return; + } + if (rtype < 0) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value scale coefficient " + "has an undefined bit.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + return; + } + if (ivl_expr_opcode(expr) == '+') scale_val *= -1; + if (lsb != scale_val) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Scaled value " + "expression/value scale coefficient " + "did not match expected value " + "(%d != %"PRIu64").\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr), + lsb, scale_val); + vlog_errors += 1; + return; + } + emit_expr(scope, ivl_expr_oper2(expr), 0); + } + } +} + +// HERE: Do we need the scope to know which name to use? +void emit_name_of_nexus(ivl_nexus_t nex) +{ + fprintf(vlog_out, ""); +} + +/* + * This function traverses the scope tree looking for the enclosing module + * scope. When it is found the module scope is returned. + */ +ivl_scope_t get_module_scope(ivl_scope_t scope) +{ + + while (ivl_scope_type(scope) != IVL_SCT_MODULE) { + ivl_scope_t pscope = ivl_scope_parent(scope); + assert(pscope); + scope = pscope; + } + return scope; +} + +/* + * This routine emits the appropriate string to call the call_scope from the + * given scope. If the module scopes for the two match then do nothing. If + * the module scopes are different, but the call_scope begins with the + * entire module scope of scope then we can trim the top off the call_scope + * (it is a sub-scope of the module that contains scope). Otherwise we need + * to print the entire path of call_scope. + */ +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. */ + 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); + } +} + +/* + * 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 + * base name of the call_scope. If the module scopes are different, but the + * call_scope begins with the entire module scope of scope then we can trim + * the top off the call_scope (it is a sub-scope of the module that contains + * scope). Otherwise we need to print the entire path of call_scope. + */ +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 { + /* 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_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); + } +} + +/* + * Extract an uint64_t value from the given number expression. If the result + * type is 0 then the returned value is valid. If it is positive then the + * value was too large and if it is negative then the value had undefined + * bits. + */ +uint64_t get_uint64_from_number(ivl_expr_t expr, int *result_type) +{ + unsigned nbits = ivl_expr_width(expr); + unsigned trim_wid = nbits - 1; + const char *bits = ivl_expr_bits(expr); + unsigned idx; + uint64_t value = 0; + assert(ivl_expr_type(expr) == IVL_EX_NUMBER); + assert(! ivl_expr_signed(expr)); + /* Trim any '0' bits from the MSB. */ + for (/* none */; trim_wid > 0; trim_wid -= 1) { + if ('0' != bits[trim_wid]) { + trim_wid += 1; + break; + } + } + if (trim_wid < nbits) trim_wid += 1; + /* Check to see if the value is too large. */ + if (trim_wid > 64U) { + *result_type = trim_wid; + return 0; + } + /* Now build the value from the bits. */ + for (idx = 0; idx < trim_wid; idx += 1) { + if (bits[idx] == '1') value |= (uint64_t)1 << idx; + else if (bits[idx] != '0') { + *result_type = -1; + return 0; + } + } + *result_type = 0; + return value; +} + +/* + * Extract an int64_t value from the given number expression. If the result + * type is 0 then the returned value is valid. If it is positive then the + * value was too large and if it is negative then the value had undefined + * bits. + */ +int64_t get_int64_from_number(ivl_expr_t expr, int *result_type) +{ + unsigned is_signed = ivl_expr_signed(expr); + unsigned nbits = ivl_expr_width(expr); + unsigned trim_wid = nbits - 1; + const char *bits = ivl_expr_bits(expr); + const char msb = is_signed ? bits[trim_wid] : '0'; + unsigned idx; + int64_t value = 0; + assert(ivl_expr_type(expr) == IVL_EX_NUMBER); + /* Trim any duplicate bits from the MSB. */ + for (/* none */; trim_wid > 0; trim_wid -= 1) { + if (msb != bits[trim_wid]) { + trim_wid += 1; + break; + } + } + if (trim_wid < nbits) trim_wid += 1; + /* Check to see if the value is too large. */ + if (trim_wid > 64U) { + *result_type = trim_wid; + return 0; + } + /* Now build the value from the bits. */ + for (idx = 0; idx < trim_wid; idx += 1) { + if (bits[idx] == '1') value |= (int64_t)1 << idx; + else if (bits[idx] != '0') { + *result_type = -1; + return 0; + } + } + /* Sign extend as needed. */ + if (is_signed && (msb == '1') && (trim_wid < 64U)) { + value |= ~(((int64_t)1 << trim_wid) - (int64_t)1); + } + *result_type = 0; + return value; +} + +/* + * Extract an int32_t value from the given number expression. If the result + * type is 0 then the returned value is valid. If it is positive then the + * value was too large and if it is negative then the value had undefined + * bits. + */ +int32_t get_int32_from_number(ivl_expr_t expr, int *result_type) +{ + unsigned is_signed = ivl_expr_signed(expr); + unsigned nbits = ivl_expr_width(expr); + unsigned trim_wid = nbits - 1; + const char *bits = ivl_expr_bits(expr); + const char msb = is_signed ? bits[trim_wid] : '0'; + unsigned idx; + int32_t value = 0; + assert(ivl_expr_type(expr) == IVL_EX_NUMBER); + /* Trim any duplicate bits from the MSB. */ + for (/* none */; trim_wid > 0; trim_wid -= 1) { + if (msb != bits[trim_wid]) { + trim_wid += 1; + break; + } + } + if (trim_wid < nbits) trim_wid += 1; + /* Check to see if the value is too large. */ + if (trim_wid > 32U) { + *result_type = trim_wid; + return 0; + } + /* Now build the value from the bits. */ + for (idx = 0; idx < trim_wid; idx += 1) { + if (bits[idx] == '1') value |= (int32_t)1 << idx; + else if (bits[idx] != '0') { + *result_type = -1; + return 0; + } + } + /* Sign extend as needed. */ + if (is_signed && (msb == '1') && (trim_wid < 32U)) { + value |= ~(((int32_t)1 << trim_wid) - (int32_t)1); + } + *result_type = 0; + return value; +} diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 63475a8f4..6d92d5991 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -14,11 +14,6 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * - * This is the vlog95 target module. It generates a 1364-1995 compliant - * netlist from the input netlist. The generated netlist is expected to - * be simulation equivalent to the original. */ # include @@ -200,6 +195,208 @@ static char *get_mangled_name(ivl_scope_t scope, unsigned root) return name; } +static void emit_gate_drive(ivl_net_logic_t nlogic, ivl_drive_t drive) +{ + switch (drive) { + case IVL_DR_HiZ: + fprintf(vlog_out, "highz"); + break; + case IVL_DR_WEAK: + fprintf(vlog_out, "weak"); + break; + case IVL_DR_PULL: + fprintf(vlog_out, "pull"); + break; + case IVL_DR_STRONG: + fprintf(vlog_out, "strong"); + break; + case IVL_DR_SUPPLY: + fprintf(vlog_out, "supply"); + break; + default: + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate " + "drive (%d)\n", ivl_logic_file(nlogic), + ivl_logic_lineno(nlogic), (int)drive); + vlog_errors += 1; + break; + } +} + +static void emit_gate_strength(ivl_net_logic_t nlogic) +{ + ivl_drive_t drive1 = ivl_logic_drive1(nlogic); + ivl_drive_t drive0 = ivl_logic_drive0(nlogic); + if ((drive1 != IVL_DR_STRONG) || (drive0 != IVL_DR_STRONG)) { + fprintf(vlog_out, " ("); + emit_gate_drive(nlogic, drive1); + fprintf(vlog_out, "1, "); + emit_gate_drive(nlogic, drive0); + fprintf(vlog_out, "0)"); + } +} + +static void emit_gate_delay(ivl_scope_t scope, ivl_net_logic_t nlogic, + unsigned dly_count) +{ + ivl_expr_t rise = ivl_logic_delay(nlogic, 0); + ivl_expr_t fall = ivl_logic_delay(nlogic, 1); + ivl_expr_t decay = ivl_logic_delay(nlogic, 2); + assert((dly_count >= 2) && (dly_count <= 3)); + + /* No delays. */ + if (! rise) { + assert(! fall); + assert(! decay); + return; + } + /* 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); + return; + } + /* If we have a gate that only supports two delays then print them. */ + if (dly_count == 2) { + fprintf(vlog_out, " #("); + emit_scaled_delayx(scope, rise); + fprintf(vlog_out, ","); + emit_scaled_delayx(scope, fall); + fprintf(vlog_out, ")"); + return; + } + + /* What's left is a gate that supports three delays. */ + fprintf(vlog_out, " #("); + emit_scaled_delayx(scope, rise); + fprintf(vlog_out, ","); + emit_scaled_delayx(scope, fall); + if (decay) { + fprintf(vlog_out, ","); + emit_scaled_delayx(scope, decay); + } + fprintf(vlog_out, ")"); +} + +static void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) +{ + unsigned idx, count, dly_count; + fprintf(vlog_out, "%*c", indent, ' '); + switch (ivl_logic_type(nlogic)) { + case IVL_LO_AND: + fprintf(vlog_out, "and"); + dly_count = 2; + break; + case IVL_LO_BUF: + fprintf(vlog_out, "buf"); + dly_count = 2; + break; + case IVL_LO_BUFIF0: + fprintf(vlog_out, "bufif0"); + dly_count = 3; + break; + case IVL_LO_BUFIF1: + fprintf(vlog_out, "bufif1"); + dly_count = 3; + break; + case IVL_LO_CMOS: + fprintf(vlog_out, "cmos"); + dly_count = 3; + break; + case IVL_LO_NAND: + fprintf(vlog_out, "nand"); + dly_count = 2; + break; + case IVL_LO_NMOS: + fprintf(vlog_out, "nmos"); + dly_count = 3; + break; + case IVL_LO_NOR: + fprintf(vlog_out, "nor"); + dly_count = 2; + break; + case IVL_LO_NOT: + fprintf(vlog_out, "not"); + dly_count = 2; + break; + case IVL_LO_NOTIF0: + fprintf(vlog_out, "notif0"); + dly_count = 3; + break; + case IVL_LO_NOTIF1: + fprintf(vlog_out, "notif1"); + dly_count = 3; + break; + case IVL_LO_OR: + fprintf(vlog_out, "or"); + dly_count = 2; + break; + case IVL_LO_PMOS: + fprintf(vlog_out, "pmos"); + dly_count = 3; + break; + case IVL_LO_PULLDOWN: + fprintf(vlog_out, "pulldown"); + dly_count = 0; + break; + case IVL_LO_PULLUP: + fprintf(vlog_out, "pullup"); + dly_count = 0; + break; + case IVL_LO_RCMOS: + fprintf(vlog_out, "rcmos"); + dly_count = 3; + break; + case IVL_LO_RNMOS: + fprintf(vlog_out, "rnmos"); + dly_count = 3; + break; + case IVL_LO_RPMOS: + fprintf(vlog_out, "rpmos"); + dly_count = 3; + break; + case IVL_LO_XNOR: + fprintf(vlog_out, "xnor"); + dly_count = 2; + break; + case IVL_LO_XOR: + fprintf(vlog_out, "xor"); + dly_count = 2; + break; + default: +// HERE: Missing support for BUFT, BUFZ, UDP. + fprintf(vlog_out, "("); + fprintf(stderr, "%s:%u: vlog95 error: Unsupported logic type " + "(%d) named: %s.\n", ivl_logic_file(nlogic), + ivl_logic_lineno(nlogic), ivl_logic_type(nlogic), + ivl_logic_basename(nlogic)); + vlog_errors += 1; + dly_count = 0; + break; + } + emit_gate_strength(nlogic); + if (dly_count) emit_gate_delay(scope, nlogic, dly_count); + fprintf(vlog_out, " %s(", ivl_logic_basename(nlogic)); + count = ivl_logic_pins(nlogic); + count -= 1; + for (idx = 0; idx < count; idx += 1) { + emit_name_of_nexus(ivl_logic_pin(nlogic, idx)); + fprintf(vlog_out, ", "); + } + emit_name_of_nexus(ivl_logic_pin(nlogic, count)); + fprintf(vlog_out, ");\n"); +} + +/* + * This function is called for each process in the design so that we + * can extract the processes for the given scope. + */ +static int find_process(ivl_process_t proc, ivl_scope_t scope) +{ + if (scope == ivl_process_scope(proc)) emit_process(scope, proc); + return 0; +} + /* * 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 @@ -377,8 +574,18 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) } } -// HERE: Need to find and print any continuous assignments/logic cells or -// initial/always blocks. +// HERE: Need to find and print any continuous assignments. + + if (sc_type == IVL_SCT_MODULE) { + /* Output any logic devices. */ + count = ivl_scope_logs(scope); + for (idx = 0; idx < count; idx += 1) { + emit_logic(scope, ivl_scope_log(scope, idx)); + } + + /* Output the initial/always blocks for this module. */ + ivl_design_process(design, (ivl_process_f)find_process, scope); + } /* Output the function/task body. */ if (sc_type == IVL_SCT_TASK || sc_type == IVL_SCT_FUNCTION) { diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index e59ffd21b..366a60550 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -14,11 +14,6 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * - * This is the vlog95 target module. It generates a 1364-1995 compliant - * netlist from the input netlist. The generated netlist is expected to - * be simulation equivalent to the original. */ # include "config.h" @@ -50,10 +45,24 @@ static void emit_stmt_inter_delay(ivl_scope_t scope, ivl_statement_t stmt) { ivl_expr_t delay = ivl_stmt_delay_expr(stmt); unsigned nevents = ivl_stmt_nevent(stmt); -// HERE: No support for event based delays/ if (nevents) { + ivl_expr_t count = ivl_stmt_cond_expr(stmt); + if (count) { + if (ivl_expr_type(count) == IVL_EX_ULONG) { + unsigned long repeat = ivl_expr_uvalue(count); + if (repeat != 1) { + fprintf(vlog_out, "repeat(%lu) ", repeat); + } + } else { + fprintf(vlog_out, "repeat("); + emit_expr(scope, count, 0); + fprintf(vlog_out, ") "); + } + } assert(delay == 0); - assert(0); + fprintf(vlog_out, "@("); + emit_event(scope, stmt); + fprintf(vlog_out, ") "); } if (delay) { assert(nevents == 0); @@ -63,18 +72,44 @@ static void emit_stmt_inter_delay(ivl_scope_t scope, ivl_statement_t stmt) } } -static void emit_stmt_lval_piece(ivl_lval_t lval) +static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) { + ivl_expr_t expr; ivl_signal_t sig = ivl_lval_sig(lval); + unsigned width = ivl_lval_width(lval); + int msb, lsb; + assert(width > 0); + emit_scope_module_path(scope, ivl_signal_scope(sig)); fprintf(vlog_out, "%s", ivl_signal_basename(sig)); -// HERE: Need support for bit, part or array word. -// ivl_lval_width and ivl_lval_part_off is used for part select. -// If the lval width is less than the signal width this is a zero based PS. -// ivl_lval_idx is used for an array select. Handle non-zero based and -// different endian accesses. + /* Check to see if we have an array word access. */ + expr = ivl_lval_idx(lval); + if (expr) { + assert(ivl_signal_dimensions(sig)); + fprintf(vlog_out, "["); + /* For an array the LSB/MSB order is not important. They are + * always accessed from base counting up. */ + lsb = ivl_signal_array_base(sig); + msb = lsb + ivl_signal_array_count(sig) - 1; + emit_scaled_expr(scope, expr, msb, lsb); + fprintf(vlog_out, "]"); + } + + /* If there are no selects then just return. */ + if (width == ivl_signal_width(sig)) return; + + /* We have some kind of select. */ + lsb = ivl_signal_lsb(sig); + msb = ivl_signal_msb(sig); + if (width == 1) { + fprintf(vlog_out, "["); + emit_scaled_expr(scope, ivl_lval_part_off(lval), msb, lsb); + fprintf(vlog_out, "]"); + } else { + emit_scaled_range(scope, ivl_lval_part_off(lval), width, msb, lsb); + } } -static unsigned emit_stmt_lval(ivl_statement_t stmt) +static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt) { unsigned idx; unsigned count = ivl_stmt_lvals(stmt); @@ -83,29 +118,90 @@ static unsigned emit_stmt_lval(ivl_statement_t stmt) ivl_lval_t lval = ivl_stmt_lval(stmt, 0); wid += ivl_lval_width(lval); fprintf(vlog_out, "{"); - emit_stmt_lval_piece(lval); + emit_stmt_lval_piece(scope, lval); for (idx = 1; idx < count; idx += 1) { fprintf(vlog_out, ", "); lval = ivl_stmt_lval(stmt, idx); wid += ivl_lval_width(lval); - emit_stmt_lval_piece(lval); + emit_stmt_lval_piece(scope, lval); } fprintf(vlog_out, "}"); } else { ivl_lval_t lval = ivl_stmt_lval(stmt, 0); wid = ivl_lval_width(lval); - emit_stmt_lval_piece(lval); + emit_stmt_lval_piece(scope, lval); } return wid; } +/* + * 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) +{ + unsigned wid; + ivl_statement_t assign, delay, delayed_assign; + ivl_lval_t lval; + ivl_expr_t rval; + ivl_signal_t lsig, rsig; + + /* 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 delayx. */ + delay = ivl_stmt_block_stmt(stmt, 1); + if (ivl_statement_type(delay) != IVL_ST_DELAYX) 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; + /* The L-value must be a single signal. */ + if (ivl_stmt_lvals(assign) != 1) return 0; + lval = ivl_stmt_lval(assign, 0); + /* It must not have an array select. */ + if (ivl_lval_idx(lval)) return 0; + /* It must not have a non-zero base. */ + if (ivl_lval_part_off(lval)) return 0; + lsig = ivl_lval_sig(lval); + /* It must not be part of the signal. */ + if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0; + /* The R-value must be a single signal. */ + rval = ivl_stmt_rval(delayed_assign); + if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0; + /* It must not be an array word. */ + if (ivl_expr_oper1(rval)) return 0; + rsig = ivl_expr_signal(rval); + /* And finally the two signals must be the same. */ + if (lsig != rsig) return 0; + + /* The pattern matched so generate the appropriate code. */ + fprintf(vlog_out, "%*c", get_indent(), ' '); +// 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, " "); + emit_expr(scope, ivl_stmt_rval(assign), wid); + fprintf(vlog_out, ";\n"); + + return 1; +} + static void emit_stmt_assign(ivl_scope_t scope, ivl_statement_t stmt) { unsigned wid; fprintf(vlog_out, "%*c", get_indent(), ' '); // HERE: Do we need to calculate the width? The compiler should have already // done this for us. - wid = emit_stmt_lval(stmt); + wid = emit_stmt_lval(scope, stmt); fprintf(vlog_out, " = "); emit_expr(scope, ivl_stmt_rval(stmt), wid); fprintf(vlog_out, ";\n"); @@ -117,21 +213,21 @@ static void emit_stmt_assign_nb(ivl_scope_t scope, ivl_statement_t stmt) fprintf(vlog_out, "%*c", get_indent(), ' '); // HERE: Do we need to calculate the width? The compiler should have already // done this for us. - wid = emit_stmt_lval(stmt); + wid = emit_stmt_lval(scope, stmt); fprintf(vlog_out, " <= "); emit_stmt_inter_delay(scope, stmt); emit_expr(scope, ivl_stmt_rval(stmt), wid); fprintf(vlog_out, ";\n"); } -void emit_stmt_block(ivl_scope_t scope, ivl_statement_t stmt) +static void emit_stmt_block(ivl_scope_t scope, ivl_statement_t stmt) { fprintf(vlog_out, "%*cbegin\n", get_indent(), ' '); emit_stmt_block_body(scope, stmt); fprintf(vlog_out, "%*cend\n", get_indent(), ' '); } -void emit_stmt_block_named(ivl_scope_t scope, ivl_statement_t stmt) +static void emit_stmt_block_named(ivl_scope_t scope, ivl_statement_t stmt) { ivl_scope_t my_scope = ivl_stmt_block_scope(stmt); fprintf(vlog_out, "%*cbegin: %s\n", get_indent(), ' ', @@ -194,7 +290,7 @@ static void emit_stmt_cassign(ivl_scope_t scope, ivl_statement_t stmt) fprintf(vlog_out, "%*cassign ", get_indent(), ' '); // HERE: Do we need to calculate the width? The compiler should have already // done this for us. - wid = emit_stmt_lval(stmt); + wid = emit_stmt_lval(scope, stmt); fprintf(vlog_out, " = "); emit_expr(scope, ivl_stmt_rval(stmt), wid); fprintf(vlog_out, ";\n"); @@ -221,7 +317,7 @@ static void emit_stmt_condit(ivl_scope_t scope, ivl_statement_t stmt) static void emit_stmt_deassign(ivl_scope_t scope, ivl_statement_t stmt) { fprintf(vlog_out, "%*cdeassign ", get_indent(), ' '); - (void) emit_stmt_lval(stmt); + (void) emit_stmt_lval(scope, stmt); fprintf(vlog_out, ";\n"); } @@ -233,13 +329,29 @@ static void emit_stmt_delay(ivl_scope_t scope, ivl_statement_t stmt) emit_stmt(scope, ivl_stmt_sub_stmt(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)); + single_indent = 1; + emit_stmt(scope, ivl_stmt_sub_stmt(stmt)); +} + +static void emit_stmt_disable(ivl_scope_t scope, ivl_statement_t stmt) +{ + ivl_scope_t disable_scope = ivl_stmt_call(stmt); + fprintf(vlog_out, "%*cdisable ", get_indent(), ' '); + emit_scope_path(scope, disable_scope); + fprintf(vlog_out, ";\n"); +} + static void emit_stmt_force(ivl_scope_t scope, ivl_statement_t stmt) { unsigned wid; fprintf(vlog_out, "%*cforce ", get_indent(), ' '); // HERE: Do we need to calculate the width? The compiler should have already // done this for us. - wid = emit_stmt_lval(stmt); + wid = emit_stmt_lval(scope, stmt); fprintf(vlog_out, " = "); emit_expr(scope, ivl_stmt_rval(stmt), wid); fprintf(vlog_out, ";\n"); @@ -272,7 +384,7 @@ static void emit_stmt_fork_named(ivl_scope_t scope, ivl_statement_t stmt) static void emit_stmt_release(ivl_scope_t scope, ivl_statement_t stmt) { fprintf(vlog_out, "%*crelease ", get_indent(), ' '); - (void) emit_stmt_lval(stmt); + (void) emit_stmt_lval(scope, stmt); fprintf(vlog_out, ";\n"); } @@ -293,7 +405,8 @@ static void emit_stmt_stask(ivl_scope_t scope, ivl_statement_t stmt) fprintf(vlog_out, "("); count -= 1; for (idx = 0; idx < count; idx += 1) { - emit_expr(scope, ivl_stmt_parm(stmt, idx), 0); + ivl_expr_t expr = ivl_stmt_parm(stmt, idx); + if (expr) emit_expr(scope, expr, 0); fprintf(vlog_out, ", "); } emit_expr(scope, ivl_stmt_parm(stmt, count), 0); @@ -302,6 +415,37 @@ static void emit_stmt_stask(ivl_scope_t scope, ivl_statement_t stmt) fprintf(vlog_out, ";\n"); } +static void emit_stmt_trigger(ivl_scope_t scope, ivl_statement_t stmt) +{ + fprintf(vlog_out, "%*c-> ", get_indent(), ' '); + assert(ivl_stmt_nevent(stmt) == 1); + emit_event(scope, stmt); + fprintf(vlog_out, ";\n"); +} + +static void emit_stmt_utask(ivl_scope_t scope, ivl_statement_t stmt) +{ + ivl_scope_t task_scope = ivl_stmt_call(stmt); + fprintf(vlog_out, "%*c", get_indent(), ' '); + emit_scope_path(scope, task_scope); +// HERE: No support for the calling arguments. We need ivl_stmt_parm() and +// ivl_stmt_parm_count() like is used for the system tasks. This is +// the same basic issue we have with module instantiation. Maybe we +// can look for assignments to a task scope and assignments from a +// task scope after the call to handle input and output ports. inout +// is a bit harder. + fprintf(vlog_out, ";\n"); +} + +static void emit_stmt_wait(ivl_scope_t scope, ivl_statement_t stmt) +{ + fprintf(vlog_out, "%*c@(", get_indent(), ' '); + emit_event(scope, stmt); + fprintf(vlog_out, ")"); + single_indent = 1; + emit_stmt(scope, ivl_stmt_sub_stmt(stmt)); +} + static void emit_stmt_while(ivl_scope_t scope, ivl_statement_t stmt) { fprintf(vlog_out, "%*cwhile (", get_indent(), ' '); @@ -328,6 +472,7 @@ 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; emit_stmt_block(scope, stmt); } break; @@ -349,6 +494,12 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) case IVL_ST_DELAY: emit_stmt_delay(scope, stmt); break; + case IVL_ST_DELAYX: + emit_stmt_delayx(scope, stmt); + break; + case IVL_ST_DISABLE: + emit_stmt_disable(scope, stmt); + break; case IVL_ST_FORCE: emit_stmt_force(scope, stmt); break; @@ -371,6 +522,15 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) case IVL_ST_STASK: emit_stmt_stask(scope, stmt); break; + case IVL_ST_TRIGGER: + emit_stmt_trigger(scope, stmt); + break; + case IVL_ST_UTASK: + emit_stmt_utask(scope, stmt); + break; + case IVL_ST_WAIT: + emit_stmt_wait(scope, stmt); + break; case IVL_ST_WHILE: emit_stmt_while(scope, stmt); break; @@ -385,3 +545,25 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) break; } } + +void emit_process(ivl_scope_t scope, ivl_process_t proc) +{ + fprintf(vlog_out, "\n%*c", get_indent(), ' '); + switch (ivl_process_type(proc)) { + case IVL_PR_INITIAL: + fprintf(vlog_out, "initial"); + break; + case IVL_PR_ALWAYS: + fprintf(vlog_out, "always"); + break; + default: + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Unknown process type (%d).\n", + ivl_process_file(proc), ivl_process_lineno(proc), + (int)ivl_process_type(proc)); + vlog_errors+= 1; + break; + } + single_indent = 1; + emit_stmt(scope, ivl_process_stmt(proc)); +} diff --git a/tgt-vlog95/vlog95.c b/tgt-vlog95/vlog95.c index 8247b278d..26bb36e63 100644 --- a/tgt-vlog95/vlog95.c +++ b/tgt-vlog95/vlog95.c @@ -49,6 +49,8 @@ int sim_precision = 0; unsigned indent = 0; unsigned indent_incr = 2; +ivl_design_t design = 0; + int target_design(ivl_design_t des) { ivl_scope_t *roots; @@ -56,6 +58,8 @@ int target_design(ivl_design_t des) const char*path = ivl_design_flag(des, "-o"); assert(path); + design = des; + #ifdef HAVE_FOPEN64 vlog_out = fopen64(path, "w"); #else @@ -70,6 +74,8 @@ int target_design(ivl_design_t des) fprintf(vlog_out, " * 1364-1995 Verilog generated by Icarus Verilog " "VLOG95 Code Generator,\n"); fprintf(vlog_out, " * Version: " VERSION " (" VERSION_TAG ")\n"); + fprintf(vlog_out, " * Converted using %s delays.\n", + ivl_design_delay_sel(des)); fprintf(vlog_out, " */\n"); sim_precision = ivl_design_time_precision(des); diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 03588b160..077e897e8 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -16,11 +16,6 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * - * This is the vlog95 target module. It generates a 1364-1995 compliant - * netlist from the input netlist. The generated netlist is expected to - * be simulation equivalent to the original. */ # include "config.h" @@ -29,6 +24,11 @@ # include # include +/* + * The design we are emitting. + */ +extern ivl_design_t design; + /* * This is the file that the converted design is written to. */ @@ -51,24 +51,38 @@ extern unsigned indent; extern unsigned indent_incr; /* - * Emit the Verilog code for the given scope. + * Emit various Verilog types. */ +extern void emit_event(ivl_scope_t scope, ivl_statement_t stmt); +extern void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned width); +extern void emit_process(ivl_scope_t scope, ivl_process_t proc); extern int emit_scope(ivl_scope_t scope, ivl_scope_t parent); - -/* - * Emit a Verilog statement. - */ extern void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt); -/* - * Emit a Verilog expression. - */ -extern void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned width); +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_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, + unsigned width, int msb, int lsb); +extern void emit_scope_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_nexus_t nex); /* - * Emit a delay scaled to the current timescale (units and precision). + * Find the enclosing module scope. */ -extern void emit_scaled_delay(ivl_scope_t scope, uint64_t delay); +extern ivl_scope_t get_module_scope(ivl_scope_t scope); + +/* + * Get an int32_t/uint64_t from a number is possible. The return type is + * 0 for a valid value, negative for a number with undefined bits and + * positive it the value is too large. The positive value is the minimum + * number of bits required to represent the value. + */ +extern int32_t get_int32_from_number(ivl_expr_t expr, int *return_type); +extern int64_t get_int64_from_number(ivl_expr_t expr, int *return_type); +extern uint64_t get_uint64_from_number(ivl_expr_t expr, int *return_type); /* * Cleanup functions.