diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 7e932762e..138adf510 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -21,6 +21,9 @@ # include "config.h" # include "vlog95_priv.h" +/* This variable lets a select know it is really a >>> operator. */ +static unsigned sign_extend = 0; + static unsigned emit_drive(ivl_drive_t drive) { switch (drive) { @@ -232,6 +235,27 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm) static void emit_logic_as_ca(ivl_scope_t scope, ivl_net_logic_t nlogic); static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm); +/* For an undriven port look for the local signal to get the nexus name. */ +static void emit_nexus_port_signal(ivl_scope_t scope, ivl_nexus_t nex) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + 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)) assert(0); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (t_sig) { + if (scope != ivl_signal_scope(t_sig)) continue; + assert(! sig); + sig = t_sig; + } + } + /* There will not be a signal for an empty port. */ + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + else fprintf(vlog_out, "/* Empty */"); +} + void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) { unsigned idx, count = ivl_nexus_ptrs(nex); @@ -278,7 +302,12 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) emit_logic_as_ca(scope, net_logic); } else if (sig) { emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); - } else assert(0); + /* If there is no driver then look for a single signal that is + * driven by this nexus that has the correct scope. This is needed + * to translate top level ports. */ + } else { + emit_nexus_port_signal(scope, nex); + } } void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) @@ -542,22 +571,47 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) int msb, lsb; ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0), &base, &array_word); + + if (sign_extend && !allow_signed) { + fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not " + "supported.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + } + // HERE: variable parameter select needs to be rebuilt. 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); + if (base) { + fprintf(vlog_out, " "); + if (sign_extend) fprintf(vlog_out, ">"); + fprintf(vlog_out, ">> %d)", base); + } + sign_extend = 0; return; } + + if (sign_extend) fprintf(vlog_out, "("); emit_id(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); + if (sign_extend) { + assert(base != lsb); + if (msb >= lsb) base += lsb; + else base = lsb - base; + fprintf(vlog_out, " >>> %d)", base); + sign_extend = 0; + return; + } + fprintf(vlog_out, "["); if (width == 1) { ivl_nexus_t sel = ivl_lpm_data(lpm, 1); @@ -771,12 +825,15 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_SHIFTR: fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + fprintf(vlog_out, " "); + assert(! sign_extend); 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? +// assert(! sign_extend); + sign_extend = 1; emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); break; case IVL_LPM_SUB: diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 0cf1c1489..84e188a25 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -549,9 +549,10 @@ 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, ""); + + /* It is possible that the nexus does not have a name. For this + * case do not print an actual name. */ + fprintf(vlog_out, "/* Empty */"); } /* diff --git a/tgt-vlog95/numbers.c b/tgt-vlog95/numbers.c index ecf72dcc2..3327c6312 100644 --- a/tgt-vlog95/numbers.c +++ b/tgt-vlog95/numbers.c @@ -66,13 +66,71 @@ static int32_t get_int32_from_bits(const char *bits, unsigned nbits, return value; } +/* Emit the given bits as either a signed or unsigned constant. If the + * bits contain an undefined value then emit them as a binary constant + * otherwise emit them as a hex constant. */ +static void emit_bits(const char *bits, unsigned nbits, unsigned is_signed) +{ + int idx; + unsigned has_undef = 0; + + /* Check for an undefined bit. */ + for (idx = (int)nbits -1; idx >= 0; idx -= 1) { + if ((bits[idx] != '0') && (bits[idx] != '1')) { + has_undef = 1; + break; + } + } + + fprintf(vlog_out, "%u'", nbits); + if (is_signed) fprintf(vlog_out, "s"); + + /* Emit as a binary constant. */ + if (has_undef || (nbits < 2)) { + fprintf(vlog_out, "b"); + for (idx = (int)nbits-1; idx >= 0; idx -= 1) { + fprintf(vlog_out, "%c", bits[idx]); + } + /* Emit as a hex constant. */ + } else { + int start = 4*(nbits/4); + unsigned result = 0; + fprintf(vlog_out, "h"); + /* 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); + } + /* 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); + } + } +} + void emit_number(const char *bits, unsigned nbits, unsigned is_signed, const char *file, unsigned lineno) { - /* A signed value can only be 32 bits long since it can only be - * represented as an integer. We can trim any matching MSB bits - * to make it fit. We do not support undefined bits. */ - if (is_signed) { + /* If the user is allowing signed constructs then we can emit a + * signed number as a normal integer or with the 's syntax if + * an integer is not appropriate. */ + if (is_signed && allow_signed) { + int rtype; + int32_t value = get_int32_from_bits(bits, nbits, 1, &rtype); + if (rtype != 0) emit_bits(bits, nbits, is_signed); + else fprintf(vlog_out, "%"PRId32, value); + /* Otherwise a signed value can only be 32 bits long since it can + * only be represented as an integer. We can trim any matching MSB + * bits to make it fit. We cannot support individual undefined + * bits in the constant. */ + } else if (is_signed) { int rtype; int32_t value = get_int32_from_bits(bits, nbits, 1, &rtype); if (rtype > 0) { @@ -100,40 +158,7 @@ void emit_number(const char *bits, unsigned nbits, unsigned is_signed, * 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; - } - } - 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 { - 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); - } - /* 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); - } - } + emit_bits(bits, nbits, is_signed); } } @@ -152,8 +177,9 @@ void emit_real_number(double value) } // HERE: This needs to be reworked. We must have a trailing digit after the // decimal point and we want to print all the significant digits. -// I think the will require our own printing routine. - fprintf(vlog_out, "%#.16g", value); +// I think this will require our own printing routine. + if (value == 0.0) fprintf(vlog_out, "0.0"); + else fprintf(vlog_out, "%#.16g", value); } /* diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 949adca2e..767281111 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -418,7 +418,9 @@ static void emit_sig_type(ivl_signal_t sig) } } } else { - assert(type == IVL_SIT_TRI); + assert((type == IVL_SIT_TRI) || + (type == IVL_SIT_TRI0) || + (type == IVL_SIT_TRI1)); if (ivl_signal_data_type(sig) == IVL_VT_REAL) { fprintf(stderr, "%s:%u: vlog95 error: Real net ports (%s) " "are not supported.\n",