Merge branch 'master' into vvp-net-out-rework
Conflicts: vvp/part.cc
This commit is contained in:
commit
bbc0ee0ad0
|
|
@ -134,6 +134,9 @@ extern bool gn_specify_blocks_flag;
|
|||
/* If this flag is true, then support/elaborate Verilog-AMS. */
|
||||
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
|
||||
is scalar and the net/register definition is vectored. */
|
||||
extern bool gn_io_range_error_flag;
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ static int t_version_only(void)
|
|||
}
|
||||
|
||||
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);
|
||||
rc = system(tmp);
|
||||
if (rc != 0) {
|
||||
|
|
|
|||
133
elab_scope.cc
133
elab_scope.cc
|
|
@ -174,6 +174,15 @@ static void elaborate_scope_parameters_(Design*des, NetScope*scope,
|
|||
for (mparm_it_t cur = parameters.begin()
|
||||
; 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -184,6 +193,15 @@ static void elaborate_scope_localparams_(Design*des, NetScope*scope,
|
|||
for (mparm_it_t cur = localparams.begin()
|
||||
; 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -249,6 +267,15 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope,
|
|||
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.
|
||||
const NetExpr *ex_msb, *ex_lsb;
|
||||
const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb,
|
||||
|
|
@ -296,6 +323,15 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope,
|
|||
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.
|
||||
const NetExpr *ex_msb, *ex_lsb;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// module introduces to the design. This loop elaborates the
|
||||
// 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
|
||||
// genvar statement.
|
||||
|
||||
// MISSING CODE!
|
||||
//
|
||||
// Also the genvar checks below need to be moved/changed
|
||||
// when this is implemented. They currently work, but do
|
||||
// not reference the genvar statement.
|
||||
if (container->find_genvar(loop_index) == 0) {
|
||||
cerr << get_fileline() << ": error: genvar is missing for "
|
||||
"generate \"loop\" variable '" << loop_index << "'."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're going to need a genvar...
|
||||
int genvar;
|
||||
|
|
@ -558,6 +601,15 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
des->errors += 1;
|
||||
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.
|
||||
const NetEvent *event = container->find_event(scope_name);
|
||||
if (event) {
|
||||
|
|
@ -578,17 +630,11 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
des->errors += 1;
|
||||
}
|
||||
|
||||
// Since we will be adding the genvar value as a local parameter
|
||||
// to each instances scope. We need to make sure a parameter does
|
||||
// not already exist.
|
||||
texpr = container->get_parameter(loop_index, tmsb, tlsb);
|
||||
if (texpr != 0) {
|
||||
cerr << get_fileline() << ": error: genvar and "
|
||||
"parameter in '" << container->fullname()
|
||||
<< "' have the same name '" << loop_index << "'." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
// These have all been checked so we just need to skip the actual
|
||||
// generation for these name conflicts. Not skipping these two will
|
||||
// cause the compiler to have problems (assert, inf. loop, etc.).
|
||||
if (container->get_parameter(loop_index, tmsb, tlsb)) return false;
|
||||
if (container->find_event(loop_index)) return false;
|
||||
|
||||
genvar = init->value().as_long();
|
||||
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
|
||||
// genvar is no longer value for evaluating expressions.
|
||||
// genvar is no longer valid for evaluating expressions.
|
||||
container->genvar_tmp = perm_string();
|
||||
|
||||
return true;
|
||||
|
|
@ -717,6 +763,14 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
|||
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.
|
||||
const NetEvent *event = container->find_event(scope_name);
|
||||
if (event) {
|
||||
|
|
@ -855,6 +909,14 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
|||
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.
|
||||
const NetEvent *event = container->find_event(item->scope_name);
|
||||
if (event) {
|
||||
|
|
@ -895,7 +957,8 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
|||
bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
|
||||
{
|
||||
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);
|
||||
if (child) {
|
||||
cerr << get_fileline() << ": error: generate \"block\" and ";
|
||||
|
|
@ -906,6 +969,14 @@ bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
|
|||
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.
|
||||
const NetEvent *event = container->find_event(scope_name);
|
||||
if (event) {
|
||||
|
|
@ -1057,6 +1128,14 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
|||
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.
|
||||
const NetExpr *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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
const NetExpr *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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
const NetExpr *ex_msb, *ex_lsb;
|
||||
const NetExpr *parm = scope->get_parameter(pscope_name(), ex_msb,
|
||||
|
|
|
|||
|
|
@ -878,6 +878,14 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
cerr << " in '" << scope->fullname()
|
||||
<< "' have the same name '" << name_ << "'." << endl;
|
||||
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.
|
||||
const NetExpr *ex_msb, *ex_lsb;
|
||||
|
|
|
|||
10
eval_tree.cc
10
eval_tree.cc
|
|
@ -1161,16 +1161,6 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
|
||||
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
|
||||
// the concatenation. The total width of the result is the gap
|
||||
// times the repeat count.
|
||||
|
|
|
|||
|
|
@ -722,25 +722,35 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
unsigned nparms = parms_.count();
|
||||
NetNet**tmp = new NetNet*[parms_.count()];
|
||||
bool flag = true;
|
||||
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
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;
|
||||
} else {
|
||||
tmp[idx] = parms_[idx]->synthesize(des, scope, root);
|
||||
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;
|
||||
|
||||
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. */
|
||||
perm_string path = scope->local_symbol();
|
||||
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
|
||||
osig->local_flag(true);
|
||||
osig->data_type(tmp[0]->data_type());
|
||||
osig->data_type(data_type);
|
||||
|
||||
NetConcat*concat = new NetConcat(scope, scope->local_symbol(),
|
||||
osig->vector_width(),
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
|||
<IFCCOMMENT>\n\r |
|
||||
<IFCCOMMENT>\r\n |
|
||||
<IFCCOMMENT>\n |
|
||||
<IFCCOMMENT>\r { istack->lineno += 1; }
|
||||
<IFCCOMMENT>\r { istack->lineno += 1; fputc('\n', yyout); }
|
||||
<IFCCOMMENT>"*/" { BEGIN(comment_enter); }
|
||||
|
||||
<IFDEF_FALSE,IFDEF_SUPR>[^\r\n] { }
|
||||
|
|
|
|||
25
lexor.lex
25
lexor.lex
|
|
@ -107,6 +107,8 @@ W [ \t\b\f\r]+
|
|||
|
||||
S [afpnumkKMGT]
|
||||
|
||||
TU [munpf]
|
||||
|
||||
%%
|
||||
|
||||
/* Recognize the various line directives. */
|
||||
|
|
@ -248,6 +250,15 @@ S [afpnumkKMGT]
|
|||
in_UDP = false;
|
||||
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:
|
||||
yylval.text = 0;
|
||||
break;
|
||||
|
|
@ -323,6 +334,13 @@ S [afpnumkKMGT]
|
|||
based_size = yylval.number->as_ulong();
|
||||
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
|
||||
value is a number with a single letter scale factor. If
|
||||
verilog-ams is not enabled, then reject this rule. If it is
|
||||
|
|
@ -1205,6 +1223,13 @@ static void process_timescale(const char*txt)
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ tan, GN_KEYWORDS_VAMS_2_3, K_tan
|
|||
tanh, GN_KEYWORDS_VAMS_2_3, K_tanh
|
||||
task, GN_KEYWORDS_1364_1995, K_task
|
||||
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
|
||||
tranif0, GN_KEYWORDS_1364_1995, K_tranif0
|
||||
tranif1, GN_KEYWORDS_1364_1995, K_tranif1
|
||||
|
|
|
|||
17
net_expr.cc
17
net_expr.cc
|
|
@ -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
|
||||
* 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)
|
||||
: NetEBinary(op__, l, r)
|
||||
{
|
||||
if (expr_type() == IVL_VT_REAL)
|
||||
if (expr_type() == IVL_VT_REAL) {
|
||||
expr_width(1);
|
||||
else
|
||||
expr_width(l->expr_width() + r->expr_width());
|
||||
|
||||
if (expr_type() == IVL_VT_REAL)
|
||||
cast_signed(true);
|
||||
else
|
||||
} else {
|
||||
expr_width(l->expr_width() + r->expr_width());
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
}
|
||||
}
|
||||
|
||||
NetEBMult::~NetEBMult()
|
||||
|
|
@ -294,8 +292,8 @@ NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r)
|
|||
: NetEBinary(op__, l, r)
|
||||
{
|
||||
assert(op__ == 'p');
|
||||
/* This is incorrect! a * (2^b - 1) is close. */
|
||||
expr_width(l->expr_width()+r->expr_width());
|
||||
/* You could need up to a * (2^b - 1) bits. */
|
||||
expr_width(l->expr_width());
|
||||
cast_signed(l->has_sign() || r->has_sign());
|
||||
}
|
||||
|
||||
|
|
@ -438,6 +436,7 @@ NetECReal::NetECReal(const verireal&val)
|
|||
: value_(val)
|
||||
{
|
||||
expr_width(1);
|
||||
cast_signed(true);
|
||||
}
|
||||
|
||||
NetECReal::~NetECReal()
|
||||
|
|
|
|||
24
net_scope.cc
24
net_scope.cc
|
|
@ -395,6 +395,30 @@ NetEvent* NetScope::find_event(perm_string name)
|
|||
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)
|
||||
{
|
||||
signals_map_[net->name()]=net;
|
||||
|
|
|
|||
|
|
@ -720,6 +720,9 @@ class NetScope : public Attrib {
|
|||
void rem_event(NetEvent*);
|
||||
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
|
||||
methods are used by the NetNet objects to make themselves
|
||||
|
|
@ -899,6 +902,8 @@ class NetScope : public Attrib {
|
|||
|
||||
NetEvent *events_;
|
||||
|
||||
map<perm_string,LineInfo*> genvars_;
|
||||
|
||||
typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t;
|
||||
std::map <perm_string,NetNet*> signals_map_;
|
||||
perm_string module_name_;
|
||||
|
|
|
|||
48
parse.y
48
parse.y
|
|
@ -35,6 +35,9 @@ class PSpecPath;
|
|||
extern void lex_start_table();
|
||||
extern void lex_end_table();
|
||||
|
||||
bool have_timeunit_decl = false;
|
||||
bool have_timeprec_decl = false;
|
||||
|
||||
static svector<PExpr*>* param_active_range = 0;
|
||||
static bool param_active_signed = false;
|
||||
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;
|
||||
};
|
||||
|
||||
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
|
||||
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
|
||||
%token <discipline> DISCIPLINE_IDENTIFIER
|
||||
%token <text> PATHPULSE_IDENTIFIER
|
||||
%token <number> BASED_NUMBER DEC_NUMBER
|
||||
|
|
@ -269,7 +272,10 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
|||
%token K_wone K_uwire
|
||||
|
||||
/* 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. */
|
||||
%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[] $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
|
||||
|
|
@ -1975,6 +1985,25 @@ cont_assign_list
|
|||
{ $$ = $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
|
||||
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_attribute_foreign ';'
|
||||
{ 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
|
||||
{ Module::UCDriveType ucd;
|
||||
switch (uc_drive) {
|
||||
|
|
@ -2003,8 +2037,9 @@ module : attribute_list_opt module_start IDENTIFIER
|
|||
}
|
||||
pform_endmodule($3, in_celldefine, ucd);
|
||||
delete[]$3;
|
||||
have_timeunit_decl = false; // We will allow decls again.
|
||||
have_timeprec_decl = false;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
module_start : K_module | K_macromodule ;
|
||||
|
|
@ -2463,6 +2498,11 @@ module_item
|
|||
}
|
||||
| KK_attribute '(' error ')' ';'
|
||||
{ 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
|
||||
|
|
|
|||
|
|
@ -70,5 +70,11 @@ extern unsigned long based_size;
|
|||
extern bool in_celldefine;
|
||||
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
|
||||
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
|
||||
|
|
|
|||
189
pform.cc
189
pform.cc
|
|
@ -73,6 +73,21 @@ static NetNet::Type pform_default_nettype = NetNet::WIRE;
|
|||
static int pform_time_unit;
|
||||
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 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()) !=
|
||||
pform_cur_generate->tasks.end()) {
|
||||
cerr << task->get_fileline() << ": error: duplicate "
|
||||
" definition for task '" << name << "' in '"
|
||||
"definition for task '" << name << "' in '"
|
||||
<< pform_cur_module->mod_name() << "' (generate)."
|
||||
<< endl;
|
||||
error_count += 1;
|
||||
|
|
@ -292,6 +307,9 @@ void pform_set_timescale(int unit, int prec,
|
|||
assert(unit >= prec);
|
||||
pform_time_unit = unit;
|
||||
pform_time_prec = prec;
|
||||
/* A `timescale clears the timeunit/timeprecision state. */
|
||||
tu_global_flag = false;
|
||||
tp_global_flag = false;
|
||||
|
||||
if (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,
|
||||
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);
|
||||
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_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
|
||||
* a timescale directive. */
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
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();
|
||||
assert(strcmp(name, mod_name) == 0);
|
||||
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);
|
||||
|
||||
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)
|
||||
|
|
@ -503,7 +681,14 @@ void pform_genvars(const struct vlltype&li, list<perm_string>*names)
|
|||
for (cur = names->begin(); cur != names->end() ; *cur++) {
|
||||
LineInfo*lni = new LineInfo();
|
||||
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;
|
||||
|
|
|
|||
8
pform.h
8
pform.h
|
|
@ -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,
|
||||
svector<named_pexpr_t*>*attr);
|
||||
extern void pform_check_timeunit_prec();
|
||||
extern void pform_module_set_ports(vector<Module::port_t*>*);
|
||||
|
||||
/* 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,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ void dll_target::expr_concat(const NetEConcat*net)
|
|||
cur->type_ = IVL_EX_CONCAT;
|
||||
cur->value_ = IVL_VT_VECTOR;
|
||||
cur->width_ = net->expr_width();
|
||||
cur->signed_ = 0;
|
||||
cur->signed_ = net->has_sign() ? 1 : 0;
|
||||
|
||||
cur->u_.concat_.rept = net->repeat();
|
||||
cur->u_.concat_.parms = net->nparms();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
int stuff_ok_flag)
|
||||
{
|
||||
unsigned off, rep;
|
||||
unsigned off, rep, expr_wid, concat_wid, num_sube, idx;
|
||||
struct vector_info res;
|
||||
|
||||
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
|
||||
|
||||
/* Allocate a vector to hold the result. */
|
||||
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), wid);
|
||||
vvp_errors += 1;
|
||||
/* Find out how wide the base concatenation expression is. */
|
||||
num_sube = ivl_expr_parms(exp);
|
||||
expr_wid = 0;
|
||||
for (idx = 0 ; idx < num_sube; idx += 1) {
|
||||
expr_wid += ivl_expr_width(ivl_expr_parm(exp, idx));
|
||||
}
|
||||
|
||||
/* Get the repeat count. This must be a constant that has been
|
||||
evaluated at compile time. The operands will be repeated to
|
||||
form the result. */
|
||||
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
|
||||
to msb, and copy each into the result vector. The
|
||||
expressions are arranged in the concatenation from
|
||||
MSB to LSB, to go through them backwards.
|
||||
|
||||
Abort the loop if the result vector gets filled up. */
|
||||
|
||||
unsigned idx = ivl_expr_parms(exp);
|
||||
while ((idx > 0) && (off < wid)) {
|
||||
/* If the result is the right size we can just build this in place. */
|
||||
concat_wid = rep*expr_wid;
|
||||
if (concat_wid <= wid) {
|
||||
off = 0;
|
||||
/* Evaluate the base expression. */
|
||||
for (idx = num_sube; idx > 0; idx -= 1) {
|
||||
ivl_expr_t arg = ivl_expr_parm(exp, idx-1);
|
||||
unsigned awid = ivl_expr_width(arg);
|
||||
|
||||
unsigned trans;
|
||||
struct vector_info avec;
|
||||
|
||||
assert(awid+off <= expr_wid);
|
||||
|
||||
/* 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.wid = awid;
|
||||
|
||||
trans = awid;
|
||||
if ((off + awid) > wid)
|
||||
trans = wid - off;
|
||||
|
||||
if (avec.base != 0) {
|
||||
assert(awid == avec.wid);
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse calculated expression\n",
|
||||
res.base+off,
|
||||
avec.base, trans);
|
||||
clr_vector(avec);
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse "
|
||||
"calculated expression.\n",
|
||||
res.base+off, avec.base, awid);
|
||||
clr_vector(avec);
|
||||
} else {
|
||||
struct vector_info dest;
|
||||
|
||||
dest.base = res.base+off;
|
||||
dest.wid = trans;
|
||||
dest.wid = awid;
|
||||
draw_eval_expr_dest(arg, dest, 0);
|
||||
}
|
||||
|
||||
|
||||
idx -= 1;
|
||||
off += trans;
|
||||
assert(off <= wid);
|
||||
off += awid;
|
||||
}
|
||||
rep -= 1;
|
||||
}
|
||||
|
||||
/* Pad the result with 0, if necessary. */
|
||||
if (off < wid) {
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
res.base+off, wid-off);
|
||||
/* Now repeat the expression as needed. */
|
||||
if (rep != 0) {
|
||||
rep -= 1;
|
||||
} 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. */
|
||||
|
|
@ -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);
|
||||
assert(tmp.wid == dest.wid);
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
dest.base, tmp.base, dest.wid);
|
||||
/* If the replication is 0 we can have a zero width, so skip it. */
|
||||
if (dest.wid) fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
dest.base, tmp.base, dest.wid);
|
||||
|
||||
if (tmp.base >= 8)
|
||||
save_expression_lookaside(tmp.base, exp, tmp.wid);
|
||||
|
|
|
|||
|
|
@ -240,6 +240,14 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv)
|
|||
vpi_get_value(item, &val);
|
||||
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) {
|
||||
|
||||
if (isspace(*fmtp)) {
|
||||
|
|
|
|||
29
vvp/array.cc
29
vvp/array.cc
|
|
@ -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)
|
||||
{
|
||||
assert(array->vals4);
|
||||
return array->vals_width;
|
||||
unsigned 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)
|
||||
|
|
@ -665,7 +679,7 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
|
|||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
return parent->vals_width;
|
||||
return get_array_word_size(parent);
|
||||
|
||||
case vpiLeftRange:
|
||||
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);
|
||||
} else {
|
||||
vvp_vector4_t tmp = array_get_word(parent, index);
|
||||
vpip_vec4_get_value(tmp, parent->vals_width, parent->signed_flag,
|
||||
value);
|
||||
unsigned width = get_array_word_size(parent);
|
||||
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);
|
||||
array_set_word(parent, index, val);
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
19
vvp/event.cc
19
vvp/event.cc
|
|
@ -195,6 +195,8 @@ struct vvp_fun_edge_state_s : public waitable_state_s {
|
|||
vvp_fun_edge::vvp_fun_edge(edge_t e)
|
||||
: edge_(e)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
|
||||
bits_[idx] = BIT4_X;
|
||||
}
|
||||
|
||||
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(e), threads_(0)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
|
||||
bits_[idx] = BIT4_X;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -268,7 +269,7 @@ void vvp_fun_edge_aa::reset_instance(vvp_context_t context)
|
|||
|
||||
state->threads = 0;
|
||||
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
|
||||
state->bits[idx] = BIT4_X;
|
||||
state->bits[idx] = bits_[idx];
|
||||
}
|
||||
|
||||
#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);
|
||||
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()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
|
||||
bitsr_[idx] = 0.0;
|
||||
}
|
||||
|
||||
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()
|
||||
: threads_(0)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 4 ; idx += 1)
|
||||
bitsr_[idx] = 0.0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -425,8 +428,8 @@ void vvp_fun_anyedge_aa::reset_instance(vvp_context_t context)
|
|||
|
||||
state->threads = 0;
|
||||
for (unsigned idx = 0 ; idx < 4 ; idx += 1) {
|
||||
state->bits[idx].set_to_x();
|
||||
state->bitsr[idx] = 0.0;
|
||||
state->bits[idx] = bits_[idx];
|
||||
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);
|
||||
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);
|
||||
context = vvp_get_next_context(context);
|
||||
}
|
||||
bitsr_[port.port()] = bit;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
10
vvp/event.h
10
vvp/event.h
|
|
@ -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,
|
||||
vvp_bit4_t&old_bit, vthread_t&threads);
|
||||
|
||||
vvp_bit4_t bits_[4];
|
||||
|
||||
private:
|
||||
edge_t edge_;
|
||||
};
|
||||
|
|
@ -165,7 +167,6 @@ class vvp_fun_edge_sa : public vvp_fun_edge {
|
|||
|
||||
private:
|
||||
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);
|
||||
bool recv_real_(vvp_net_ptr_t port, double bit,
|
||||
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:
|
||||
vthread_t threads_;
|
||||
vvp_vector4_t bits_[4];
|
||||
// In case I'm a real-valued event.
|
||||
double bitsr_[4];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
17
vvp/part.cc
17
vvp/part.cc
|
|
@ -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);
|
||||
|
||||
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;
|
||||
|
||||
val_ = bit;
|
||||
val_ = tmp;
|
||||
|
||||
if (net_ == 0) {
|
||||
net_ = port.ptr();
|
||||
|
|
@ -94,13 +99,7 @@ void vvp_fun_part_sa::run_run()
|
|||
{
|
||||
vvp_net_t*ptr = net_;
|
||||
net_ = 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);
|
||||
ptr->send_vec4(val_, 0);
|
||||
}
|
||||
|
||||
vvp_fun_part_aa::vvp_fun_part_aa(unsigned base, unsigned wid)
|
||||
|
|
|
|||
Loading…
Reference in New Issue