Merge branch 'master' into vvp-net-out-rework

Conflicts:
	vvp/part.cc
This commit is contained in:
Stephen Williams 2009-07-28 21:20:50 -07:00
commit bbc0ee0ad0
23 changed files with 590 additions and 124 deletions

View File

@ -134,6 +134,9 @@ extern bool gn_specify_blocks_flag;
/* If this flag is true, then support/elaborate Verilog-AMS. */ /* If this flag is true, then support/elaborate Verilog-AMS. */
extern bool gn_verilog_ams_flag; extern bool gn_verilog_ams_flag;
/* If this flag is true, then support/elaborate SystemVerilog. */
extern bool gn_system_verilog_flag;
/* If this flag is false a warning is printed when the port declaration /* If this flag is false a warning is printed when the port declaration
is scalar and the net/register definition is vectored. */ is scalar and the net/register definition is vectored. */
extern bool gn_io_range_error_flag; extern bool gn_io_range_error_flag;

View File

@ -281,7 +281,7 @@ static int t_version_only(void)
} }
fflush(0); fflush(0);
snprintf(tmp, sizeof tmp, "%s%civl -V -C%s -C%s", pbase, sep, snprintf(tmp, sizeof tmp, "%s%civl -V -C%s -C%s", base, sep,
iconfig_path, iconfig_common_path); iconfig_path, iconfig_common_path);
rc = system(tmp); rc = system(tmp);
if (rc != 0) { if (rc != 0) {

View File

@ -174,6 +174,15 @@ static void elaborate_scope_parameters_(Design*des, NetScope*scope,
for (mparm_it_t cur = parameters.begin() for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) { ; cur != parameters.end() ; cur ++) {
// A parameter can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second.get_fileline()
<< ": error: parameter and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
elaborate_parm_item_((*cur).first, (*cur).second, des, scope); elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
} }
} }
@ -184,6 +193,15 @@ static void elaborate_scope_localparams_(Design*des, NetScope*scope,
for (mparm_it_t cur = localparams.begin() for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) { ; cur != localparams.end() ; cur ++) {
// A localparam can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second.get_fileline()
<< ": error: localparam and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
elaborate_parm_item_((*cur).first, (*cur).second, des, scope); elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
} }
} }
@ -249,6 +267,15 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope,
continue; continue;
} }
// A task can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second->get_fileline()
<< ": error: task and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
// A task can not have the same name as a parameter. // A task can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb; const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb, const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb,
@ -296,6 +323,15 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope,
continue; continue;
} }
// A function can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second->get_fileline()
<< ": error: function and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
// A function can not have the same name as a parameter. // A function can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb; const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb, const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb,
@ -361,6 +397,12 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
<< scope_path(scope) << "." << endl; << scope_path(scope) << "." << endl;
} }
// Add the genvars to the scope.
typedef map<perm_string,LineInfo*>::const_iterator genvar_it_t;
for (genvar_it_t cur = genvars.begin(); cur != genvars.end(); cur++ ) {
scope->add_genvar((*cur).first, (*cur).second);
}
// Generate all the parameters that this instance of this // Generate all the parameters that this instance of this
// module introduces to the design. This loop elaborates the // module introduces to the design. This loop elaborates the
// parameters, but doesn't evaluate references to // parameters, but doesn't evaluate references to
@ -521,12 +563,13 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
{ {
// Check that the loop_index variable was declared in a // Check that the loop_index variable was declared in a
// genvar statement. // genvar statement.
if (container->find_genvar(loop_index) == 0) {
// MISSING CODE! cerr << get_fileline() << ": error: genvar is missing for "
// "generate \"loop\" variable '" << loop_index << "'."
// Also the genvar checks below need to be moved/changed << endl;
// when this is implemented. They currently work, but do des->errors += 1;
// not reference the genvar statement. return false;
}
// We're going to need a genvar... // We're going to need a genvar...
int genvar; int genvar;
@ -558,6 +601,15 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
des->errors += 1; des->errors += 1;
return false; return false;
} }
// A generate "loop" can not have the same name as a genvar.
if (container->find_genvar(scope_name)) {
cerr << get_fileline() << ": error: generate \"loop\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "loop" can not have the same name as a named event. // A generate "loop" can not have the same name as a named event.
const NetEvent *event = container->find_event(scope_name); const NetEvent *event = container->find_event(scope_name);
if (event) { if (event) {
@ -578,17 +630,11 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
des->errors += 1; des->errors += 1;
} }
// Since we will be adding the genvar value as a local parameter // These have all been checked so we just need to skip the actual
// to each instances scope. We need to make sure a parameter does // generation for these name conflicts. Not skipping these two will
// not already exist. // cause the compiler to have problems (assert, inf. loop, etc.).
texpr = container->get_parameter(loop_index, tmsb, tlsb); if (container->get_parameter(loop_index, tmsb, tlsb)) return false;
if (texpr != 0) { if (container->find_event(loop_index)) return false;
cerr << get_fileline() << ": error: genvar and "
"parameter in '" << container->fullname()
<< "' have the same name '" << loop_index << "'." << endl;
des->errors += 1;
return false;
}
genvar = init->value().as_long(); genvar = init->value().as_long();
delete init_ex; delete init_ex;
@ -672,7 +718,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
} }
// Clear the genvar_tmp field in the scope to reflect that the // Clear the genvar_tmp field in the scope to reflect that the
// genvar is no longer value for evaluating expressions. // genvar is no longer valid for evaluating expressions.
container->genvar_tmp = perm_string(); container->genvar_tmp = perm_string();
return true; return true;
@ -717,6 +763,14 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
return false; return false;
} }
// A generate "if" can not have the same name as a genvar.
if (container->find_genvar(scope_name)) {
cerr << get_fileline() << ": error: generate \"if\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "if" can not have the same name as a named event. // A generate "if" can not have the same name as a named event.
const NetEvent *event = container->find_event(scope_name); const NetEvent *event = container->find_event(scope_name);
if (event) { if (event) {
@ -855,6 +909,14 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
return false; return false;
} }
// A generate "case" can not have the same name as a genvar.
if (container->find_genvar(item->scope_name)) {
cerr << get_fileline() << ": error: generate \"case\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A generate "case" can not have the same name as a named event. // A generate "case" can not have the same name as a named event.
const NetEvent *event = container->find_event(item->scope_name); const NetEvent *event = container->find_event(item->scope_name);
if (event) { if (event) {
@ -895,7 +957,8 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container) bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
{ {
hname_t use_name (scope_name); hname_t use_name (scope_name);
// A generate "case" can not have the same name as another scope object. // A generate "block" can not have the same name as another scope
// object.
const NetScope *child = container->child(use_name); const NetScope *child = container->child(use_name);
if (child) { if (child) {
cerr << get_fileline() << ": error: generate \"block\" and "; cerr << get_fileline() << ": error: generate \"block\" and ";
@ -906,6 +969,14 @@ bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
return false; return false;
} }
// A generate "block" can not have the same name as a genvar.
if (container->find_genvar(scope_name)) {
cerr << get_fileline() << ": error: generate \"block\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "block" can not have the same name as a named event. // A generate "block" can not have the same name as a named event.
const NetEvent *event = container->find_event(scope_name); const NetEvent *event = container->find_event(scope_name);
if (event) { if (event) {
@ -1057,6 +1128,14 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
return; return;
} }
// A module instance can not have the same name as a genvar.
if (sc->find_genvar(get_name())) {
cerr << get_fileline() << ": error: module <" << mod->mod_name()
<< "> instance and genvar in '" << sc->fullname()
<< "' have the same name '" << get_name() << "'." << endl;
des->errors += 1;
}
// A module instance can not have the same name as a parameter. // A module instance can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb; const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = sc->get_parameter(get_name(), ex_msb, ex_lsb); const NetExpr *parm = sc->get_parameter(get_name(), ex_msb, ex_lsb);
@ -1314,6 +1393,14 @@ void PEvent::elaborate_scope(Design*des, NetScope*scope) const
des->errors += 1; des->errors += 1;
} }
// A named event can not have the same name as a genvar.
if (scope->find_genvar(name_)) {
cerr << get_fileline() << ": error: named event and "
<< "genvar in '" << scope->fullname()
<< "' have the same name '" << name_ << "'." << endl;
des->errors += 1;
}
// A named event can not have the same name as a parameter. // A named event can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb; const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter(name_, ex_msb, ex_lsb); const NetExpr *parm = scope->get_parameter(name_, ex_msb, ex_lsb);
@ -1416,6 +1503,14 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
return; return;
} }
// A named block can not have the same name as a genvar.
if (scope->find_genvar(pscope_name())) {
cerr << get_fileline() << ": error: named block and "
"genvar in '" << scope->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A named block can not have the same name as a parameter. // A named block can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb; const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter(pscope_name(), ex_msb, const NetExpr *parm = scope->get_parameter(pscope_name(), ex_msb,

View File

@ -878,6 +878,14 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
cerr << " in '" << scope->fullname() cerr << " in '" << scope->fullname()
<< "' have the same name '" << name_ << "'." << endl; << "' have the same name '" << name_ << "'." << endl;
des->errors += 1; des->errors += 1;
}
// A signal can not have the same name as a genvar.
const LineInfo *genvar = scope->find_genvar(name_);
if (genvar) {
cerr << get_fileline() << ": error: signal and genvar in '"
<< scope->fullname() << "' have the same name '" << name_
<< "'." << endl;
des->errors += 1;
} }
// A signal can not have the same name as a parameter. // A signal can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb; const NetExpr *ex_msb, *ex_lsb;

View File

@ -1161,16 +1161,6 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
if (local_errors > 0) return 0; if (local_errors > 0) return 0;
// Handle the special case that the repeat expression is
// zero. In this case, just return a 0 value with the expected
// width.
if (repeat_val == 0) {
verinum val (verinum::V0, expr_width());
NetEConst*res = new NetEConst(val);
res->set_width(val.len());
return res;
}
// At this point, the "gap" is the width of a single repeat of // At this point, the "gap" is the width of a single repeat of
// the concatenation. The total width of the result is the gap // the concatenation. The total width of the result is the gap
// times the repeat count. // times the repeat count.

View File

@ -722,25 +722,35 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
unsigned nparms = parms_.count(); unsigned nparms = parms_.count();
NetNet**tmp = new NetNet*[parms_.count()]; NetNet**tmp = new NetNet*[parms_.count()];
bool flag = true; bool flag = true;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
if (parms_[idx]->expr_width() == 0) { if (parms_[idx]->expr_width() == 0) {
tmp[idx] = 0; /* We need to synthesize a replication of zero. */
tmp[idx] = parms_[idx]->synthesize(des, scope, root);
assert(tmp[idx] == 0);
nparms -= 1; nparms -= 1;
} else { } else {
tmp[idx] = parms_[idx]->synthesize(des, scope, root); tmp[idx] = parms_[idx]->synthesize(des, scope, root);
if (tmp[idx] == 0) flag = false; if (tmp[idx] == 0) flag = false;
/* Set the data type to the first one found. */
if (data_type == IVL_VT_NO_TYPE) {
data_type = tmp[idx]->data_type();
}
} }
} }
if (flag == false) return 0; if (flag == false) return 0;
ivl_assert(*this, tmp[0]); ivl_assert(*this, data_type != IVL_VT_NO_TYPE);
/* If this is a replication of zero just return 0. */
if (expr_width() == 0) return 0;
/* Make a NetNet object to carry the output vector. */ /* Make a NetNet object to carry the output vector. */
perm_string path = scope->local_symbol(); perm_string path = scope->local_symbol();
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width()); NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
osig->local_flag(true); osig->local_flag(true);
osig->data_type(tmp[0]->data_type()); osig->data_type(data_type);
NetConcat*concat = new NetConcat(scope, scope->local_symbol(), NetConcat*concat = new NetConcat(scope, scope->local_symbol(),
osig->vector_width(), osig->vector_width(),

View File

@ -457,7 +457,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
<IFCCOMMENT>\n\r | <IFCCOMMENT>\n\r |
<IFCCOMMENT>\r\n | <IFCCOMMENT>\r\n |
<IFCCOMMENT>\n | <IFCCOMMENT>\n |
<IFCCOMMENT>\r { istack->lineno += 1; } <IFCCOMMENT>\r { istack->lineno += 1; fputc('\n', yyout); }
<IFCCOMMENT>"*/" { BEGIN(comment_enter); } <IFCCOMMENT>"*/" { BEGIN(comment_enter); }
<IFDEF_FALSE,IFDEF_SUPR>[^\r\n] { } <IFDEF_FALSE,IFDEF_SUPR>[^\r\n] { }

View File

@ -107,6 +107,8 @@ W [ \t\b\f\r]+
S [afpnumkKMGT] S [afpnumkKMGT]
TU [munpf]
%% %%
/* Recognize the various line directives. */ /* Recognize the various line directives. */
@ -248,6 +250,15 @@ S [afpnumkKMGT]
in_UDP = false; in_UDP = false;
break; break;
/* Translate these to checks if we already have or are
* outside the declaration region. */
case K_timeunit:
if (have_timeunit_decl) rc = K_timeunit_check;
break;
case K_timeprecision:
if (have_timeprec_decl) rc = K_timeprecision_check;
break;
default: default:
yylval.text = 0; yylval.text = 0;
break; break;
@ -323,6 +334,13 @@ S [afpnumkKMGT]
based_size = yylval.number->as_ulong(); based_size = yylval.number->as_ulong();
return DEC_NUMBER; } return DEC_NUMBER; }
/* This rule handles scaled time values for SystemVerilog. */
[0-9][0-9_]*(\.[0-9][0-9_]*)?{TU}?s {
if(gn_system_verilog_flag) {
yylval.text = strdupnew(yytext);
return TIME_LITERAL;
} else REJECT; }
/* These rules handle the scaled real literals from Verilog-AMS. The /* These rules handle the scaled real literals from Verilog-AMS. The
value is a number with a single letter scale factor. If value is a number with a single letter scale factor. If
verilog-ams is not enabled, then reject this rule. If it is verilog-ams is not enabled, then reject this rule. If it is
@ -1205,6 +1223,13 @@ static void process_timescale(const char*txt)
return; return;
} }
/* The time unit must be greater than or equal to the precision. */
if (unit < prec) {
VLerror(yylloc, "error: `timescale unit must not be less than "
"the precision.");
return;
}
pform_set_timescale(unit, prec, yylloc.text, yylloc.first_line); pform_set_timescale(unit, prec, yylloc.text, yylloc.first_line);
} }

View File

@ -162,6 +162,8 @@ tan, GN_KEYWORDS_VAMS_2_3, K_tan
tanh, GN_KEYWORDS_VAMS_2_3, K_tanh tanh, GN_KEYWORDS_VAMS_2_3, K_tanh
task, GN_KEYWORDS_1364_1995, K_task task, GN_KEYWORDS_1364_1995, K_task
time, GN_KEYWORDS_1364_1995, K_time time, GN_KEYWORDS_1364_1995, K_time
timeprecision, GN_KEYWORDS_1364_1995, K_timeprecision
timeunit, GN_KEYWORDS_1364_1995, K_timeunit
tran, GN_KEYWORDS_1364_1995, K_tran tran, GN_KEYWORDS_1364_1995, K_tran
tranif0, GN_KEYWORDS_1364_1995, K_tranif0 tranif0, GN_KEYWORDS_1364_1995, K_tranif0
tranif1, GN_KEYWORDS_1364_1995, K_tranif1 tranif1, GN_KEYWORDS_1364_1995, K_tranif1

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -257,15 +257,13 @@ ivl_variable_type_t NetEBMinMax::expr_type() const
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r) NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r)
{ {
if (expr_type() == IVL_VT_REAL) if (expr_type() == IVL_VT_REAL) {
expr_width(1); expr_width(1);
else
expr_width(l->expr_width() + r->expr_width());
if (expr_type() == IVL_VT_REAL)
cast_signed(true); cast_signed(true);
else } else {
expr_width(l->expr_width() + r->expr_width());
cast_signed(l->has_sign() && r->has_sign()); cast_signed(l->has_sign() && r->has_sign());
}
} }
NetEBMult::~NetEBMult() NetEBMult::~NetEBMult()
@ -294,8 +292,8 @@ NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r)
{ {
assert(op__ == 'p'); assert(op__ == 'p');
/* This is incorrect! a * (2^b - 1) is close. */ /* You could need up to a * (2^b - 1) bits. */
expr_width(l->expr_width()+r->expr_width()); expr_width(l->expr_width());
cast_signed(l->has_sign() || r->has_sign()); cast_signed(l->has_sign() || r->has_sign());
} }
@ -438,6 +436,7 @@ NetECReal::NetECReal(const verireal&val)
: value_(val) : value_(val)
{ {
expr_width(1); expr_width(1);
cast_signed(true);
} }
NetECReal::~NetECReal() NetECReal::~NetECReal()

