Add more functionality to the vlog95 back end.
This patch adds significantly more functionality to the vlog95 back end. The following are the major additions: Display unsigned numbers without undefined bits in hex. Add support for both L-Value and R-value bit and part selects. Added support for out of scope references. Added support for emitting logic gates (range not finished, name is invalid). Added support for emitting initial/always blocks. Add support for event inter statement delays. Convert a blocking inter statement delay assign back to the original form. Added support for rescaling variable delays. Added support for the disable statement. Added support for an event trigger statement (event name is missing). Added support for calling a user task (calling arguments are missing). Added support for an event based delay statement (@) (event name is missing) Not all of these are working as expected since there is not currently a routine to find a nexus name as a function of scope (needed for event names, logic gate ports, etc.). Since the Icarus compiler generates structural code the arguments to modules, module instantiations and calling user tasks are also still missing.
This commit is contained in:
parent
69ec4cfc6d
commit
203a8cc997
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <stdlib.h>
|
||||
# include <string.h>
|
||||
# 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<oversized_signed>");
|
||||
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, "<undefined_signed>");
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <stdlib.h>
|
||||
# include <string.h>
|
||||
# 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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "[<invalid>:<invalid>]");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "[<invalid>:<invalid>]");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<invalid>");
|
||||
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, "<missing>");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <inttypes.h>
|
||||
|
|
@ -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, "<invalid>");
|
||||
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, "<unknown>(");
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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 <var> = <delay> <value> into
|
||||
* begin
|
||||
* <tmp> = <value>;
|
||||
* <delay> <var> = <tmp>;
|
||||
* 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, "<unknown>");
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 <stdio.h>
|
||||
# include <assert.h>
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue