Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Stephen Williams 2013-02-24 08:36:23 -08:00
commit 952169ded9
8 changed files with 301 additions and 55 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -207,6 +207,7 @@ NetESelect* NetESelect::dup_expr() const
base_? base_->dup_expr() : 0,
expr_width(), sel_type_);
ivl_assert(*this, tmp);
tmp->cast_signed(has_sign());
tmp->set_line(*this);
return tmp;
}

View File

@ -49,6 +49,7 @@ NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig)
} else {
verinum zero ((int64_t)val);
zero = pad_to_width(zero, sig->vector_width());
zero.has_sign(sig->get_signed());
NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero);
zero_obj->set_line(*sig);
des->add_node(zero_obj);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -2166,7 +2166,7 @@ bool dll_target::net_const(const NetConst*net)
assert(net->pin_count() == 1);
obj->width_ = net->width();
obj->signed_ = 0;
obj->signed_ = net->value().has_sign();
if (obj->width_ <= sizeof(obj->b.bit_)) {
bits = obj->b.bit_;

View File

@ -176,19 +176,29 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
vlog_errors += 1;
}
break;
/* Convert Verilog-A min() or max() functions. This only works
* when the arguments have no side effect. */
/* Convert the Verilog-A min() or max() functions. */
case 'm':
case 'M':
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") %s (", oper);
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, ") ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : (");
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, "))");
if (ivl_expr_value(expr) == IVL_VT_REAL) {
/* For a real expression use the $min()/$max() function. */
if (ivl_expr_opcode(expr) == 'm') fprintf(vlog_out, "$min(");
else fprintf(vlog_out, "$max(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ",");
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, ")");
} else {
/* This only works when the argument has no side effect. */
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") %s (", oper);
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, ") ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : (");
emit_expr(scope, ivl_expr_oper2(expr), wid);
fprintf(vlog_out, "))");
}
break;
default:
emit_expr(scope, ivl_expr_oper1(expr), wid);
@ -321,6 +331,27 @@ static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
}
/*
* Emit a packed array access as a concatenation of bit selects.
*/
static void emit_expr_packed(ivl_scope_t scope, ivl_expr_t sig_expr,
ivl_expr_t sel_expr, unsigned wid)
{
unsigned idx;
assert(wid > 0);
fprintf(vlog_out, "{");
for (idx = wid - 1; idx > 0; idx -= 1) {
emit_select_name(scope, sig_expr, wid);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0);
fprintf(vlog_out, " + %u], ", idx);
}
emit_select_name(scope, sig_expr, wid);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0);
fprintf(vlog_out, "]}");
}
/*
* Emit an indexed part select as a concatenation of bit selects.
*/
@ -434,18 +465,19 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]");
} else if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
/* A constant part select. */
emit_select_name(scope, sig_expr, wid);
emit_scaled_range(scope, sel_expr, width, msb, lsb);
} else if (sel_type == IVL_SEL_OTHER) {
/* A packed array access. */
assert(lsb == 0);
assert(msb >= 0);
emit_expr_packed(scope, sig_expr, sel_expr, width);
} else {
if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
/* A constant part select. */
emit_select_name(scope, sig_expr, wid);
emit_scaled_range(scope, sel_expr, width,
msb, lsb);
} else {
/* An indexed part select. */
assert(sel_type != IVL_SEL_OTHER);
emit_expr_ips(scope, sig_expr, sel_expr,
sel_type, width, msb, lsb);
}
/* An indexed part select. */
emit_expr_ips(scope, sig_expr, sel_expr, sel_type,
width, msb, lsb);
}
}
} else {
@ -587,19 +619,23 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
/* Convert Verilog-A abs() function. This only works when the
* argument has no side effect. */
/* Convert the Verilog-A abs() function. */
case 'm':
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") > ");
if (ivl_expr_value(expr) == IVL_VT_REAL) fprintf(vlog_out, "0.0");
else fprintf(vlog_out, "0");
fprintf(vlog_out, " ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : -(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, "))");
if (ivl_expr_value(expr) == IVL_VT_REAL) {
/* For a real expression use the $abs() function. */
fprintf(vlog_out, "$abs(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ")");
} else {
/* This only works when the argument has no side effect. */
fprintf(vlog_out, "((");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") > 0 ? (");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ") : -(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, "))");
}
break;
default:
fprintf(vlog_out, "<unknown>");

View File

@ -465,7 +465,7 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD)
assert(! must_be_sig);
// HERE: I think we need special input code like the following.
#if 0
/* If these is a signal in this scope that is also driven by
/* If there is a signal in this scope that is also driven by
* the LPM then use the signal instead. */
sig = find_local_signal(scope, ivl_lpm_q(lpm), &word);
if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0);
@ -818,13 +818,14 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm)
static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm)
{
switch (ivl_lpm_type(lpm)) {
/* Convert Verilog-A abs() function. This only works when the
/* Convert the Verilog-A abs() function. This only works when the
* argument has no side effect. */
case IVL_LPM_ABS:
// HERE: If this is a real net then use the $abs() function to get nan to
// work correctly. See the expr code.
fprintf(vlog_out, "((");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
fprintf(vlog_out, ") > ");
// HERE: If this is a real net then use 0.0. See the expr code.
fprintf(vlog_out, "0 ? (");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
fprintf(vlog_out, ") : -(");
@ -1008,9 +1009,12 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm)
fprintf(vlog_out, ")");
break;
case IVL_LPM_SIGN_EXT:
// HERE: pr1002 and one other test fails if this assert is used. A more
// robust method is needed to make sure things work as expected.
// assert(! sign_extend);
sign_extend = 1;
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 1);
sign_extend = 0;
break;
case IVL_LPM_SUB:
fprintf(vlog_out, "(");

View File