View File

@ -395,6 +395,30 @@ NetEvent* NetScope::find_event(perm_string name)
return 0; return 0;
} }
// We only add genvars to a module scope, so we do not need to search
// for the module scope here.
void NetScope::add_genvar(perm_string name, LineInfo *li)
{
genvars_[name] = li;
}
LineInfo* NetScope::find_genvar(perm_string name)
{
// genvars are only added to the module so we need to find it
// if we are in a sub scope.
NetScope *scope = this;
while (scope->type() != NetScope::MODULE) {
scope = scope->parent();
assert(scope != NULL);
}
if (scope->genvars_.find(name) != scope->genvars_.end()) {
return scope->genvars_[name];
}
return 0;
}
void NetScope::add_signal(NetNet*net) void NetScope::add_signal(NetNet*net)
{ {
signals_map_[net->name()]=net; signals_map_[net->name()]=net;

View File

@ -720,6 +720,9 @@ class NetScope : public Attrib {
void rem_event(NetEvent*); void rem_event(NetEvent*);
NetEvent*find_event(perm_string name); NetEvent*find_event(perm_string name);
/* These methods add or find a genvar that lives in this scope. */
void add_genvar(perm_string name, LineInfo *li);
LineInfo* find_genvar(perm_string name);
/* These methods manage signals. The add_ and rem_signal /* These methods manage signals. The add_ and rem_signal
methods are used by the NetNet objects to make themselves methods are used by the NetNet objects to make themselves
@ -899,6 +902,8 @@ class NetScope : public Attrib {
NetEvent *events_; NetEvent *events_;
map<perm_string,LineInfo*> genvars_;
typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t; typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t;
std::map <perm_string,NetNet*> signals_map_; std::map <perm_string,NetNet*> signals_map_;
perm_string module_name_; perm_string module_name_;

46
parse.y
View File

@ -35,6 +35,9 @@ class PSpecPath;
extern void lex_start_table(); extern void lex_start_table();
extern void lex_end_table(); extern void lex_end_table();
bool have_timeunit_decl = false;
bool have_timeprec_decl = false;
static svector<PExpr*>* param_active_range = 0; static svector<PExpr*>* param_active_range = 0;
static bool param_active_signed = false; static bool param_active_signed = false;
static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC;
@ -218,7 +221,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
list<index_component_t> *dimensions; list<index_component_t> *dimensions;
}; };
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING %token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
%token <discipline> DISCIPLINE_IDENTIFIER %token <discipline> DISCIPLINE_IDENTIFIER
%token <text> PATHPULSE_IDENTIFIER %token <text> PATHPULSE_IDENTIFIER
%token <number> BASED_NUMBER DEC_NUMBER %token <number> BASED_NUMBER DEC_NUMBER
@ -270,6 +273,9 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
/* The new tokens from 1800-2005. */ /* The new tokens from 1800-2005. */
%token K_always_comb K_always_ff K_always_latch K_assert %token K_always_comb K_always_ff K_always_latch K_assert
%token K_timeprecision K_timeunit
/* Fake tokens that are passed once we have an initial token. */
%token K_timeprecision_check K_timeunit_check
/* The new tokens for Verilog-AMS 2.3. */ /* The new tokens for Verilog-AMS 2.3. */
%token K_abs K_abstol K_access K_acos K_acosh K_analog K_asin K_asinh %token K_abs K_abstol K_access K_acos K_acosh K_analog K_asin K_asinh
@ -728,6 +734,10 @@ description
delete[] $3; delete[] $3;
delete[] $5; delete[] $5;
} }
| K_timeunit TIME_LITERAL ';'
{ pform_set_timeunit($2, false, false); }
| K_timeprecision TIME_LITERAL ';'
{ pform_set_timeprecision($2, false, false); }
; ;
/* The discipline and nature declarations used to take no ';' after /* The discipline and nature declarations used to take no ';' after
@ -1975,6 +1985,25 @@ cont_assign_list
{ $$ = $1; } { $$ = $1; }
; ;
/* We allow zero, one or two unique declarations. */
local_timeunit_prec_decl_opt
: /* Empty */
| local_timeunit_prec_decl
| local_timeunit_prec_decl local_timeunit_prec_decl
;
/* By setting the appropriate have_time???_decl we allow only
one declaration of each type in this module. */
local_timeunit_prec_decl
: K_timeunit TIME_LITERAL ';'
{ pform_set_timeunit($2, true, false);
have_timeunit_decl = true;
}
| K_timeprecision TIME_LITERAL ';'
{ pform_set_timeprecision($2, true, false);
have_timeprec_decl = true;
}
;
/* This is the global structure of a module. A module in a start /* This is the global structure of a module. A module in a start
section, with optional ports, then an optional list of module section, with optional ports, then an optional list of module
@ -1986,7 +2015,12 @@ module : attribute_list_opt module_start IDENTIFIER
module_port_list_opt module_port_list_opt
module_attribute_foreign ';' module_attribute_foreign ';'
{ pform_module_set_ports($6); } { pform_module_set_ports($6); }
module_item_list_opt local_timeunit_prec_decl_opt
{ have_timeunit_decl = true; // Every thing past here is
have_timeprec_decl = true; // a check!
pform_check_timeunit_prec();
}
module_item_list_opt
K_endmodule K_endmodule
{ Module::UCDriveType ucd; { Module::UCDriveType ucd;
switch (uc_drive) { switch (uc_drive) {
@ -2003,8 +2037,9 @@ module : attribute_list_opt module_start IDENTIFIER
} }
pform_endmodule($3, in_celldefine, ucd); pform_endmodule($3, in_celldefine, ucd);
delete[]$3; delete[]$3;
have_timeunit_decl = false; // We will allow decls again.
have_timeprec_decl = false;
} }
; ;
module_start : K_module | K_macromodule ; module_start : K_module | K_macromodule ;
@ -2463,6 +2498,11 @@ module_item
} }
| KK_attribute '(' error ')' ';' | KK_attribute '(' error ')' ';'
{ yyerror(@1, "error: Malformed $attribute parameter list."); } { yyerror(@1, "error: Malformed $attribute parameter list."); }
| K_timeunit_check TIME_LITERAL ';'
{ pform_set_timeunit($2, true, true); }
| K_timeprecision_check TIME_LITERAL ';'
{ pform_set_timeprecision($2, true, true); }
; ;
automatic_opt automatic_opt

View File

@ -70,5 +70,11 @@ extern unsigned long based_size;
extern bool in_celldefine; extern bool in_celldefine;
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 }; enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
extern UCDriveType uc_drive; extern UCDriveType uc_drive;
/*
* Flags to control if we are declaring or checking a timeunit or
* timeprecision statement.
*/
extern bool have_timeunit_decl;
extern bool have_timeprec_decl;
#endif #endif

189
pform.cc
View File

@ -73,6 +73,21 @@ static NetNet::Type pform_default_nettype = NetNet::WIRE;
static int pform_time_unit; static int pform_time_unit;
static int pform_time_prec; static int pform_time_prec;
/* These two flags check the initial timeprecision and timeunit
* declaration inside a module.
*/
static bool tp_decl_flag = false;
static bool tu_decl_flag = false;
/*
* Flags used to set time_from_timescale based on timeunit and
* timeprecision.
*/
static bool tu_global_flag = false;
static bool tp_global_flag = false;
static bool tu_local_flag = false;
static bool tp_local_flag = false;
static char*pform_timescale_file = 0; static char*pform_timescale_file = 0;
static unsigned pform_timescale_line; static unsigned pform_timescale_line;
@ -116,7 +131,7 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
if (pform_cur_generate->tasks.find(task->pscope_name()) != if (pform_cur_generate->tasks.find(task->pscope_name()) !=
pform_cur_generate->tasks.end()) { pform_cur_generate->tasks.end()) {
cerr << task->get_fileline() << ": error: duplicate " cerr << task->get_fileline() << ": error: duplicate "
" definition for task '" << name << "' in '" "definition for task '" << name << "' in '"
<< pform_cur_module->mod_name() << "' (generate)." << pform_cur_module->mod_name() << "' (generate)."
<< endl; << endl;
error_count += 1; error_count += 1;
@ -292,6 +307,9 @@ void pform_set_timescale(int unit, int prec,
assert(unit >= prec); assert(unit >= prec);
pform_time_unit = unit; pform_time_unit = unit;
pform_time_prec = prec; pform_time_prec = prec;
/* A `timescale clears the timeunit/timeprecision state. */
tu_global_flag = false;
tp_global_flag = false;
if (pform_timescale_file) { if (pform_timescale_file) {
free(pform_timescale_file); free(pform_timescale_file);
@ -339,6 +357,139 @@ void pform_set_timescale(int unit, int prec,
} }
} }
/*
* Get a timeunit or timeprecision value from a string. This is
* similar to the code in lexor.lex for the `timescale directive.
*/
static bool get_time_unit_prec(const char*cp, int &res, bool is_unit)
{
/* We do not support a '_' in these time constants. */
if (strchr(cp, '_')) {
if (is_unit) {
VLerror(yylloc, "Invalid timeunit constant ('_' is not "
"supported).");
} else {
VLerror(yylloc, "Invalid timeprecision constant ('_' is not "
"supported).");
}
return true;
}
/* Check for the 1 digit. */
if (*cp != '1') {
if (is_unit) {
VLerror(yylloc, "Invalid timeunit constant (1st digit).");
} else {
VLerror(yylloc, "Invalid timeprecision constant (1st digit).");
}
return true;
}
cp += 1;
/* Check the number of zeros after the 1. */
res = strspn(cp, "0");
if (res > 2) {
if (is_unit) {
VLerror(yylloc, "Invalid timeunit constant (number of "
"zeros).");
} else {
VLerror(yylloc, "Invalid timeprecision constant (number of "
"zeros).");
}
return true;
}
cp += res;
/* Now process the scaling string. */
if (strncmp("s", cp, 1) == 0) {
res -= 0;
return false;
} else if (strncmp("ms", cp, 2) == 0) {
res -= 3;
return false;
} else if (strncmp("us", cp, 2) == 0) {
res -= 6;
return false;
} else if (strncmp("ns", cp, 2) == 0) {
res -= 9;
return false;
} else if (strncmp("ps", cp, 2) == 0) {
res -= 12;
return false;
} else if (strncmp("fs", cp, 2) == 0) {
res -= 15;
return false;
}
ostringstream msg;
msg << "Invalid ";
if (is_unit) msg << "timeunit";
else msg << "timeprecision";
msg << " scale '" << cp << "'.";
VLerror(msg.str().c_str());
return true;
}
void pform_set_timeunit(const char*txt, bool in_module, bool only_check)
{
int val;
if (get_time_unit_prec(txt, val, true)) return;
if (in_module) {
if (!only_check) {
pform_cur_module->time_unit = val;
tu_decl_flag = true;
tu_local_flag = true;
} else if (!tu_decl_flag) {
VLerror(yylloc, "error: repeat timeunit found and the "
"initial module timeunit is missing.");
return;
} else if (pform_cur_module->time_unit != val) {
VLerror(yylloc, "error: repeat timeunit does not match "
"the initial module timeunit "
"declaration.");
return;
}
} else {
tu_global_flag = true;
pform_time_unit = val;
}
}
void pform_set_timeprecision(const char*txt, bool in_module, bool only_check)
{
int val;
if (get_time_unit_prec(txt, val, false)) return;
if (in_module) {
if (!only_check) {
pform_cur_module->time_precision = val;
tp_decl_flag = true;
tp_local_flag = true;
} else if (!tp_decl_flag) {
VLerror(yylloc, "error: repeat timeprecision found and the "
"initial module timeprecision is missing.");
return;
} else if (pform_cur_module->time_precision != val) {
VLerror(yylloc, "error: repeat timeprecision does not match "
"the initial module timeprecision "
"declaration.");
return;
}
} else {
pform_time_prec = val;
tp_global_flag=true;
}
}
verinum* pform_verinum_with_size(verinum*siz, verinum*val, verinum* pform_verinum_with_size(verinum*siz, verinum*val,
const char*file, unsigned lineno) const char*file, unsigned lineno)
@ -397,8 +548,12 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno,
perm_string lex_name = lex_strings.make(name); perm_string lex_name = lex_strings.make(name);
pform_cur_module = new Module(lex_name); pform_cur_module = new Module(lex_name);
/* Set the local time unit/precision to the global value. */
pform_cur_module->time_unit = pform_time_unit; pform_cur_module->time_unit = pform_time_unit;
pform_cur_module->time_precision = pform_time_prec; pform_cur_module->time_precision = pform_time_prec;
tu_local_flag = tu_global_flag;
tp_local_flag = tp_global_flag;
/* If we have a timescale file then the time information is from /* If we have a timescale file then the time information is from
* a timescale directive. */ * a timescale directive. */
pform_cur_module->time_from_timescale = pform_timescale_file != 0; pform_cur_module->time_from_timescale = pform_timescale_file != 0;
@ -431,6 +586,22 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno,
} }
} }
/*
* In SystemVerilog we can have separate timeunit and timeprecision
* declarations. We need to have the values worked out by time this
* task is called.
*/
void pform_check_timeunit_prec()
{
assert(pform_cur_module);
if (gn_system_verilog_flag && (pform_cur_module->time_unit <
pform_cur_module->time_precision)) {
VLerror("error: a timeprecision is missing or is too "
"large!");
} else assert(pform_cur_module->time_unit >=
pform_cur_module->time_precision);
}
/* /*
* This function is called by the parser to make a simple port * This function is called by the parser to make a simple port
* reference. This is a name without a .X(...), so the internal name * reference. This is a name without a .X(...), so the internal name
@ -471,6 +642,9 @@ void pform_endmodule(const char*name, bool in_celldefine,
Module::UCDriveType uc_drive) Module::UCDriveType uc_drive)
{ {
assert(pform_cur_module); assert(pform_cur_module);
pform_cur_module->time_from_timescale = (tu_local_flag &&
tp_local_flag) ||
(pform_timescale_file != 0);
perm_string mod_name = pform_cur_module->mod_name(); perm_string mod_name = pform_cur_module->mod_name();
assert(strcmp(name, mod_name) == 0); assert(strcmp(name, mod_name) == 0);
pform_cur_module->is_cell = in_celldefine; pform_cur_module->is_cell = in_celldefine;
@ -495,6 +669,10 @@ void pform_endmodule(const char*name, bool in_celldefine,
ivl_assert(*pform_cur_module, lexical_scope == 0); ivl_assert(*pform_cur_module, lexical_scope == 0);
pform_cur_module = 0; pform_cur_module = 0;
tp_decl_flag = false;
tu_decl_flag = false;
tu_local_flag = false;
tp_local_flag = false;
} }
void pform_genvars(const struct vlltype&li, list<perm_string>*names) void pform_genvars(const struct vlltype&li, list<perm_string>*names)
@ -503,7 +681,14 @@ void pform_genvars(const struct vlltype&li, list<perm_string>*names)
for (cur = names->begin(); cur != names->end() ; *cur++) { for (cur = names->begin(); cur != names->end() ; *cur++) {
LineInfo*lni = new LineInfo(); LineInfo*lni = new LineInfo();
FILE_NAME(lni, li); FILE_NAME(lni, li);
pform_cur_module->genvars[*cur] = lni; if (pform_cur_module->genvars.find(*cur) !=
pform_cur_module->genvars.end()) {
cerr << lni->get_fileline() << ": error: duplicate "
"definition for genvar '" << *cur << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
delete lni;
} else pform_cur_module->genvars[*cur] = lni;
} }
delete names; delete names;

View File

@ -143,6 +143,7 @@ extern PWire* pform_get_wire_in_scope(perm_string name);
*/ */
extern void pform_startmodule(const char*, const char*file, unsigned lineno, extern void pform_startmodule(const char*, const char*file, unsigned lineno,
svector<named_pexpr_t*>*attr); svector<named_pexpr_t*>*attr);
extern void pform_check_timeunit_prec();
extern void pform_module_set_ports(vector<Module::port_t*>*); extern void pform_module_set_ports(vector<Module::port_t*>*);
/* This function is used to support the port definition in a /* This function is used to support the port definition in a
@ -409,4 +410,11 @@ extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
char*name, char*branch); char*name, char*branch);
/*
* Tasks to set the timeunit or timeprecision for SystemVerilog.
*/
extern void pform_set_timeunit(const char*txt, bool in_module, bool only_check);
extern void pform_set_timeprecision(const char*txt, bool in_module,
bool only_check);
#endif #endif

