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

This commit is contained in:
Stephen Williams 2019-10-14 14:11:58 -07:00
commit bf655003e8
4 changed files with 104 additions and 71 deletions

View File

@ -190,9 +190,13 @@ prefixed by "I " and other files are prefixed by "M ".
.B -m\fImodule\fP
Add this module to the list of VPI modules to be loaded by the
simulation. Many modules can be specified, and all will be loaded, in
the order specified. The system module is implicit and always included.
If a System Function Table file (<module>.sft) exists for the module it
will be loaded automatically.
the order specified. The system module is implicit and always included
(and loaded last). If a System Function Table file (<module>.sft)
exists for the module it will be loaded automatically.
If the specified name includes at least one directory character, it is
assumed to be prefixed by the path to the module, otherwise the module
is assumed to be located in the \fIiverilog\fP base directory.
.TP 8
.B -N\fIpath\fP
This is used for debugging the compiler proper. Dump the final netlist

View File

@ -864,7 +864,14 @@ static void add_sft_file(const char *module)
char *file;
file = (char *) malloc(strlen(base)+1+strlen(module)+4+1);
sprintf(file, "%s%c%s.sft", base, sep, module);
// If the module name has at least one directory character
// in it, assume it includes the path, otherwise look in
// the base directory.
if (strchr(module, sep))
sprintf(file, "%s.sft", module);
else
sprintf(file, "%s%c%s.sft", base, sep, module);
if (access(file, R_OK) == 0)
fprintf(iconfig_file, "sys_func:%s\n", file);
free(file);

View File

