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. */
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;

View File

@ -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) {

View File

@ -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,

View File

@ -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;

View File

@ -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.

View File

@ -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(),

View File

@ -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] { }

View File

@ -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);
}

View File

@ -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

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
* 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()

View File

@ -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;

View File

@ -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
View File

@ -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

View File

@ -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
View File

@ -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;

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,
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

View File

@ -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();

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,
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);

View File

@ -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)) {

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)
{
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);
}

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)
: 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;
}
}

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,
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];
};
/*

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);
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)