2011-01-31 08:53:53 +01:00
|
|
|
/*
|
|
|
|
|
* 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 "config.h"
|
|
|
|
|
# include "vlog95_priv.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Extract an int32_t value from the given bit information. 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. -2 is all bits z and -3 is all bits x.
|
|
|
|
|
*/
|
|
|
|
|
static int32_t get_int32_from_bits(const char *bits, unsigned nbits,
|
|
|
|
|
unsigned is_signed, int *result_type)
|
|
|
|
|
{
|
|
|
|
|
unsigned trim_wid = nbits - 1;
|
|
|
|
|
const char msb = is_signed ? bits[trim_wid] : '0';
|
|
|
|
|
unsigned idx;
|
|
|
|
|
int32_t value = 0;
|
|
|
|
|
/* 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;
|
|
|
|
|
/* If the value is entirely x/z then return -2 or -3. */
|
2011-03-14 00:13:39 +01:00
|
|
|
if (trim_wid == 1) {
|
2011-01-31 08:53:53 +01:00
|
|
|
if (bits[idx] == 'x') *result_type -= 1;
|
|
|
|
|
*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;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-21 22:37:59 +01:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-31 08:53:53 +01:00
|
|
|
void emit_number(const char *bits, unsigned nbits, unsigned is_signed,
|
|
|
|
|
const char *file, unsigned lineno)
|
|
|
|
|
{
|
2011-03-21 22:37:59 +01:00
|
|
|
/* 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) {
|
2011-01-31 08:53:53 +01:00
|
|
|
int rtype;
|
|
|
|
|
int32_t value = get_int32_from_bits(bits, nbits, 1, &rtype);
|
|
|
|
|
if (rtype > 0) {
|
|
|
|
|
fprintf(vlog_out, "<invalid>");
|
|
|
|
|
fprintf(stderr, "%s:%u: vlog95 error: Signed number is "
|
|
|
|
|
"greater than 32 bits (%u) and cannot be "
|
|
|
|
|
"safely represented.\n", file, lineno,
|
|
|
|
|
rtype);
|
|
|
|
|
vlog_errors += 1;
|
|
|
|
|
} else if (rtype == -1) {
|
|
|
|
|
fprintf(vlog_out, "<invalid>");
|
|
|
|
|
fprintf(stderr, "%s:%u: vlog95 error: Signed number has "
|
|
|
|
|
"an undefined bit and cannot be "
|
|
|
|
|
"represented.\n", file, lineno);
|
|
|
|
|
vlog_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
} else if (rtype == -2) {
|
|
|
|
|
fprintf(vlog_out, "'bz");
|
|
|
|
|
} else if (rtype == -3) {
|
|
|
|
|
fprintf(vlog_out, "'bx");
|
|
|
|
|
} else {
|
|
|
|
|
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 {
|
2011-03-21 22:37:59 +01:00
|
|
|
emit_bits(bits, nbits, is_signed);
|
2011-01-31 08:53:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void emit_real_number(double value)
|
|
|
|
|
{
|
|
|
|
|
/* Check for NaN. */
|
|
|
|
|
if (value != value) {
|
|
|
|
|
fprintf(vlog_out, "(0.0/0.0)");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Check for the infinities. */
|
|
|
|
|
if (value && value == 0.5*value) {
|
|
|
|
|
if (value > 0) fprintf(vlog_out, "(1.0/0.0)");
|
|
|
|
|
else fprintf(vlog_out, "(-1.0/0.0)");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 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.
|
2011-03-21 22:37:59 +01:00
|
|
|
// I think this will require our own printing routine.
|
|
|
|
|
if (value == 0.0) fprintf(vlog_out, "0.0");
|
|
|
|
|
else fprintf(vlog_out, "%#.16g", value);
|
2011-01-31 08:53:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
/* If the value is entirely x/z then return -2 or -3. */
|
2011-03-14 00:13:39 +01:00
|
|
|
if (trim_wid == 1) {
|
2011-01-31 08:53:53 +01:00
|
|
|
if (bits[idx] == 'x') *result_type -= 1;
|
|
|
|
|
*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. -2 is all bits z and -3 is all bits x.
|
|
|
|
|
*/
|
|
|
|
|
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;
|
|
|
|
|
/* If the value is entirely x/z then return -2 or -3. */
|
2011-03-14 00:13:39 +01:00
|
|
|
if (trim_wid == 1) {
|
2011-01-31 08:53:53 +01:00
|
|
|
if (bits[idx] == 'x') *result_type -= 1;
|
|
|
|
|
*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. -2 is all bits z and -3 is all bits x.
|
|
|
|
|
*/
|
|
|
|
|
int32_t get_int32_from_number(ivl_expr_t expr, int *result_type)
|
|
|
|
|
{
|
|
|
|
|
assert(ivl_expr_type(expr) == IVL_EX_NUMBER);
|
|
|
|
|
return get_int32_from_bits(ivl_expr_bits(expr), ivl_expr_width(expr),
|
|
|
|
|
ivl_expr_signed(expr), result_type);
|
|
|
|
|
}
|