@ -2752,13 +2752,15 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
ivl_assert(*this, size_);
ivl_assert(*this, base_);
// When changing size, a cast behaves exactly like an assignment,
// so the result size affects the final expression width.
// A cast behaves exactly like an assignment to a temporary variable,
// so the temporary result size may affect the sub-expression width.
unsigned cast_width = base_->expr_width();
if (cast_width < expr_width_)
cast_width = expr_width_;
NetExpr*sub = base_->elaborate_expr(des, scope, cast_width, flags);
if (sub == 0)
return 0;
// Perform the cast. The extension method (zero/sign), if needed,
// depends on the type of the base expression.
@ -2769,33 +2771,33 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid)
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&)
{
ivl_type_t t = target_->elaborate_type(des, scope);
base_->test_width(des, scope, wid);
if(const netdarray_t*use_darray = dynamic_cast<const netdarray_t*> (t)) {
width_mode_t tmp_mode = PExpr::SIZED;
base_->test_width(des, scope, tmp_mode);
if (const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(t)) {
expr_type_ = use_darray->element_base_type();
expr_width_ = use_darray->element_width();
}
else if(const netstring_t*use_string = dynamic_cast<const netstring_t*> (t)) {
} else if (const netstring_t*use_string = dynamic_cast<const netstring_t*>(t)) {
expr_type_ = use_string->base_type();
expr_width_ = 8;
}
else {
} else {
expr_type_ = t->base_type();
expr_width_ = t->packed_width();
}
min_width_ = expr_width_;
signed_flag_ = t->get_signed();
min_width_ = expr_width_;
return expr_width_;
}
NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
ivl_type_t type, unsigned) const
ivl_type_t type, unsigned flags) const
{
const netdarray_t*darray = NULL;
const netvector_t*vector = NULL;
@ -2824,60 +2826,68 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
}
// Fallback
return elaborate_expr(des, scope, (unsigned) 0, 0);
return elaborate_expr(des, scope, (unsigned) 0, flags);
}
NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
unsigned, unsigned) const
unsigned expr_wid, unsigned flags) const
{
NetExpr*expr = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS);
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
if(dynamic_cast<const real_type_t*>(target_)) {
return cast_to_real(expr);
// A cast behaves exactly like an assignment to a temporary variable,
// so the temporary result size may affect the sub-expression width.
unsigned cast_width = base_->expr_width();
if (type_is_vectorable(base_->expr_type()) && (cast_width < expr_width_))
cast_width = expr_width_;
NetExpr*sub = base_->elaborate_expr(des, scope, cast_width, flags);
if (sub == 0)
return 0;
if (dynamic_cast<const real_type_t*>(target_)) {
return cast_to_real(sub);
}
if(const atom2_type_t*atom = dynamic_cast<const atom2_type_t*>(target_)) {
if(base_->expr_width() > expr_width_) {
cerr << get_fileline() << ": cast type is not wide enough to store the result." << endl;
ivl_assert(*this, 0);
}
NetExpr*tmp = 0;
if (dynamic_cast<const atom2_type_t*>(target_)) {
tmp = cast_to_int2(sub, expr_width_);
}
if (const vector_type_t*vec = dynamic_cast<const vector_type_t*>(target_)) {
switch (vec->base_type) {
case IVL_VT_BOOL:
tmp = cast_to_int2(sub, expr_width_);
break;
if(base_->has_sign() != atom->signed_flag) {
cerr << get_fileline() << ": cast type and subject differ in signedness." << endl;
ivl_assert(*this, 0);
}
case IVL_VT_LOGIC:
tmp = cast_to_int4(sub, expr_width_);
break;
// That is how you both resize & cast to integers
return new NetECast('2', expr, expr_width_, expr->has_sign());
default:
break;
}
}
if (tmp) {
if (tmp == sub) {
// We already had the correct base type, so we just need to
// fix the size. Note that even if the size is already correct,
// we still need to isolate the sub-expression from changes in
// the signedness pushed down from the main expression.
tmp = cast_to_width(sub, expr_width_, sub->has_sign(), *this);
}
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
if(const vector_type_t*vec = dynamic_cast<const vector_type_t*>(target_)) {
switch(vec->base_type) {
case IVL_VT_BOOL:
return cast_to_int2(expr, expr_width_);
if (dynamic_cast<const string_type_t*>(target_)) {
if (base_->expr_type() == IVL_VT_STRING)
return sub; // no conversion
case IVL_VT_LOGIC:
return cast_to_int4(expr, expr_width_);
default:
break; /* Suppress warnings */
}
}
else if(dynamic_cast<const string_type_t*>(target_)) {
if(base_->expr_type() == IVL_VT_STRING)
return expr; // no conversion
if((base_->expr_type() != IVL_VT_BOOL) &&
(base_->expr_type() != IVL_VT_LOGIC)) {
cerr << get_fileline() << ": cannot be cast to a string." << endl;
ivl_assert(*this, false);
}
return expr;
if (base_->expr_type() == IVL_VT_LOGIC
|| base_->expr_type() == IVL_VT_BOOL)
return sub; // handled by the target as special cases
}
cerr << get_fileline() << ": sorry: This cast operation is not yet supported." << endl;
des->errors += 1;
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2004-2019 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
@ -44,11 +44,24 @@ struct sfunc_return_type_cell : sfunc_return_type {
struct sfunc_return_type_cell*next;
};
static struct sfunc_return_type_cell*sfunc_stack = 0;
static struct sfunc_return_type_cell*sfunc_list_head = 0;
static struct sfunc_return_type_cell*sfunc_list_tail = 0;
void append_to_list(struct sfunc_return_type_cell*cell)
{
if (sfunc_list_tail) {
sfunc_list_tail->next = cell;
sfunc_list_tail = cell;
} else {
sfunc_list_head = cell;
sfunc_list_tail = cell;
}
cell->next = 0;
}
void cleanup_sys_func_table()
{
struct sfunc_return_type_cell *next, *cur = sfunc_stack;
struct sfunc_return_type_cell *next, *cur = sfunc_list_head;
while (cur) {
next = cur->next;
delete cur;
@ -58,8 +71,8 @@ void cleanup_sys_func_table()
const struct sfunc_return_type* lookup_sys_func(const char*name)
{
/* First, try to find the name in the function stack. */
struct sfunc_return_type_cell*cur = sfunc_stack;
/* First, try to find the name in the function list. */
struct sfunc_return_type_cell*cur = sfunc_list_head;
while (cur) {
if (strcmp(cur->name, name) == 0)
return cur;
@ -77,7 +90,7 @@ const struct sfunc_return_type* lookup_sys_func(const char*name)
idx += 1;
}
/* No luck finding, so return the trailer, which give a
/* No luck finding, so return the trailer, which gives a
default description. */
return sfunc_table + idx;
}
@ -87,6 +100,10 @@ const struct sfunc_return_type* lookup_sys_func(const char*name)
* format:
*
* <name> <type> [<arguments>]
*
* The driver passes us user-provided tables first, so we add new entries
* to the end of the list. This allows user-defined functions to override
* built-in functions.
*/
int load_sys_func_table(const char*path)
{
@ -136,8 +153,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_REAL;
cell->wid = 1;
cell->signed_flag = true;
cell->next = sfunc_stack;
sfunc_stack = cell;
append_to_list(cell);
continue;
}
@ -147,8 +163,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_LOGIC;
cell->wid = 32;
cell->signed_flag = true;
cell->next = sfunc_stack;
sfunc_stack = cell;
append_to_list(cell);
continue;
}
@ -188,8 +203,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_LOGIC;
cell->wid = width;
cell->signed_flag = signed_flag;
cell->next = sfunc_stack;
sfunc_stack = cell;
append_to_list(cell);
continue;
}
@ -199,8 +213,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_VOID;
cell->wid = 0;
cell->signed_flag = false;
cell->next = sfunc_stack;
sfunc_stack = cell;
append_to_list(cell);
continue;
}
@ -210,8 +223,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_STRING;
cell->wid = 0; // string is a dynamic length type
cell->signed_flag = false;
cell->next = sfunc_stack;
sfunc_stack = cell;
append_to_list(cell);
continue;
}