@ -627,6 +627,163 @@ static void emit_named_block_scope(ivl_scope_t scope)
fprintf(vlog_out, " */\n");
}
/*
* In SystemVerilog a task or function can have a process to initialize
* variables. In reality SystemVerilog requires this to be before the
* initial/always blocks are processed, but that's not how it is currently
* implemented in Icarus!
*/
static int find_tf_process(ivl_process_t proc, ivl_scope_t scope)
{
if (scope == ivl_process_scope(proc)) {
ivl_scope_t mod_scope = scope;
/* A task or function can only have initial processes that
* are used to set local variables. */
assert(ivl_process_type(proc) == IVL_PR_INITIAL);
/* Find the module scope for this task/function. */
while (ivl_scope_type(mod_scope) != IVL_SCT_MODULE) {
mod_scope = ivl_scope_parent(mod_scope);
assert(mod_scope);
}
/* Emit the process in the module scope since that is where
* this all started. */
emit_process(mod_scope, proc);
}
return 0;
}
/*
* Emit any initial blocks for the tasks or functions in a module.
*/
static int emit_tf_process(ivl_scope_t scope, ivl_scope_t parent)
{
ivl_scope_type_t sc_type = ivl_scope_type(scope);
if ((sc_type == IVL_SCT_FUNCTION) || (sc_type == IVL_SCT_TASK)) {
/* Output the initial/always blocks for this module. */
ivl_design_process(design, (ivl_process_f)find_tf_process, scope);
}
return 0;
}
static void emit_path_delay(ivl_scope_t scope, ivl_delaypath_t dpath)
{
unsigned idx, count = 6;
uint64_t pdlys [12];
pdlys[0] = ivl_path_delay(dpath, IVL_PE_01);
pdlys[1] = ivl_path_delay(dpath, IVL_PE_10);
pdlys[2] = ivl_path_delay(dpath, IVL_PE_0z);
pdlys[3] = ivl_path_delay(dpath, IVL_PE_z1);
pdlys[4] = ivl_path_delay(dpath, IVL_PE_1z);
pdlys[5] = ivl_path_delay(dpath, IVL_PE_z0);
pdlys[6] = ivl_path_delay(dpath, IVL_PE_0x);
pdlys[7] = ivl_path_delay(dpath, IVL_PE_x1);
pdlys[8] = ivl_path_delay(dpath, IVL_PE_1x);
pdlys[9] = ivl_path_delay(dpath, IVL_PE_x0);
pdlys[10] = ivl_path_delay(dpath, IVL_PE_xz);
pdlys[11] = ivl_path_delay(dpath, IVL_PE_zx);
/* If the first six pdlys match then this may be a 1 delay form. */
if ((pdlys[0] == pdlys[1]) &&
(pdlys[0] == pdlys[2]) &&
(pdlys[0] == pdlys[3]) &&
(pdlys[0] == pdlys[4]) &&
(pdlys[0] == pdlys[5])) count = 1;
/* Check to see if only a rise and fall value are given for the first
* six pdlys. */
else if ((pdlys[0] == pdlys[2]) &&
(pdlys[0] == pdlys[3]) &&
(pdlys[1] == pdlys[4]) &&
(pdlys[1] == pdlys[5])) count = 2;
/* Check to see if a rise, fall and high-Z value are given for the
* first six pdlys. */
else if ((pdlys[0] == pdlys[3]) &&
(pdlys[1] == pdlys[5]) &&
(pdlys[2] == pdlys[4])) count = 3;
/* Now check to see if the 'bx related pdlys match the reduced
* delay form. If not then this is a twelve delay value. */
if ((pdlys[6] != ((pdlys[0] < pdlys[2]) ? pdlys[0] : pdlys[2])) ||
(pdlys[8] != ((pdlys[1] < pdlys[4]) ? pdlys[1] : pdlys[4])) ||
(pdlys[11] != ((pdlys[3] < pdlys[5]) ? pdlys[3] : pdlys[5])) ||
(pdlys[7] != ((pdlys[0] > pdlys[3]) ? pdlys[0] : pdlys[3])) ||
(pdlys[9] != ((pdlys[1] > pdlys[5]) ? pdlys[1] : pdlys[5])) ||
(pdlys[10] != ((pdlys[2] > pdlys[4]) ? pdlys[2] : pdlys[4]))) {
count = 12;
}
emit_scaled_delay(scope, pdlys[0]);
for(idx = 1; idx < count; idx += 1) {
fprintf(vlog_out, ", ");
emit_scaled_delay(scope, pdlys[idx]);
}
}
static void emit_specify_paths(ivl_scope_t scope, ivl_signal_t sig)
{
unsigned idx, count = ivl_signal_npath(sig);
for(idx = 0; idx < count; idx += 1) {
ivl_delaypath_t dpath = ivl_signal_path(sig, idx);
ivl_nexus_t cond = ivl_path_condit(dpath);
ivl_nexus_t source = ivl_path_source(dpath);
unsigned has_edge = 0;
fprintf(vlog_out, "%*c", indent, ' ');
if (cond) {
fprintf(vlog_out, "if (");
emit_nexus_as_ca(scope, cond, 0);
fprintf(vlog_out, ") ");
} else if (ivl_path_is_condit(dpath)) {
fprintf(vlog_out, "ifnone ");
}
fprintf(vlog_out, "(");
if (ivl_path_source_posedge(dpath)) {
fprintf(vlog_out, "posedge ");
has_edge = 1;
}
if (ivl_path_source_negedge(dpath)) {
fprintf(vlog_out, "negedge ");
has_edge = 1;
}
emit_nexus_as_ca(scope, source, 0);
fprintf(vlog_out, " =>");
/* The compiler does not keep the source expression for an edge
* sensitive path so add a constant to get the syntax right. */
if (has_edge) {
fprintf(vlog_out, "(%s : 1'bx /* Missing */)",
ivl_signal_basename(sig));
} else {
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
}
fprintf(vlog_out, ") = (");
emit_path_delay(scope, dpath);
fprintf(vlog_out, ");\n");
}
}
/*
* The path delay information from the specify block is attached to the
* output ports.
*/
static void emit_specify(ivl_scope_t scope)
{
unsigned word, idx, count = ivl_scope_ports(scope);
unsigned need_specify = 0;
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
ivl_signal_t port = get_port_from_nexus(scope, nex, &word);
// HERE: Do we need to use word? See emit_module_port_def().
assert(port);
if (ivl_signal_npath(port)) {
if (! need_specify) {
fprintf(vlog_out, "\n%*cspecify\n", indent, ' ');
need_specify = 1;
indent += indent_incr;
}
emit_specify_paths(scope, port);
}
}
if (need_specify) {
indent -= indent_incr;
fprintf(vlog_out, "%*cendspecify\n", indent, ' ');
}
}
/*
* 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
@ -801,6 +958,10 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
emit_tran(scope, ivl_scope_switch(scope, idx));
}
/* Output any initial blocks for tasks or functions defined
* in this module. Used to initialize local variables. */
ivl_scope_children(scope, (ivl_scope_f*) emit_tf_process, scope);
/* Output the initial/always blocks for this module. */
ivl_design_process(design, (ivl_process_f)find_process, scope);
}
@ -810,9 +971,12 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
emit_stmt(scope, ivl_scope_def(scope));
}
/* Now print out any sub-scopes. */
/* Print any sub-scopes. */
ivl_scope_children(scope, (ivl_scope_f*) emit_scope, scope);
/* And finally print a specify block when needed. */
if (sc_type == IVL_SCT_MODULE) emit_specify(scope);
/* Output the scope ending. */
assert(indent >= indent_incr);
indent -= indent_incr;

View File

@ -105,6 +105,25 @@ static void emit_stmt_lval_name(ivl_scope_t scope, ivl_lval_t lval,
}
}
static void emit_stmt_lval_packed(ivl_scope_t scope, ivl_lval_t lval,
ivl_signal_t sig, ivl_expr_t sel_expr,
unsigned wid)
{
unsigned idx;
assert(wid > 0);
fprintf(vlog_out, "{");
for (idx = wid - 1; idx > 0; idx -= 1) {
emit_stmt_lval_name(scope, lval, sig);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0);
fprintf(vlog_out, " + %u], ", idx);
}
emit_stmt_lval_name(scope, lval, sig);
fprintf(vlog_out, "[");
emit_expr(scope, sel_expr, 0);
fprintf(vlog_out, "]}");
}
static void emit_stmt_lval_ips(ivl_scope_t scope, ivl_lval_t lval,
ivl_signal_t sig, ivl_expr_t sel_expr,
ivl_select_type_t sel_type,
@ -245,17 +264,18 @@ static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval)
fprintf(vlog_out, "[");
emit_scaled_expr(scope, sel_expr, msb, lsb);
fprintf(vlog_out, "]");
} else {
} else if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
/* A constant part select. */
if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
emit_stmt_lval_name(scope, lval, sig);
emit_scaled_range(scope, sel_expr, width, msb, lsb);
emit_stmt_lval_name(scope, lval, sig);
emit_scaled_range(scope, sel_expr, width, msb, lsb);
} else if (sel_type == IVL_SEL_OTHER) {
assert(lsb == 0);
assert(msb >= 0);
emit_stmt_lval_packed(scope, lval, sig, sel_expr, width);
} else {
/* An indexed part select. */
} else {
assert(sel_type != IVL_SEL_OTHER);
emit_stmt_lval_ips(scope, lval, sig, sel_expr, sel_type,
width, msb, lsb);
}
emit_stmt_lval_ips(scope, lval, sig, sel_expr, sel_type,
width, msb, lsb);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2013 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
@ -30,7 +30,7 @@
static const char*version_string =
"Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n"
"Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com)\n\n"
"Copyright (C) 2010-2013 Cary R. (cygcary@yahoo.com)\n\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 2 of the License, or\n"
@ -175,8 +175,9 @@ 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, " * Converted using %s delays and %s signed support.\n",
ivl_design_delay_sel(des),
allow_signed ? "with" : "without");
fprintf(vlog_out, " */\n");
sim_precision = ivl_design_time_precision(des);
@ -193,6 +194,25 @@ int target_design(ivl_design_t des)
/* Emit any UDPs that are Icarus generated (D-FF). */
emit_icarus_generated_udps();
/* If there were errors then add this information to the output. */
if (vlog_errors) {
fprintf(vlog_out, "\n");
fprintf(vlog_out, "/*\n");
if (vlog_errors == 1) {
fprintf(vlog_out, " * There was 1 error during "
"translation.\n");
} else {
fprintf(vlog_out, " * There were %d errors during "
"translation.\n",
vlog_errors);
}
fprintf(vlog_out, " */\n");
/* Add something that makes the file invalid to make sure
* the user knows there were errors. */
fprintf(vlog_out, "<Add some text to make sure this file is not "
"valid Verilog>\n");
}
fclose(vlog_out);
/* A do nothing call to prevent warnings about this routine not