Added parser support for SV modport declarations.

This commit is contained in:
Martin Whitaker 2015-01-10 11:09:42 +00:00
parent e61ed48914
commit bca84d9dbb
7 changed files with 279 additions and 9 deletions

View File

@ -118,8 +118,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
pform_class_type.o pform_string_type.o pform_struct_type.o pform_types.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \
PGenerate.o PPackage.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \
Statement.o AStatement.o $M $(FF) $(TT)
PGenerate.o PModport.o PPackage.o PScope.o PSpec.o PTask.o PUdp.o \
PFunction.o PWire.o Statement.o AStatement.o $M $(FF) $(TT)
all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true

View File

@ -1,7 +1,7 @@
#ifndef IVL_Module_H
#define IVL_Module_H
/*
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2015 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
@ -35,6 +35,7 @@ class PExpr;
class PEIdent;
class PGate;
class PGenerate;
class PModport;
class PSpecPath;
class PTask;
class PFunction;
@ -68,7 +69,7 @@ class Module : public PScopeExtra, public LineInfo {
public:
/* The name passed here is the module name, not the instance
name. This make must be a permallocated string. */
name. This name must be a permallocated string. */
explicit Module(LexicalScope*parent, perm_string name);
~Module();
@ -134,6 +135,11 @@ class Module : public PScopeExtra, public LineInfo {
unless they are instantiated, implicitly or explicitly. */
std::map<perm_string,Module*> nested_modules;
/* An interface can contain one or more named modport lists.
The parser will ensure these don't appear in modules or
program blocks. */
map<perm_string,PModport*> modports;
list<PSpecPath*> specify_paths;
// The mod_name() is the name of the module type.

31
PModport.cc Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2015 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "config.h"
# include "PModport.h"
PModport::PModport(perm_string n)
: name_(n)
{
}
PModport::~PModport()
{
}

52
PModport.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef IVL_PModport_H
#define IVL_PModport_H
/*
* Copyright (c) 2015 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "LineInfo.h"
# include "PScope.h"
# include "StringHeap.h"
# include "netlist.h"
# include <vector>
/*
* The PModport class represents a parsed SystemVerilog modport list.
*/
class PModport : public LineInfo {
public:
// The name is a perm-allocated string. It is the simple name
// of the modport, without any scope.
explicit PModport(perm_string name);
~PModport();
perm_string name() const { return name_; }
typedef pair <NetNet::PortType,PExpr*> simple_port_t;
map<perm_string,simple_port_t> simple_ports;
private:
perm_string name_;
private: // not implemented
PModport(const PModport&);
PModport& operator= (const PModport&);
};
#endif /* IVL_PModport_H */

131
parse.y
View File

@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -49,6 +49,16 @@ static struct {
data_type_t* data_type;
} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, 0};
/* Modport port declaration lists use this structure for context. */
enum modport_port_type_t { MP_NONE, MP_SIMPLE, MP_TF, MP_CLOCKING };
static struct {
modport_port_type_t type;
union {
NetNet::PortType direction;
bool is_import;
};
} last_modport_port = { MP_NONE, NetNet::NOT_A_PORT};
/* The task and function rules need to briefly hold the pointer to the
task/function that is currently in progress. */
static PTask* current_task = 0;
@ -549,6 +559,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <flag> from_exclude block_item_decls_opt
%type <number> number pos_neg_number
%type <flag> signing unsigned_signed_opt signed_unsigned_opt
%type <flag> import_export
%type <flag> K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt
%type <flag> udp_reg_opt edge_operator
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
@ -583,7 +594,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <tf_ports> task_item task_item_list task_item_list_opt
%type <tf_ports> tf_port_declaration tf_port_item tf_port_list tf_port_list_opt
%type <named_pexpr> port_name parameter_value_byname
%type <named_pexpr> modport_simple_port port_name parameter_value_byname
%type <named_pexprs> port_name_list parameter_value_byname_list
%type <named_pexpr> attribute
@ -1270,6 +1281,11 @@ function_declaration /* IEEE1800-2005: A.2.6 */
;
import_export /* IEEE1800-2012: A.2.9 */
: K_import { $$ = true; }
| K_export { $$ = false; }
;
implicit_class_handle /* IEEE1800-2005: A.8.4 */
: K_this { $$ = pform_create_this(); }
| K_super { $$ = pform_create_super(); }
@ -1546,6 +1562,115 @@ method_qualifier_opt
|
;
modport_declaration /* IEEE1800-2012: A.2.9 */
: K_modport
{ if (!pform_in_interface())
yyerror(@1, "error: modport declarations are only allowed "
"in interfaces.");
}
modport_item_list ';'
modport_item_list
: modport_item
| modport_item_list ',' modport_item
;
modport_item
: IDENTIFIER
{ pform_start_modport_item(@1, $1); }
'(' modport_ports_list ')'
{ pform_end_modport_item(@1); }
;
/* The modport_ports_list is a LALR(2) grammar. When the parser sees a
',' it needs to look ahead to the next token to decide whether it is
a continuation of the preceeding modport_ports_declaration, or the
start of a new modport_ports_declaration. bison only supports LALR(1),
so we have to handcraft a mini parser for this part of the syntax.
last_modport_port holds the state for this mini parser.*/
modport_ports_list
: modport_ports_declaration
| modport_ports_list ',' modport_ports_declaration
| modport_ports_list ',' modport_simple_port
{ if (last_modport_port.type == MP_SIMPLE) {
pform_add_modport_port(@3, last_modport_port.direction,
$3->name, $3->parm);
} else {
yyerror(@3, "error: modport expression not allowed here.");
}
delete $3;
}
| modport_ports_list ',' modport_tf_port
{ if (last_modport_port.type != MP_TF)
yyerror(@3, "error: task/function declaration not allowed here.");
}
| modport_ports_list ',' IDENTIFIER
{ if (last_modport_port.type == MP_SIMPLE) {
pform_add_modport_port(@3, last_modport_port.direction,
lex_strings.make($3), 0);
} else if (last_modport_port.type != MP_TF) {
yyerror(@3, "error: list of identifiers not allowed here.");
}
delete[] $3;
}
| modport_ports_list ','
{ yyerror(@2, "error: NULL port declarations are not allowed"); }
;
modport_ports_declaration
: attribute_list_opt port_direction IDENTIFIER
{ last_modport_port.type = MP_SIMPLE;
last_modport_port.direction = $2;
pform_add_modport_port(@3, $2, lex_strings.make($3), 0);
delete[] $3;
delete $1;
}
| attribute_list_opt port_direction modport_simple_port
{ last_modport_port.type = MP_SIMPLE;
last_modport_port.direction = $2;
pform_add_modport_port(@3, $2, $3->name, $3->parm);
delete $3;
delete $1;
}
| attribute_list_opt import_export IDENTIFIER
{ last_modport_port.type = MP_TF;
last_modport_port.is_import = $2;
yyerror(@3, "sorry: modport task/function ports are not yet supported.");
delete[] $3;
delete $1;
}
| attribute_list_opt import_export modport_tf_port
{ last_modport_port.type = MP_TF;
last_modport_port.is_import = $2;
yyerror(@3, "sorry: modport task/function ports are not yet supported.");
delete $1;
}
| attribute_list_opt K_clocking IDENTIFIER
{ last_modport_port.type = MP_CLOCKING;
last_modport_port.direction = NetNet::NOT_A_PORT;
yyerror(@3, "sorry: modport clocking declaration is not yet supported.");
delete[] $3;
delete $1;
}
;
modport_simple_port
: '.' IDENTIFIER '(' expression ')'
{ named_pexpr_t*tmp = new named_pexpr_t;
tmp->name = lex_strings.make($2);
tmp->parm = $4;
delete[]$2;
$$ = tmp;
}
;
modport_tf_port
: K_task IDENTIFIER
| K_task IDENTIFIER '(' tf_port_list_opt ')'
| K_function data_type_or_implicit_or_void IDENTIFIER
| K_function data_type_or_implicit_or_void IDENTIFIER '(' tf_port_list_opt ')'
;
non_integer_type /* IEEE1800-2005: A.2.2.1 */
: K_real { $$ = real_type_t::REAL; }
@ -4684,6 +4809,8 @@ module_item
pform_endgenerate();
}
| modport_declaration
| package_import_declaration
/* 1364-2001 and later allow specparam declarations outside specify blocks. */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -29,6 +29,7 @@
# include "PPackage.h"
# include "PUdp.h"
# include "PGenerate.h"
# include "PModport.h"
# include "PSpec.h"
# include "discipline.h"
# include <list>
@ -265,6 +266,10 @@ static unsigned scope_generate_counter = 1;
always within a module. */
static PGenerate*pform_cur_generate = 0;
/* This tracks the current modport list being processed. This is
always within an interface. */
static PModport*pform_cur_modport = 0;
static NetNet::Type pform_default_nettype = NetNet::WIRE;
/*
@ -3356,6 +3361,46 @@ PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st,
return pp;
}
void pform_start_modport_item(const struct vlltype&loc, const char*name)
{
Module*scope = pform_cur_module.front();
ivl_assert(loc, scope && scope->is_interface);
ivl_assert(loc, pform_cur_modport == 0);
perm_string use_name = lex_strings.make(name);
pform_cur_modport = new PModport(use_name);
FILE_NAME(pform_cur_modport, loc);
if (scope->modports.find(use_name) != scope->modports.end()) {
cerr << loc << ": error: duplicate declaration for modport '"
<< name << "' in '" << scope->mod_name() << "'." << endl;
error_count += 1;
}
scope->modports[use_name] = pform_cur_modport;
delete[] name;
}
void pform_end_modport_item(const struct vlltype&loc)
{
ivl_assert(loc, pform_cur_modport);
pform_cur_modport = 0;
}
void pform_add_modport_port(const struct vlltype&loc,
NetNet::PortType port_type,
perm_string name, PExpr*expr)
{
ivl_assert(loc, pform_cur_modport);
if (pform_cur_modport->simple_ports.find(name)
!= pform_cur_modport->simple_ports.end()) {
cerr << loc << ": error: duplicate declaration of port '"
<< name << "' in modport list '"
<< pform_cur_modport->name() << "'." << endl;
error_count += 1;
}
pform_cur_modport->simple_ports[name] = make_pair(port_type, expr);
}
FILE*vl_input = 0;
extern void reset_lexor();

11
pform.h
View File

@ -1,7 +1,7 @@
#ifndef IVL_pform_H
#define IVL_pform_H
/*
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2015 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
@ -219,6 +219,15 @@ extern void pform_package_import(const struct vlltype&loc,
extern PExpr* pform_package_ident(const struct vlltype&loc,
PPackage*pkg, pform_name_t*ident);
/*
* Interface related functions.
*/
extern void pform_start_modport_item(const struct vlltype&loc, const char*name);
extern void pform_end_modport_item(const struct vlltype&loc);
extern void pform_add_modport_port(const struct vlltype&loc,
NetNet::PortType port_type,
perm_string name, PExpr*expr);
/*
* This creates an identifier aware of names that may have been
* imported from other packages.