Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
bf655003e8
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
112
elab_expr.cc
112
elab_expr.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
44
sys_funcs.cc
44
sys_funcs.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue