Added parser support for SV modport declarations.
This commit is contained in:
parent
e61ed48914
commit
bca84d9dbb
|
|
@ -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
|
||||
|
|
|
|||
10
Module.h
10
Module.h
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
@ -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 */
|
||||
133
parse.y
133
parse.y
|
|
@ -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. */
|
||||
|
|
@ -6608,7 +6735,7 @@ udp_primitive
|
|||
presence is significant. This is a fairly common pattern so
|
||||
collect those rules here. */
|
||||
|
||||
K_automatic_opt: K_automatic { $$ = true; } | { $$ = false;} ;
|
||||
K_automatic_opt: K_automatic { $$ = true; } | { $$ = false; } ;
|
||||
K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ;
|
||||
K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ;
|
||||
K_static_opt : K_static { $$ = true; } | { $$ = false; } ;
|
||||
|
|
|
|||
47
pform.cc
47
pform.cc
|
|
@ -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
11
pform.h
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue