Support parameters without default value
SystemVerilog allows to omit the default value of a parameter declared in a
parameter port list. In this case the parameter must be overridden for
every module instance. This is defined in section 6.20.1 ("Parameter
declaration syntax") of the LRM (1800-2017).
In addition a module that has a parameter without a default value does not
qualify for automatic toplevel module selection.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
b1fb4a6117
commit
4a87bee3c0
16
Module.cc
16
Module.cc
|
|
@ -139,3 +139,19 @@ PNamedItem::SymbolType Module::symbol_type() const
|
|||
|
||||
return MODULE;
|
||||
}
|
||||
|
||||
bool Module::can_be_toplevel() const
|
||||
{
|
||||
// Don't choose library modules.
|
||||
if (library_flag)
|
||||
return false;
|
||||
|
||||
// Don't choose modules with parameters without default value
|
||||
for (std::map<perm_string,param_expr_t*>::const_iterator cur =
|
||||
parameters.begin(); cur != parameters.end(); cur++) {
|
||||
if (cur->second->expr == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
2
Module.h
2
Module.h
|
|
@ -166,6 +166,8 @@ class Module : public PScopeExtra, public PNamedItem {
|
|||
|
||||
SymbolType symbol_type() const;
|
||||
|
||||
bool can_be_toplevel() const;
|
||||
|
||||
private:
|
||||
void dump_specparams_(std::ostream&out, unsigned indent) const;
|
||||
std::list<PGate*> gates_;
|
||||
|
|
|
|||
3
main.cc
3
main.cc
|
|
@ -1187,8 +1187,7 @@ int main(int argc, char*argv[])
|
|||
for (mod = pform_modules.begin()
|
||||
; mod != pform_modules.end() ; ++ mod ) {
|
||||
|
||||
/* Don't choose library modules. */
|
||||
if ((*mod).second->library_flag)
|
||||
if (!(*mod).second->can_be_toplevel())
|
||||
continue;
|
||||
|
||||
/* Don't choose modules instantiated in other
|
||||
|
|
|
|||
|
|
@ -827,9 +827,19 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
|
|||
}
|
||||
|
||||
// If the parameter has already been evaluated, quietly return.
|
||||
if (cur->second.val_expr == 0)
|
||||
if (cur->second.val != 0)
|
||||
return;
|
||||
|
||||
if (cur->second.val_expr == 0) {
|
||||
cerr << this->get_fileline() << ": error: "
|
||||
<< "Missing value for parameter `"
|
||||
<< cur->first << "`." << endl;
|
||||
des->errors += 1;
|
||||
|
||||
cur->second.val = new NetEConst(verinum(verinum::Vx));
|
||||
return;
|
||||
}
|
||||
|
||||
// Guess the varaiable type of the parameter. If the parameter has no
|
||||
// given type, then guess the type from the expression and use that to
|
||||
// evaluate.
|
||||
|
|
|
|||
13
parse.y
13
parse.y
|
|
@ -4901,7 +4901,11 @@ module_port_list_opt
|
|||
that the port declarations may use them. */
|
||||
module_parameter_port_list_opt
|
||||
:
|
||||
| '#' '(' module_parameter_port_list ')'
|
||||
| '#' '('
|
||||
{ pform_start_parameter_port_list(); }
|
||||
module_parameter_port_list
|
||||
{ pform_end_parameter_port_list(); }
|
||||
')'
|
||||
;
|
||||
|
||||
module_parameter
|
||||
|
|
@ -5580,7 +5584,12 @@ parameter_assign_list
|
|||
;
|
||||
|
||||
parameter_assign
|
||||
: IDENTIFIER '=' expression parameter_value_ranges_opt
|
||||
: IDENTIFIER parameter_value_ranges_opt
|
||||
{ pform_set_parameter(@1, lex_strings.make($1), param_is_local,
|
||||
param_data_type, 0, $2);
|
||||
delete[]$1;
|
||||
}
|
||||
| IDENTIFIER '=' expression parameter_value_ranges_opt
|
||||
{ PExpr*tmp = $3;
|
||||
pform_set_parameter(@1, lex_strings.make($1), param_is_local,
|
||||
param_data_type, tmp, $4);
|
||||
|
|
|
|||
25
pform.cc
25
pform.cc
|
|
@ -386,6 +386,9 @@ static unsigned pform_timescale_line;
|
|||
bool allow_timeunit_decl = true;
|
||||
bool allow_timeprec_decl = true;
|
||||
|
||||
// Track whether the current parameter declaration is in a parameter port list
|
||||
static bool pform_in_parameter_port_list = false;
|
||||
|
||||
static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
|
||||
{
|
||||
obj->set_lineno(lineno);
|
||||
|
|
@ -1378,6 +1381,16 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
|
|||
pform_bind_attributes(cur_module->attributes, attr);
|
||||
}
|
||||
|
||||
void pform_start_parameter_port_list()
|
||||
{
|
||||
pform_in_parameter_port_list = true;
|
||||
}
|
||||
|
||||
void pform_end_parameter_port_list()
|
||||
{
|
||||
pform_in_parameter_port_list = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by the parser to make a simple port
|
||||
* reference. This is a name without a .X(...), so the internal name
|
||||
|
|
@ -3228,6 +3241,17 @@ void pform_set_parameter(const struct vlltype&loc,
|
|||
return;
|
||||
}
|
||||
|
||||
if (expr == 0) {
|
||||
if (is_local) {
|
||||
VLerror(loc, "error: localparam must have a value.");
|
||||
} else if (!pform_in_parameter_port_list) {
|
||||
VLerror(loc, "error: parameter declared outside parameter "
|
||||
"port list must have a default value.");
|
||||
} else {
|
||||
pform_requires_sv(loc, "parameter without default value");
|
||||
}
|
||||
}
|
||||
|
||||
bool overridable = !is_local;
|
||||
|
||||
if (scope == pform_cur_generate && !is_local) {
|
||||
|
|
@ -3240,7 +3264,6 @@ void pform_set_parameter(const struct vlltype&loc,
|
|||
overridable = false;
|
||||
}
|
||||
|
||||
assert(expr);
|
||||
Module::param_expr_t*parm = new Module::param_expr_t();
|
||||
FILE_NAME(parm, loc);
|
||||
|
||||
|
|
|
|||
3
pform.h
3
pform.h
|
|
@ -614,4 +614,7 @@ void pform_put_enum_type_in_scope(enum_type_t*enum_set);
|
|||
|
||||
bool pform_requires_sv(const struct vlltype&loc, const char *feature);
|
||||
|
||||
void pform_start_parameter_port_list();
|
||||
void pform_end_parameter_port_list();
|
||||
|
||||
#endif /* IVL_pform_H */
|
||||
|
|
|
|||
|
|
@ -1485,11 +1485,9 @@ void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const
|
|||
cur->second->data_type->debug_dump(out);
|
||||
else
|
||||
out << "(nil type)";
|
||||
out << " " << (*cur).first << " = ";
|
||||
if ((*cur).second->expr)
|
||||
out << *(*cur).second->expr;
|
||||
else
|
||||
out << "/* ERROR */";
|
||||
out << " " << (*cur).first << " = "
|
||||
<< *(*cur).second->expr;
|
||||
for (LexicalScope::range_t*tmp = (*cur).second->range
|
||||
; tmp ; tmp = tmp->next) {
|
||||
if (tmp->exclude_flag)
|
||||
|
|
|
|||
Loading…
Reference in New Issue