vlog95: Print structural string constants and a few other fixes
This patch adds the ability to print a constant string in a structural context. It also fixes the argument order for structural function calls and makes a few improvements in nexus identification.
This commit is contained in:
parent
2158ebdf0b
commit
8b8e181fe2
|
|
@ -244,7 +244,7 @@ static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
||||||
{
|
{
|
||||||
unsigned idx, count, lineno;
|
unsigned idx, count, lineno;
|
||||||
const char* file;
|
const char *file;
|
||||||
count = ivl_scope_params(scope);
|
count = ivl_scope_params(scope);
|
||||||
file = ivl_expr_file(expr);
|
file = ivl_expr_file(expr);
|
||||||
lineno = ivl_expr_lineno(expr);
|
lineno = ivl_expr_lineno(expr);
|
||||||
|
|
@ -253,7 +253,7 @@ static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
||||||
if (lineno != ivl_parameter_lineno(par)) continue;
|
if (lineno != ivl_parameter_lineno(par)) continue;
|
||||||
if (strcmp(file, ivl_parameter_file(par)) == 0) {
|
if (strcmp(file, ivl_parameter_file(par)) == 0) {
|
||||||
/* Check that the appropriate expression bits match the
|
/* Check that the appropriate expression bits match the
|
||||||
* the original parameter bits. */
|
* original parameter bits. */
|
||||||
ivl_expr_t pex = ivl_parameter_expr(par);
|
ivl_expr_t pex = ivl_parameter_expr(par);
|
||||||
unsigned wid = ivl_expr_width(expr);
|
unsigned wid = ivl_expr_width(expr);
|
||||||
unsigned param_wid = ivl_expr_width(pex);
|
unsigned param_wid = ivl_expr_width(pex);
|
||||||
|
|
@ -271,6 +271,8 @@ static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// HERE: Does this work with an out of scope parameter reference?
|
||||||
|
// What about real parameters?
|
||||||
emit_id(ivl_parameter_basename(par));
|
emit_id(ivl_parameter_basename(par));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,9 +242,9 @@ static void emit_nexus_port_signal(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
ivl_signal_t sig = 0;
|
ivl_signal_t sig = 0;
|
||||||
for (idx = 0; idx < count; idx += 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||||
|
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
|
||||||
if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) ||
|
if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) ||
|
||||||
(ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) assert(0);
|
(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 (t_sig) {
|
||||||
if (scope != ivl_signal_scope(t_sig)) continue;
|
if (scope != ivl_signal_scope(t_sig)) continue;
|
||||||
assert(! sig);
|
assert(! sig);
|
||||||
|
|
@ -256,6 +256,9 @@ static void emit_nexus_port_signal(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
else fprintf(vlog_out, "/* Empty */");
|
else fprintf(vlog_out, "/* Empty */");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Emit the input port driving expression.
|
||||||
|
*/
|
||||||
void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex)
|
void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
{
|
{
|
||||||
unsigned idx, count = ivl_nexus_ptrs(nex);
|
unsigned idx, count = ivl_nexus_ptrs(nex);
|
||||||
|
|
@ -265,12 +268,12 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
ivl_signal_t sig = 0;
|
ivl_signal_t sig = 0;
|
||||||
for (idx = 0; idx < count; idx += 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
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_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_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_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr);
|
||||||
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
|
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
|
||||||
|
if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) &&
|
||||||
|
(ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue;
|
||||||
if (t_lpm) {
|
if (t_lpm) {
|
||||||
assert(! lpm);
|
assert(! lpm);
|
||||||
lpm = t_lpm;
|
lpm = t_lpm;
|
||||||
|
|
@ -325,6 +328,10 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
ivl_signal_t sig = 0;
|
ivl_signal_t sig = 0;
|
||||||
for (idx = 0; idx < count; idx += 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||||
|
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 ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) &&
|
if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) &&
|
||||||
(ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) {
|
(ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) {
|
||||||
/* If we only have a single input then we want
|
/* If we only have a single input then we want
|
||||||
|
|
@ -333,10 +340,6 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
must_be_sig = 1;
|
must_be_sig = 1;
|
||||||
} else continue;
|
} 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);
|
|
||||||
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
|
|
||||||
if (t_lpm) {
|
if (t_lpm) {
|
||||||
assert(! lpm);
|
assert(! lpm);
|
||||||
lpm = t_lpm;
|
lpm = t_lpm;
|
||||||
|
|
@ -660,12 +663,13 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm)
|
||||||
unsigned count = ivl_lpm_size(lpm);
|
unsigned count = ivl_lpm_size(lpm);
|
||||||
if (count) {
|
if (count) {
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
|
count -= 1;
|
||||||
fprintf(vlog_out, "(");
|
fprintf(vlog_out, "(");
|
||||||
for (idx = count-1; idx > 0; idx -= 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx));
|
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx));
|
||||||
fprintf(vlog_out, ", ");
|
fprintf(vlog_out, ", ");
|
||||||
}
|
}
|
||||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0));
|
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, count));
|
||||||
fprintf(vlog_out, ")");
|
fprintf(vlog_out, ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -484,27 +484,115 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net)
|
static void emit_number_as_string(ivl_net_const_t net_const)
|
||||||
{
|
{
|
||||||
switch (ivl_const_type(const_net)) {
|
const char *bits = ivl_const_bits(net_const);
|
||||||
|
unsigned count = ivl_const_width(net_const);
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
assert((count % 8) == 0);
|
||||||
|
fprintf(vlog_out, "\"");
|
||||||
|
for (idx = (int)count-1; idx >= 0; idx -= 8) {
|
||||||
|
unsigned bit;
|
||||||
|
char val = 0;
|
||||||
|
for (bit = 0; bit < 8; bit += 1) {
|
||||||
|
val |= (bits[idx-bit] == '1') ? 1 << (7-bit) : 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip any NULL bytes. */
|
||||||
|
if (val == 0) continue;
|
||||||
|
/* Print some values that must be escapped. */
|
||||||
|
if (val == '"') fprintf(vlog_out, "\\\"");
|
||||||
|
else if (val == '\\') fprintf(vlog_out, "\\\\");
|
||||||
|
/* Print the printable characters. */
|
||||||
|
else if (isprint(val)) fprintf(vlog_out, "%c", val);
|
||||||
|
/* Print the non-printable characters as an octal escape. */
|
||||||
|
else fprintf(vlog_out, "\\%03o", val);
|
||||||
|
}
|
||||||
|
fprintf(vlog_out, "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned emit_as_input(ivl_scope_t scope, ivl_net_const_t net_const)
|
||||||
|
{
|
||||||
|
ivl_scope_t const_scope = ivl_const_scope(net_const);
|
||||||
|
ivl_scope_t parent = ivl_scope_parent(scope);
|
||||||
|
|
||||||
|
/* Look to see if the constant scope is a parent of this scope. */
|
||||||
|
while (parent) {
|
||||||
|
if (parent == const_scope) break;
|
||||||
|
parent = ivl_scope_parent(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the constant scope is a parent then look for an input in
|
||||||
|
* this scope and use that for the name. */
|
||||||
|
if (parent) {
|
||||||
|
ivl_nexus_t nex = ivl_const_nex(net_const);
|
||||||
|
unsigned idx, 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 && (ivl_signal_port(sig) == IVL_SIP_INPUT)) {
|
||||||
|
emit_id(ivl_signal_basename(sig));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t net_const)
|
||||||
|
{
|
||||||
|
ivl_scope_t const_scope = ivl_const_scope(net_const);
|
||||||
|
unsigned idx, count, lineno;
|
||||||
|
const char *file;
|
||||||
|
count = ivl_scope_params(const_scope);
|
||||||
|
file = ivl_const_file(net_const);
|
||||||
|
lineno = ivl_const_lineno(net_const);
|
||||||
|
/* Look to see if the constant matches a parameter in its scope. */
|
||||||
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
|
ivl_parameter_t par = ivl_scope_param(const_scope, idx);
|
||||||
|
if (lineno != ivl_parameter_lineno(par)) continue;
|
||||||
|
if (strcmp(file, ivl_parameter_file(par)) == 0) {
|
||||||
|
/* Check that the appropriate expression bits match the
|
||||||
|
* original parameter bits. */
|
||||||
|
// HERE: Verify that the values match and then print the name.
|
||||||
|
// Does this work with out of scope references? Check real parameters.
|
||||||
|
emit_id(ivl_parameter_basename(par));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the scopes don't match then we assume this is an empty port. */
|
||||||
|
if (const_scope != scope) {
|
||||||
|
/* This constant could really be from an input port. */
|
||||||
|
if (emit_as_input(scope, net_const)) return;
|
||||||
|
fprintf(vlog_out, "/* Empty */");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ivl_const_type(net_const)) {
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
emit_number(ivl_const_bits(const_net),
|
emit_number(ivl_const_bits(net_const),
|
||||||
ivl_const_width(const_net),
|
ivl_const_width(net_const),
|
||||||
ivl_const_signed(const_net),
|
ivl_const_signed(net_const),
|
||||||
ivl_const_file(const_net),
|
ivl_const_file(net_const),
|
||||||
ivl_const_lineno(const_net));
|
ivl_const_lineno(net_const));
|
||||||
|
break;
|
||||||
|
case IVL_VT_STRING:
|
||||||
|
emit_number_as_string(net_const);
|
||||||
break;
|
break;
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
emit_real_number(ivl_const_real(const_net));
|
emit_real_number(ivl_const_real(net_const));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(vlog_out, "<invalid>");
|
fprintf(vlog_out, "<invalid>");
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Unknown constant type "
|
fprintf(stderr, "%s:%u: vlog95 error: Unknown constant type "
|
||||||
"(%d).\n",
|
"(%d).\n",
|
||||||
ivl_const_file(const_net),
|
ivl_const_file(net_const),
|
||||||
ivl_const_lineno(const_net),
|
ivl_const_lineno(net_const),
|
||||||
(int)ivl_const_type(const_net));
|
(int)ivl_const_type(net_const));
|
||||||
vlog_errors += 1;
|
vlog_errors += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -517,11 +605,11 @@ static unsigned find_const_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
||||||
count = ivl_nexus_ptrs(nex);
|
count = ivl_nexus_ptrs(nex);
|
||||||
for (idx = 0; idx < count; idx += 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||||
ivl_net_const_t const_net = ivl_nexus_ptr_con(nex_ptr);
|
ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr);
|
||||||
// HERE: Do we need to check for duplicates?
|
// HERE: Do we need to check for duplicates?
|
||||||
if (const_net) {
|
if (net_const) {
|
||||||
assert(! ivl_nexus_ptr_pin(nex_ptr));
|
assert(! ivl_nexus_ptr_pin(nex_ptr));
|
||||||
emit_const_nexus(scope, const_net);
|
emit_const_nexus(scope, net_const);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ static void emit_bits(const char *bits, unsigned nbits, unsigned is_signed)
|
||||||
unsigned has_undef = 0;
|
unsigned has_undef = 0;
|
||||||
|
|
||||||
/* Check for an undefined bit. */
|
/* Check for an undefined bit. */
|
||||||
for (idx = (int)nbits -1; idx >= 0; idx -= 1) {
|
for (idx = (int)nbits-1; idx >= 0; idx -= 1) {
|
||||||
if ((bits[idx] != '0') && (bits[idx] != '1')) {
|
if ((bits[idx] != '0') && (bits[idx] != '1')) {
|
||||||
has_undef = 1;
|
has_undef = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue