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
|
||||
* 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
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
|
||||
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
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. */
|
||||
|
||||
/* 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); }
|
||||
|
|
|
|||
48
pform.cc
48
pform.cc
|
|
@ -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
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. */
|
||||
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*>*);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue