Added support for interface declaration and instantiation.
modport and extern tf declarations are not yet supported.
This commit is contained in:
parent
6fd10dedb6
commit
b400532169
9
Module.h
9
Module.h
|
|
@ -47,6 +47,10 @@ class NetScope;
|
||||||
* A module is a named container and scope. A module holds a bunch of
|
* A module is a named container and scope. A module holds a bunch of
|
||||||
* semantic quantities such as wires and gates. The module is
|
* semantic quantities such as wires and gates. The module is
|
||||||
* therefore the handle for grasping the described circuit.
|
* therefore the handle for grasping the described circuit.
|
||||||
|
*
|
||||||
|
* SystemVerilog introduces program blocks and interfaces. These have
|
||||||
|
* much in common with modules, so the Module class is used to represent
|
||||||
|
* these containers as well.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Module : public PScopeExtra, public LineInfo {
|
class Module : public PScopeExtra, public LineInfo {
|
||||||
|
|
@ -81,6 +85,11 @@ class Module : public PScopeExtra, public LineInfo {
|
||||||
restrictions and slightly modify scheduling semantics. */
|
restrictions and slightly modify scheduling semantics. */
|
||||||
bool program_block;
|
bool program_block;
|
||||||
|
|
||||||
|
/* This is true if the module represents a interface
|
||||||
|
instead of a module/cell. Interfaces have different
|
||||||
|
content restrictions and some extra allowed items. */
|
||||||
|
bool is_interface;
|
||||||
|
|
||||||
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
|
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
|
||||||
UCDriveType uc_drive;
|
UCDriveType uc_drive;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1375,6 +1375,7 @@ void NetScope::dump(ostream&o) const
|
||||||
if (is_cell()) o << " (cell)";
|
if (is_cell()) o << " (cell)";
|
||||||
if (nested_module()) o << " (nested)";
|
if (nested_module()) o << " (nested)";
|
||||||
if (program_block()) o << " (program)";
|
if (program_block()) o << " (program)";
|
||||||
|
if (is_interface()) o << " (interface)";
|
||||||
o << " " << children_.size() << " children, "
|
o << " " << children_.size() << " children, "
|
||||||
<< classes_.size() << " classes" << endl;
|
<< classes_.size() << " classes" << endl;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1742,7 +1742,8 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
||||||
// scope searches will continue into the parent scope.
|
// scope searches will continue into the parent scope.
|
||||||
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE,
|
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE,
|
||||||
bound_type_? true : false,
|
bound_type_? true : false,
|
||||||
mod->program_block);
|
mod->program_block,
|
||||||
|
mod->is_interface);
|
||||||
my_scope->set_line(get_file(), mod->get_file(),
|
my_scope->set_line(get_file(), mod->get_file(),
|
||||||
get_lineno(), mod->get_lineno());
|
get_lineno(), mod->get_lineno());
|
||||||
my_scope->set_module_name(mod->mod_name());
|
my_scope->set_module_name(mod->mod_name());
|
||||||
|
|
|
||||||
|
|
@ -6090,7 +6090,8 @@ Design* elaborate(list<perm_string>roots)
|
||||||
|
|
||||||
// Make the root scope. This makes a NetScope object and
|
// Make the root scope. This makes a NetScope object and
|
||||||
// pushes it into the list of root scopes in the Design.
|
// pushes it into the list of root scopes in the Design.
|
||||||
NetScope*scope = des->make_root_scope(*root, rmod->program_block);
|
NetScope*scope = des->make_root_scope(*root, rmod->program_block,
|
||||||
|
rmod->is_interface);
|
||||||
|
|
||||||
// Collect some basic properties of this scope from the
|
// Collect some basic properties of this scope from the
|
||||||
// Module definition.
|
// Module definition.
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,12 @@ uint64_t Design::scale_to_precision(uint64_t val,
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetScope* Design::make_root_scope(perm_string root, bool program_block)
|
NetScope* Design::make_root_scope(perm_string root, bool program_block,
|
||||||
|
bool is_interface)
|
||||||
{
|
{
|
||||||
NetScope *root_scope_;
|
NetScope *root_scope_;
|
||||||
root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE,
|
root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE,
|
||||||
false, program_block);
|
false, program_block, is_interface);
|
||||||
/* This relies on the fact that the basename return value is
|
/* This relies on the fact that the basename return value is
|
||||||
permallocated. */
|
permallocated. */
|
||||||
root_scope_->set_module_name(root_scope_->basename());
|
root_scope_->set_module_name(root_scope_->basename());
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,10 @@ void Definitions::add_class(netclass_t*net_class)
|
||||||
* in question.
|
* in question.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bool prog)
|
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
||||||
: type_(t), name_(n), nested_module_(nest), program_block_(prog), up_(up)
|
bool program, bool interface)
|
||||||
|
: type_(t), name_(n), nested_module_(nest), program_block_(program),
|
||||||
|
is_interface_(interface), up_(up)
|
||||||
{
|
{
|
||||||
events_ = 0;
|
events_ = 0;
|
||||||
lcounter_ = 0;
|
lcounter_ = 0;
|
||||||
|
|
|
||||||
11
netlist.h
11
netlist.h
|
|
@ -918,7 +918,8 @@ class NetScope : public Definitions, public Attrib {
|
||||||
|
|
||||||
/* Create a new scope, and attach it to the given parent. The
|
/* Create a new scope, and attach it to the given parent. The
|
||||||
name is expected to have been permallocated. */
|
name is expected to have been permallocated. */
|
||||||
NetScope(NetScope*up, const hname_t&name, TYPE t, bool nest=false, bool prog=false);
|
NetScope(NetScope*up, const hname_t&name, TYPE t, bool nest=false,
|
||||||
|
bool program=false, bool interface=false);
|
||||||
~NetScope();
|
~NetScope();
|
||||||
|
|
||||||
/* Rename the scope using the name generated by inserting as
|
/* Rename the scope using the name generated by inserting as
|
||||||
|
|
@ -1008,8 +1009,9 @@ class NetScope : public Definitions, public Attrib {
|
||||||
|
|
||||||
// Nested modules have slightly different scope search rules.
|
// Nested modules have slightly different scope search rules.
|
||||||
inline bool nested_module() const { return nested_module_; }
|
inline bool nested_module() const { return nested_module_; }
|
||||||
// Program blocks have elaboration constraints.
|
// Program blocks and interfaces have elaboration constraints.
|
||||||
inline bool program_block() const { return program_block_; }
|
inline bool program_block() const { return program_block_; }
|
||||||
|
inline bool is_interface() const { return is_interface_; }
|
||||||
TYPE type() const;
|
TYPE type() const;
|
||||||
void print_type(ostream&) const;
|
void print_type(ostream&) const;
|
||||||
|
|
||||||
|
|
@ -1221,6 +1223,8 @@ class NetScope : public Definitions, public Attrib {
|
||||||
bool nested_module_;
|
bool nested_module_;
|
||||||
// True if the scope is a program block
|
// True if the scope is a program block
|
||||||
bool program_block_;
|
bool program_block_;
|
||||||
|
// True if the scope is an interface
|
||||||
|
bool is_interface_;
|
||||||
|
|
||||||
perm_string file_;
|
perm_string file_;
|
||||||
perm_string def_file_;
|
perm_string def_file_;
|
||||||
|
|
@ -4747,7 +4751,8 @@ class Design : public Definitions {
|
||||||
|
|
||||||
const char* get_flag(const string&key) const;
|
const char* get_flag(const string&key) const;
|
||||||
|
|
||||||
NetScope* make_root_scope(perm_string name, bool program_block);
|
NetScope* make_root_scope(perm_string name, bool program_block,
|
||||||
|
bool is_interface);
|
||||||
NetScope* find_root_scope();
|
NetScope* find_root_scope();
|
||||||
std::list<NetScope*> find_root_scopes() const;
|
std::list<NetScope*> find_root_scopes() const;
|
||||||
|
|
||||||
|
|
|
||||||
69
parse.y
69
parse.y
|
|
@ -1117,8 +1117,8 @@ data_type_or_implicit_or_void
|
||||||
statements may go. This may be a bad idea, but it is legacy now. */
|
statements may go. This may be a bad idea, but it is legacy now. */
|
||||||
|
|
||||||
/* NOTE 2: The "module" rule of the description combines the
|
/* NOTE 2: The "module" rule of the description combines the
|
||||||
module_declaration and program_declaration rules from the
|
module_declaration, program_declaration, and interface_declaration
|
||||||
standard description. */
|
rules from the standard description. */
|
||||||
|
|
||||||
description /* IEEE1800-2005: A.1.2 */
|
description /* IEEE1800-2005: A.1.2 */
|
||||||
: module
|
: module
|
||||||
|
|
@ -4213,13 +4213,13 @@ local_timeunit_prec_decl2
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* This is the global structure of a module. A module in a start
|
/* This is the global structure of a module. A module is a start
|
||||||
section, with optional ports, then an optional list of module
|
section, with optional ports, then an optional list of module
|
||||||
items, and finally an end marker. */
|
items, and finally an end marker. */
|
||||||
|
|
||||||
module
|
module
|
||||||
: attribute_list_opt module_start IDENTIFIER
|
: attribute_list_opt module_start IDENTIFIER
|
||||||
{ pform_startmodule(@2, $3, $2==K_program, $1); }
|
{ pform_startmodule(@2, $3, $2==K_program, $2==K_interface, $1); }
|
||||||
module_package_import_list_opt
|
module_package_import_list_opt
|
||||||
module_parameter_port_list_opt
|
module_parameter_port_list_opt
|
||||||
module_port_list_opt
|
module_port_list_opt
|
||||||
|
|
@ -4258,6 +4258,9 @@ module
|
||||||
case K_program:
|
case K_program:
|
||||||
yyerror(@14, "error: program not closed by endprogram.");
|
yyerror(@14, "error: program not closed by endprogram.");
|
||||||
break;
|
break;
|
||||||
|
case K_interface:
|
||||||
|
yyerror(@14, "error: interface not closed by endinterface.");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -4283,6 +4286,10 @@ module
|
||||||
yyerror(@16, "error: End label doesn't match "
|
yyerror(@16, "error: End label doesn't match "
|
||||||
"program name.");
|
"program name.");
|
||||||
break;
|
break;
|
||||||
|
case K_interface:
|
||||||
|
yyerror(@16, "error: End label doesn't match "
|
||||||
|
"interface name.");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -4297,19 +4304,21 @@ module
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Modules start with module/macromodule or program keyword, and end
|
/* Modules start with a module/macromodule, program, or interface
|
||||||
with the endmodule or endprogram keyword. The syntax for modules
|
keyword, and end with a endmodule, endprogram, or endinterface
|
||||||
and programs is almost identical, so let semantics sort out the
|
keyword. The syntax for modules programs, and interfaces is
|
||||||
differences. */
|
almost identical, so let semantics sort out the differences. */
|
||||||
module_start
|
module_start
|
||||||
: K_module { $$ = K_module; }
|
: K_module { $$ = K_module; }
|
||||||
| K_macromodule { $$ = K_module; }
|
| K_macromodule { $$ = K_module; }
|
||||||
| K_program { $$ = K_program; }
|
| K_program { $$ = K_program; }
|
||||||
|
| K_interface { $$ = K_interface; }
|
||||||
;
|
;
|
||||||
|
|
||||||
module_end
|
module_end
|
||||||
: K_endmodule { $$ = K_module; }
|
: K_endmodule { $$ = K_module; }
|
||||||
| K_endprogram { $$ = K_program; }
|
| K_endprogram { $$ = K_program; }
|
||||||
|
| K_endinterface { $$ = K_interface; }
|
||||||
;
|
;
|
||||||
|
|
||||||
endlabel_opt
|
endlabel_opt
|
||||||
|
|
@ -4505,7 +4514,12 @@ module_item
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
| K_defparam defparam_assign_list ';'
|
| K_defparam
|
||||||
|
{ if (pform_in_interface())
|
||||||
|
yyerror(@1, "error: Parameter overrides are not allowed "
|
||||||
|
"in interfaces.");
|
||||||
|
}
|
||||||
|
defparam_assign_list ';'
|
||||||
|
|
||||||
/* Most gate types have an optional drive strength and optional
|
/* Most gate types have an optional drive strength and optional
|
||||||
two/three-value delay. These rules handle the different cases.
|
two/three-value delay. These rules handle the different cases.
|
||||||
|
|
@ -4674,21 +4688,26 @@ module_item
|
||||||
|
|
||||||
/* 1364-2001 and later allow specparam declarations outside specify blocks. */
|
/* 1364-2001 and later allow specparam declarations outside specify blocks. */
|
||||||
|
|
||||||
| attribute_list_opt K_specparam specparam_decl ';'
|
| attribute_list_opt K_specparam
|
||||||
|
{ if (pform_in_interface())
|
||||||
|
yyerror(@1, "error: specparam declarations are not allowed "
|
||||||
|
"in interfaces.");
|
||||||
|
}
|
||||||
|
specparam_decl ';'
|
||||||
|
|
||||||
/* specify blocks are parsed but ignored. */
|
/* specify blocks are parsed but ignored. */
|
||||||
|
|
||||||
| K_specify K_endspecify
|
| K_specify
|
||||||
{ /* empty lists are legal syntax. */ }
|
{ if (pform_in_interface())
|
||||||
|
yyerror(@1, "error: specify blocks are not allowed "
|
||||||
|
"in interfaces.");
|
||||||
|
}
|
||||||
|
specify_item_list_opt K_endspecify
|
||||||
|
|
||||||
| K_specify specify_item_list K_endspecify
|
| K_specify error K_endspecify
|
||||||
{
|
{ yyerror(@1, "error: syntax error in specify block");
|
||||||
}
|
yyerrok;
|
||||||
|
}
|
||||||
| K_specify error K_endspecify
|
|
||||||
{ yyerror(@1, "error: syntax error in specify block");
|
|
||||||
yyerrok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These rules match various errors that the user can type into
|
/* These rules match various errors that the user can type into
|
||||||
module items. These rules try to catch them at a point where a
|
module items. These rules try to catch them at a point where a
|
||||||
|
|
@ -5467,6 +5486,12 @@ specify_item_list
|
||||||
| specify_item_list specify_item
|
| specify_item_list specify_item
|
||||||
;
|
;
|
||||||
|
|
||||||
|
specify_item_list_opt
|
||||||
|
: /* empty */
|
||||||
|
{ }
|
||||||
|
| specify_item_list
|
||||||
|
{ }
|
||||||
|
|
||||||
specify_edge_path_decl
|
specify_edge_path_decl
|
||||||
: specify_edge_path '=' '(' delay_value_list ')'
|
: specify_edge_path '=' '(' delay_value_list ')'
|
||||||
{ $$ = pform_assign_path_delay($1, $4); }
|
{ $$ = pform_assign_path_delay($1, $4); }
|
||||||
|
|
|
||||||
48
pform.cc
48
pform.cc
|
|
@ -534,6 +534,15 @@ bool pform_in_program_block()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pform_in_interface()
|
||||||
|
{
|
||||||
|
if (pform_cur_module.empty())
|
||||||
|
return false;
|
||||||
|
if (pform_cur_module.front()->is_interface)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool pform_at_module_level()
|
static bool pform_at_module_level()
|
||||||
{
|
{
|
||||||
return (lexical_scope == pform_cur_module.front())
|
return (lexical_scope == pform_cur_module.front())
|
||||||
|
|
@ -1107,7 +1116,8 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val,
|
||||||
}
|
}
|
||||||
|
|
||||||
void pform_startmodule(const struct vlltype&loc, const char*name,
|
void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||||
bool program_block, list<named_pexpr_t>*attr)
|
bool program_block, bool is_interface,
|
||||||
|
list<named_pexpr_t>*attr)
|
||||||
{
|
{
|
||||||
if (! pform_cur_module.empty() && !gn_system_verilog()) {
|
if (! pform_cur_module.empty() && !gn_system_verilog()) {
|
||||||
cerr << loc << ": error: Module definition " << name
|
cerr << loc << ": error: Module definition " << name
|
||||||
|
|
@ -1115,15 +1125,25 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||||
error_count += 1;
|
error_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gn_system_verilog() && ! pform_cur_module.empty() &&
|
if (gn_system_verilog() && ! pform_cur_module.empty()) {
|
||||||
pform_cur_module.front()->program_block) {
|
if (pform_cur_module.front()->program_block) {
|
||||||
cerr << loc << ": error: Program blocks cannot contain nested modules/program blocks." << endl;
|
cerr << loc << ": error: module, program, or interface "
|
||||||
error_count += 1;
|
"declarations are not allowed in program "
|
||||||
|
"blocks." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
}
|
||||||
|
if (pform_cur_module.front()->is_interface
|
||||||
|
&& !(program_block || is_interface)) {
|
||||||
|
cerr << loc << ": error: module declarations are not "
|
||||||
|
"allowed in interfaces." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
perm_string lex_name = lex_strings.make(name);
|
perm_string lex_name = lex_strings.make(name);
|
||||||
Module*cur_module = new Module(lexical_scope, lex_name);
|
Module*cur_module = new Module(lexical_scope, lex_name);
|
||||||
cur_module->program_block = program_block;
|
cur_module->program_block = program_block;
|
||||||
|
cur_module->is_interface = is_interface;
|
||||||
/* Set the local time unit/precision to the global value. */
|
/* Set the local time unit/precision to the global value. */
|
||||||
cur_module->time_unit = pform_time_unit;
|
cur_module->time_unit = pform_time_unit;
|
||||||
cur_module->time_precision = pform_time_prec;
|
cur_module->time_precision = pform_time_prec;
|
||||||
|
|
@ -2001,8 +2021,13 @@ void pform_makegates(const struct vlltype&loc,
|
||||||
{
|
{
|
||||||
assert(! pform_cur_module.empty());
|
assert(! pform_cur_module.empty());
|
||||||
if (pform_cur_module.front()->program_block) {
|
if (pform_cur_module.front()->program_block) {
|
||||||
cerr << loc << ": error: Gates and switches may not be instantiated"
|
cerr << loc << ": error: Gates and switches may not be instantiated in "
|
||||||
<< " in program blocks." << endl;
|
<< "program blocks." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
}
|
||||||
|
if (pform_cur_module.front()->is_interface) {
|
||||||
|
cerr << loc << ": error: Gates and switches may not be instantiated in "
|
||||||
|
<< "interfaces." << endl;
|
||||||
error_count += 1;
|
error_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2117,8 +2142,13 @@ void pform_make_modgates(const struct vlltype&loc,
|
||||||
{
|
{
|
||||||
assert(! pform_cur_module.empty());
|
assert(! pform_cur_module.empty());
|
||||||
if (pform_cur_module.front()->program_block) {
|
if (pform_cur_module.front()->program_block) {
|
||||||
cerr << loc << ": error: Module instantiations are not allowed"
|
cerr << loc << ": error: Module instantiations are not allowed in "
|
||||||
<< " in program blocks." << endl;
|
<< "program blocks." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
}
|
||||||
|
if (pform_cur_module.front()->is_interface) {
|
||||||
|
cerr << loc << ": error: Module instantiations are not allowed in "
|
||||||
|
<< "interfaces." << endl;
|
||||||
error_count += 1;
|
error_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
pform.h
12
pform.h
|
|
@ -136,6 +136,10 @@ extern void pform_set_default_nettype(NetNet::Type net,
|
||||||
used to reject statements that cannot exist in program blocks. */
|
used to reject statements that cannot exist in program blocks. */
|
||||||
extern bool pform_in_program_block(void);
|
extern bool pform_in_program_block(void);
|
||||||
|
|
||||||
|
/* Return true if currently processing an interface. This can be
|
||||||
|
used to reject statements that cannot exist in interfaces. */
|
||||||
|
extern bool pform_in_interface(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for the given wire in the current lexical scope. If the wire
|
* Look for the given wire in the current lexical scope. If the wire
|
||||||
* (including variables of any type) cannot be found in the current
|
* (including variables of any type) cannot be found in the current
|
||||||
|
|
@ -152,12 +156,14 @@ extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_ty
|
||||||
* are to apply to the scope of that module. The endmodule causes the
|
* are to apply to the scope of that module. The endmodule causes the
|
||||||
* pform to close up and finish the named module.
|
* pform to close up and finish the named module.
|
||||||
*
|
*
|
||||||
* The program_flag indicates that the module is actually a program
|
* The program_block flag indicates that the module is actually a program
|
||||||
* block. This has implications during parse and during
|
* block. The is_interface flag indicates that the module is actually
|
||||||
|
* an interface. These flags have implications during parse and during
|
||||||
* elaboration/code generation.
|
* elaboration/code generation.
|
||||||
*/
|
*/
|
||||||
extern void pform_startmodule(const struct vlltype&loc, const char*name,
|
extern void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||||
bool program_block, list<named_pexpr_t>*attr);
|
bool program_block, bool is_interface,
|
||||||
|
list<named_pexpr_t>*attr);
|
||||||
extern void pform_check_timeunit_prec();
|
extern void pform_check_timeunit_prec();
|
||||||
extern void pform_module_set_ports(vector<Module::port_t*>*);
|
extern void pform_module_set_ports(vector<Module::port_t*>*);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue