vlog95: Add support for most unconnected ports and more signed support.

This patch adds support for correctly handling most unconnected ports.
Most important is top level ports that are the root of the conversion.

This patch also adds support for emitting more signed constructs when
they are requested. $signed() and $unsigned() are still not supported
or recognized as an error when not emitting signed constructs.
This commit is contained in:
Cary R 2011-03-21 14:37:59 -07:00 committed by Stephen Williams
parent 042f405707
commit ceaa79e95d
4 changed files with 133 additions and 47 deletions

View File

@ -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:

View File

@ -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, "<missing>");
/* It is possible that the nexus does not have a name. For this
* case do not print an actual name. */
fprintf(vlog_out, "/* Empty */");
}
/*

View File

@ -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);
}
/*

View File

@ -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",