View File

@ -199,7 +199,7 @@ void dll_target::expr_concat(const NetEConcat*net)
cur->type_ = IVL_EX_CONCAT; cur->type_ = IVL_EX_CONCAT;
cur->value_ = IVL_VT_VECTOR; cur->value_ = IVL_VT_VECTOR;
cur->width_ = net->expr_width(); cur->width_ = net->expr_width();
cur->signed_ = 0; cur->signed_ = net->has_sign() ? 1 : 0;
cur->u_.concat_.rept = net->repeat(); cur->u_.concat_.rept = net->repeat();
cur->u_.concat_.parms = net->nparms(); cur->u_.concat_.parms = net->nparms();

View File

@ -1619,82 +1619,118 @@ static struct vector_info draw_binary_expr(ivl_expr_t exp,
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid, static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
int stuff_ok_flag) int stuff_ok_flag)
{ {
unsigned off, rep; unsigned off, rep, expr_wid, concat_wid, num_sube, idx;
struct vector_info res; struct vector_info res;
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1; int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
/* Allocate a vector to hold the result. */ /* Find out how wide the base concatenation expression is. */
res.base = allocate_vector(wid); num_sube = ivl_expr_parms(exp);
res.wid = wid; expr_wid = 0;
if (res.base == 0) { for (idx = 0 ; idx < num_sube; idx += 1) {
fprintf(stderr, "%s:%u: vvp.tgt error: " expr_wid += ivl_expr_width(ivl_expr_parm(exp, idx));
"Unable to allocate %u thread bits "
"for result of concatenation.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
} }
/* Get the repeat count. This must be a constant that has been /* Get the repeat count. This must be a constant that has been
evaluated at compile time. The operands will be repeated to evaluated at compile time. The operands will be repeated to
form the result. */ form the result. */
rep = ivl_expr_repeat(exp); rep = ivl_expr_repeat(exp);
off = 0;
while (rep > 0) { /* Allocate a vector to hold the result. */
if (rep == 0) {
/* If the replication is zero we need to allocate temporary
* space to build the concatenation. */
res.base = allocate_vector(expr_wid);
res.wid = expr_wid;
} else {
res.base = allocate_vector(wid);
res.wid = wid;
}
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of concatenation.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp),
rep ? wid : expr_wid);
vvp_errors += 1;
}
/* Each repeat, evaluate the sub-expressions, from lsb /* If the result is the right size we can just build this in place. */
to msb, and copy each into the result vector. The concat_wid = rep*expr_wid;
expressions are arranged in the concatenation from if (concat_wid <= wid) {
MSB to LSB, to go through them backwards. off = 0;
/* Evaluate the base expression. */
Abort the loop if the result vector gets filled up. */ for (idx = num_sube; idx > 0; idx -= 1) {
unsigned idx = ivl_expr_parms(exp);
while ((idx > 0) && (off < wid)) {
ivl_expr_t arg = ivl_expr_parm(exp, idx-1); ivl_expr_t arg = ivl_expr_parm(exp, idx-1);
unsigned awid = ivl_expr_width(arg); unsigned awid = ivl_expr_width(arg);
unsigned trans;
struct vector_info avec; struct vector_info avec;
assert(awid+off <= expr_wid);
/* Try to locate the subexpression in the /* Try to locate the subexpression in the
lookaside map. */ * lookaside map and use it when available. */
avec.base = allocate_vector_exp(arg, awid, alloc_exclusive); avec.base = allocate_vector_exp(arg, awid, alloc_exclusive);
avec.wid = awid; avec.wid = awid;
trans = awid;
if ((off + awid) > wid)
trans = wid - off;
if (avec.base != 0) { if (avec.base != 0) {
assert(awid == avec.wid); assert(awid == avec.wid);
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse "
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse calculated expression\n", "calculated expression.\n",
res.base+off, res.base+off, avec.base, awid);
avec.base, trans);
clr_vector(avec); clr_vector(avec);
} else { } else {
struct vector_info dest; struct vector_info dest;
dest.base = res.base+off; dest.base = res.base+off;
dest.wid = trans; dest.wid = awid;
draw_eval_expr_dest(arg, dest, 0); draw_eval_expr_dest(arg, dest, 0);
} }
off += awid;
idx -= 1;
off += trans;
assert(off <= wid);
} }
rep -= 1;
}
/* Pad the result with 0, if necessary. */ /* Now repeat the expression as needed. */
if (off < wid) { if (rep != 0) {
fprintf(vvp_out, " %%mov %u, 0, %u;\n", rep -= 1;
res.base+off, wid-off); } else {
/* Clear the temporary space and return nothing.
* This will be caught in draw_eval_expr_dest()
* and dropped. */
clr_vector(res);
res.base = 0;
res.wid = 0;
}
while (rep > 0) {
fprintf(vvp_out, " %%mov %u, %u, %u; Repetition %u\n",
res.base+expr_wid*rep, res.base, expr_wid,
rep+1);
rep -= 1;
}
/* Pad the expression when needed. */
if (wid > concat_wid) {
/* We can get a signed concatenation with $signed({...}). */
if (ivl_expr_signed(exp)) {
unsigned base = res.base+concat_wid-1;
for (idx = 1; idx <= wid-concat_wid; idx += 1) {
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
base+idx, base);
}
} else {
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
res.base+concat_wid, wid-concat_wid);
}
}
} else {
/* The concatenation is too big for the result so draw it
* at full width and then copy the bits that are needed. */
struct vector_info full_res;
full_res = draw_concat_expr(exp, concat_wid, stuff_ok_flag);
assert(full_res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
full_res.base, wid);
clr_vector(full_res);
} }
/* Save the accumulated result in the lookaside map. */ /* Save the accumulated result in the lookaside map. */
@ -2843,8 +2879,9 @@ static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
tmp = draw_eval_expr_wid(exp, dest.wid, stuff_ok_flag); tmp = draw_eval_expr_wid(exp, dest.wid, stuff_ok_flag);
assert(tmp.wid == dest.wid); assert(tmp.wid == dest.wid);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", /* If the replication is 0 we can have a zero width, so skip it. */
dest.base, tmp.base, dest.wid); if (dest.wid) fprintf(vvp_out, " %%mov %u, %u, %u;\n",
dest.base, tmp.base, dest.wid);
if (tmp.base >= 8) if (tmp.base >= 8)
save_expression_lookaside(tmp.base, exp, tmp.wid); save_expression_lookaside(tmp.base, exp, tmp.wid);

View File

@ -240,6 +240,14 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv)
vpi_get_value(item, &val); vpi_get_value(item, &val);
fmtp = fmt = strdup(val.value.str); fmtp = fmt = strdup(val.value.str);
/* See if we are at EOF before we even start. */
ch = byte_getc(src);
if (ch == EOF) {
rc = EOF;
match_fail = 1;
}
byte_ungetc(src, ch);
while ( fmtp && *fmtp != 0 && !match_fail) { while ( fmtp && *fmtp != 0 && !match_fail) {
if (isspace(*fmtp)) { if (isspace(*fmtp)) {

View File

@ -152,11 +152,25 @@ struct __vpiArrayVthrA {
} }
}; };
/* Get the array word size. This has only been checked for reg arrays. */ /* Get the array word size. */
unsigned get_array_word_size(vvp_array_t array) unsigned get_array_word_size(vvp_array_t array)
{ {
assert(array->vals4); unsigned width;
return array->vals_width;
assert(array->array_count > 0);
/* For a net array we need to get the width from the first element. */
if (array->nets) {
assert(array->vals4 == 0 && array->valsr == 0);
struct __vpiSignal*vsig = vpip_signal_from_handle(array->nets[0]);
assert(vsig);
width = vpip_size(vsig);
/* For a variable array we can get the width from vals_width. */
} else {
assert(array->vals4 || array->valsr);
width = array->vals_width;
}
return width;
} }
bool is_net_array(vpiHandle obj) bool is_net_array(vpiHandle obj)
@ -665,7 +679,7 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
return 0; // Not implemented for now! return 0; // Not implemented for now!
case vpiSize: case vpiSize:
return parent->vals_width; return get_array_word_size(parent);
case vpiLeftRange: case vpiLeftRange:
return parent->msb.value; return parent->msb.value;
@ -746,8 +760,8 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
vpip_real_get_value(tmp, value); vpip_real_get_value(tmp, value);
} else { } else {
vvp_vector4_t tmp = array_get_word(parent, index); vvp_vector4_t tmp = array_get_word(parent, index);
vpip_vec4_get_value(tmp, parent->vals_width, parent->signed_flag, unsigned width = get_array_word_size(parent);
value); vpip_vec4_get_value(tmp, width, parent->signed_flag, value);
} }
} }
@ -766,7 +780,8 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
double val = real_from_vpi_value(vp); double val = real_from_vpi_value(vp);
array_set_word(parent, index, val); array_set_word(parent, index, val);
} else { } else {
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width); unsigned width = get_array_word_size(parent);
vvp_vector4_t val = vec4_from_vpi_value(vp, width);
array_set_word(parent, index, 0, val); array_set_word(parent, index, 0, val);
} }

View File

@ -195,6 +195,8 @@ struct vvp_fun_edge_state_s : public waitable_state_s {
vvp_fun_edge::vvp_fun_edge(edge_t e) vvp_fun_edge::vvp_fun_edge(edge_t e)
: edge_(e) : edge_(e)
{ {
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
bits_[idx] = BIT4_X;
} }
vvp_fun_edge::~vvp_fun_edge() vvp_fun_edge::~vvp_fun_edge()
@ -220,8 +222,6 @@ bool vvp_fun_edge::recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_fun_edge_sa::vvp_fun_edge_sa(edge_t e) vvp_fun_edge_sa::vvp_fun_edge_sa(edge_t e)
: vvp_fun_edge(e), threads_(0) : vvp_fun_edge(e), threads_(0)
{ {
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
bits_[idx] = BIT4_X;
} }
vvp_fun_edge_sa::~vvp_fun_edge_sa() vvp_fun_edge_sa::~vvp_fun_edge_sa()
@ -259,6 +259,7 @@ vvp_fun_edge_aa::~vvp_fun_edge_aa()
void vvp_fun_edge_aa::alloc_instance(vvp_context_t context) void vvp_fun_edge_aa::alloc_instance(vvp_context_t context)
{ {
vvp_set_context_item(context, context_idx_, new vvp_fun_edge_state_s); vvp_set_context_item(context, context_idx_, new vvp_fun_edge_state_s);
reset_instance(context);
} }
void vvp_fun_edge_aa::reset_instance(vvp_context_t context) void vvp_fun_edge_aa::reset_instance(vvp_context_t context)
@ -268,7 +269,7 @@ void vvp_fun_edge_aa::reset_instance(vvp_context_t context)
state->threads = 0; state->threads = 0;
for (unsigned idx = 0 ; idx < 4 ; idx += 1) for (unsigned idx = 0 ; idx < 4 ; idx += 1)
state->bits[idx] = BIT4_X; state->bits[idx] = bits_[idx];
} }
#ifdef CHECK_WITH_VALGRIND #ifdef CHECK_WITH_VALGRIND
@ -308,6 +309,7 @@ void vvp_fun_edge_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
recv_vec4(port, bit, context); recv_vec4(port, bit, context);
context = vvp_get_next_context(context); context = vvp_get_next_context(context);
} }
bits_[port.port()] = bit.value(0);
} }
} }
@ -324,6 +326,8 @@ struct vvp_fun_anyedge_state_s : public waitable_state_s {
vvp_fun_anyedge::vvp_fun_anyedge() vvp_fun_anyedge::vvp_fun_anyedge()
{ {
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
bitsr_[idx] = 0.0;
} }
vvp_fun_anyedge::~vvp_fun_anyedge() vvp_fun_anyedge::~vvp_fun_anyedge()
@ -369,8 +373,6 @@ bool vvp_fun_anyedge::recv_real_(vvp_net_ptr_t port, double bit,
vvp_fun_anyedge_sa::vvp_fun_anyedge_sa() vvp_fun_anyedge_sa::vvp_fun_anyedge_sa()
: threads_(0) : threads_(0)
{ {
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
bitsr_[idx] = 0.0;
} }
vvp_fun_anyedge_sa::~vvp_fun_anyedge_sa() vvp_fun_anyedge_sa::~vvp_fun_anyedge_sa()
@ -416,6 +418,7 @@ vvp_fun_anyedge_aa::~vvp_fun_anyedge_aa()
void vvp_fun_anyedge_aa::alloc_instance(vvp_context_t context) void vvp_fun_anyedge_aa::alloc_instance(vvp_context_t context)
{ {
vvp_set_context_item(context, context_idx_, new vvp_fun_anyedge_state_s); vvp_set_context_item(context, context_idx_, new vvp_fun_anyedge_state_s);
reset_instance(context);
} }
void vvp_fun_anyedge_aa::reset_instance(vvp_context_t context) void vvp_fun_anyedge_aa::reset_instance(vvp_context_t context)
@ -425,8 +428,8 @@ void vvp_fun_anyedge_aa::reset_instance(vvp_context_t context)
state->threads = 0; state->threads = 0;
for (unsigned idx = 0 ; idx < 4 ; idx += 1) { for (unsigned idx = 0 ; idx < 4 ; idx += 1) {
state->bits[idx].set_to_x(); state->bits[idx] = bits_[idx];
state->bitsr[idx] = 0.0; state->bitsr[idx] = bitsr_[idx];
} }
} }
@ -467,6 +470,7 @@ void vvp_fun_anyedge_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
recv_vec4(port, bit, context); recv_vec4(port, bit, context);
context = vvp_get_next_context(context); context = vvp_get_next_context(context);
} }
bits_[port.port()] = bit;
} }
} }
@ -487,6 +491,7 @@ void vvp_fun_anyedge_aa::recv_real(vvp_net_ptr_t port, double bit,
recv_real(port, bit, context); recv_real(port, bit, context);
context = vvp_get_next_context(context); context = vvp_get_next_context(context);
} }
bitsr_[port.port()] = bit;
} }
} }

View File

@ -141,6 +141,8 @@ class vvp_fun_edge : public vvp_net_fun_t, public waitable_hooks_s {
bool recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit, bool recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_bit4_t&old_bit, vthread_t&threads); vvp_bit4_t&old_bit, vthread_t&threads);
vvp_bit4_t bits_[4];
private: private:
edge_t edge_; edge_t edge_;
}; };
@ -165,7 +167,6 @@ class vvp_fun_edge_sa : public vvp_fun_edge {
private: private:
vthread_t threads_; vthread_t threads_;
vvp_bit4_t bits_[4];
}; };
/* /*
@ -214,6 +215,10 @@ class vvp_fun_anyedge : public vvp_net_fun_t, public waitable_hooks_s {
vvp_vector4_t&old_bits, vthread_t&threads); vvp_vector4_t&old_bits, vthread_t&threads);
bool recv_real_(vvp_net_ptr_t port, double bit, bool recv_real_(vvp_net_ptr_t port, double bit,
double&old_bits, vthread_t&threads); double&old_bits, vthread_t&threads);
vvp_vector4_t bits_[4];
// In case I'm a real-valued event.
double bitsr_[4];
}; };
/* /*
@ -235,9 +240,6 @@ class vvp_fun_anyedge_sa : public vvp_fun_anyedge {
private: private:
vthread_t threads_; vthread_t threads_;
vvp_vector4_t bits_[4];
// In case I'm a real-valued event.
double bitsr_[4];
}; };
/* /*

View File

@ -58,10 +58,15 @@ void vvp_fun_part_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
{ {
assert(port.port() == 0); assert(port.port() == 0);
if (val_ .eeq( bit )) vvp_vector4_t tmp (wid_, BIT4_X);
for (unsigned idx = 0 ; idx < wid_ ; idx += 1) {
if (idx + base_ < bit.size())
tmp.set_bit(idx, bit.value(base_+idx));
}
if (val_ .eeq( tmp ))
return; return;
val_ = bit; val_ = tmp;
if (net_ == 0) { if (net_ == 0) {
net_ = port.ptr(); net_ = port.ptr();
@ -94,13 +99,7 @@ void vvp_fun_part_sa::run_run()
{ {
vvp_net_t*ptr = net_; vvp_net_t*ptr = net_;
net_ = 0; net_ = 0;
ptr->send_vec4(val_, 0);
vvp_vector4_t res (wid_, BIT4_X);
for (unsigned idx = 0 ; idx < wid_ ; idx += 1) {
if (idx + base_ < val_.size())
res.set_bit(idx, val_.value(base_+idx));
}
ptr->send_vec4(res, 0);
} }
vvp_fun_part_aa::vvp_fun_part_aa(unsigned base, unsigned wid) vvp_fun_part_aa::vvp_fun_part_aa(unsigned base, unsigned wid)