Added support for interface declaration and instantiation.

modport and extern tf declarations are not yet supported.
This commit is contained in:
Martin Whitaker 2014-12-19 23:10:14 +00:00
parent 6fd10dedb6
commit b400532169
10 changed files with 124 additions and 43 deletions

View File

@ -47,6 +47,10 @@ class NetScope;
* A module is a named container and scope. A module holds a bunch of
* semantic quantities such as wires and gates. The module is
* 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 {
@ -81,6 +85,11 @@ class Module : public PScopeExtra, public LineInfo {
restrictions and slightly modify scheduling semantics. */
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 };
UCDriveType uc_drive;

View File

@ -1375,6 +1375,7 @@ void NetScope::dump(ostream&o) const
if (is_cell()) o << " (cell)";
if (nested_module()) o << " (nested)";
if (program_block()) o << " (program)";
if (is_interface()) o << " (interface)";
o << " " << children_.size() << " children, "
<< classes_.size() << " classes" << endl;

View File

@ -1742,7 +1742,8 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
// scope searches will continue into the parent scope.
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE,
bound_type_? true : false,
mod->program_block);
mod->program_block,
mod->is_interface);
my_scope->set_line(get_file(), mod->get_file(),
get_lineno(), mod->get_lineno());
my_scope->set_module_name(mod->mod_name());

View File

@ -6090,7 +6090,8 @@ Design* elaborate(list<perm_string>roots)
// Make the root scope. This makes a NetScope object and
// 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
// Module definition.

View File

@ -101,11 +101,12 @@ uint64_t Design::scale_to_precision(uint64_t 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_;
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
permallocated. */
root_scope_->set_module_name(root_scope_->basename());

View File

@ -110,8 +110,10 @@ void Definitions::add_class(netclass_t*net_class)
* in question.
*/
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bool prog)
: type_(t), name_(n), nested_module_(nest), program_block_(prog), up_(up)
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
bool program, bool interface)
: type_(t), name_(n), nested_module_(nest), program_block_(program),
is_interface_(interface), up_(up)
{
events_ = 0;
lcounter_ = 0;

View File

@ -918,7 +918,8 @@ class NetScope : public Definitions, public Attrib {
/* Create a new scope, and attach it to the given parent. The
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();
/* 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.
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 is_interface() const { return is_interface_; }
TYPE type() const;
void print_type(ostream&) const;
@ -1221,6 +1223,8 @@ class NetScope : public Definitions, public Attrib {
bool nested_module_;
// True if the scope is a program block
bool program_block_;
// True if the scope is an interface
bool is_interface_;
perm_string file_;
perm_string def_file_;
@ -4747,7 +4751,8 @@ class Design : public Definitions {
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();
std::list<NetScope*> find_root_scopes() const;

69
parse.y
View File

@ -1117,8 +1117,8 @@ data_type_or_implicit_or_void
statements may go. This may be a bad idea, but it is legacy now. */
/* NOTE 2: The "module" rule of the description combines the
module_declaration and program_declaration rules from the
standard description. */
module_declaration, program_declaration, and interface_declaration
rules from the standard description. */
description /* IEEE1800-2005: A.1.2 */
: 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
items, and finally an end marker. */
module
: 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_parameter_port_list_opt
module_port_list_opt
@ -4258,6 +4258,9 @@ module
case K_program:
yyerror(@14, "error: program not closed by endprogram.");
break;
case K_interface:
yyerror(@14, "error: interface not closed by endinterface.");
break;
default:
break;
}
@ -4283,6 +4286,10 @@ module
yyerror(@16, "error: End label doesn't match "
"program name.");
break;
case K_interface:
yyerror(@16, "error: End label doesn't match "
"interface name.");
break;
default:
break;
}
@ -4297,19 +4304,21 @@ module
}
;
/* Modules start with module/macromodule or program keyword, and end
with the endmodule or endprogram keyword. The syntax for modules
and programs is almost identical, so let semantics sort out the
differences. */
/* Modules start with a module/macromodule, program, or interface
keyword, and end with a endmodule, endprogram, or endinterface
keyword. The syntax for modules programs, and interfaces is
almost identical, so let semantics sort out the differences. */
module_start
: K_module { $$ = K_module; }
| K_macromodule { $$ = K_module; }
| K_program { $$ = K_program; }
| K_interface { $$ = K_interface; }
;
module_end
: K_endmodule { $$ = K_module; }
| K_endprogram { $$ = K_program; }
: K_endmodule { $$ = K_module; }
| K_endprogram { $$ = K_program; }
| K_endinterface { $$ = K_interface; }
;
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
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. */
| 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. */
| K_specify K_endspecify
{ /* empty lists are legal syntax. */ }
| K_specify
{ 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
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_opt
: /* empty */
{ }
| specify_item_list
{ }
specify_edge_path_decl
: specify_edge_path '=' '(' delay_value_list ')'
{ $$ = pform_assign_path_delay($1, $4); }

View File

@ -534,6 +534,15 @@ bool pform_in_program_block()
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()
{
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,
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()) {
cerr << loc << ": error: Module definition " << name
@ -1115,15 +1125,25 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
error_count += 1;
}
if (gn_system_verilog() && ! pform_cur_module.empty() &&
pform_cur_module.front()->program_block) {
cerr << loc << ": error: Program blocks cannot contain nested modules/program blocks." << endl;
error_count += 1;
if (gn_system_verilog() && ! pform_cur_module.empty()) {
if (pform_cur_module.front()->program_block) {
cerr << loc << ": error: module, program, or interface "
"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);
Module*cur_module = new Module(lexical_scope, lex_name);
cur_module->program_block = program_block;
cur_module->is_interface = is_interface;
/* Set the local time unit/precision to the global value. */
cur_module->time_unit = pform_time_unit;
cur_module->time_precision = pform_time_prec;
@ -2001,8 +2021,13 @@ void pform_makegates(const struct vlltype&loc,
{
assert(! pform_cur_module.empty());
if (pform_cur_module.front()->program_block) {
cerr << loc << ": error: Gates and switches may not be instantiated"
<< " in program blocks." << endl;
cerr << loc << ": error: Gates and switches may not be instantiated in "
<< "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;
}
@ -2117,8 +2142,13 @@ void pform_make_modgates(const struct vlltype&loc,
{
assert(! pform_cur_module.empty());
if (pform_cur_module.front()->program_block) {
cerr << loc << ": error: Module instantiations are not allowed"
<< " in program blocks." << endl;
cerr << loc << ": error: Module instantiations are not allowed in "
<< "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;
}

12
pform.h
View File

@ -136,6 +136,10 @@ extern void pform_set_default_nettype(NetNet::Type net,
used to reject statements that cannot exist in program blocks. */
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
* (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
* pform to close up and finish the named module.
*
* The program_flag indicates that the module is actually a program
* block. This has implications during parse and during
* The program_block flag indicates that the module is actually a program
* block. The is_interface flag indicates that the module is actually
* an interface. These flags have implications during parse and during
* elaboration/code generation.
*/
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_module_set_ports(vector<Module::port_t*>*);