Merge branch 'pscope'

This commit is contained in:
Stephen Williams 2008-02-24 19:45:21 -08:00
commit 11a33a0907
24 changed files with 809 additions and 812 deletions

View File

@ -111,7 +111,7 @@ parse.o parse_misc.o pform.o pform_dump.o pform_types.o \
set_width.o symbol_search.o sync.o sys_funcs.o \
verinum.o verireal.o target.o targets.o \
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \
PExpr.o PGate.o PGenerate.o PSpec.o \
PExpr.o PGate.o PGenerate.o PScope.o PSpec.o \
PTask.o PUdp.o PFunction.o PWire.o Statement.o StringHeap.o \
$(FF) $(TT)

View File

@ -29,7 +29,7 @@
/* n is a permallocated string. */
Module::Module(perm_string n)
: name_(n)
: PScope(n, 0)
{
library_flag = false;
default_nettype = NetNet::NONE;
@ -54,16 +54,6 @@ void Module::add_function(perm_string name, PFunction *func)
funcs_[name] = func;
}
PWire* Module::add_wire(PWire*wire)
{
PWire*&ep = wires_[wire->path()];
if (ep) return ep;
assert(ep == 0);
ep = wire;
return wire;
}
void Module::add_behavior(PProcess*b)
{
behaviors_.push_back(b);
@ -111,15 +101,6 @@ unsigned Module::find_port(const char*name) const
}
PWire* Module::get_wire(const pform_name_t&name) const
{
map<pform_name_t,PWire*>::const_iterator obj = wires_.find(name);
if (obj == wires_.end())
return 0;
else
return (*obj).second;
}
PGate* Module::get_gate(perm_string name)
{
for (list<PGate*>::iterator cur = gates_.begin()

View File

@ -1,7 +1,7 @@
#ifndef __Module_H
#define __Module_H
/*
* Copyright (c) 1998-2004 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2008 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
@ -18,9 +18,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: Module.h,v 1.43 2007/05/24 04:07:11 steve Exp $"
#endif
# include <list>
# include <map>
@ -28,10 +26,10 @@
# include "StringHeap.h"
# include "HName.h"
# include "named.h"
# include "PScope.h"
# include "LineInfo.h"
# include "netlist.h"
# include "pform_types.h"
class PEvent;
class PExpr;
class PEIdent;
class PGate;
@ -50,7 +48,7 @@ class NetScope;
* therefore the handle for grasping the described circuit.
*/
class Module : public LineInfo {
class Module : public PScope, public LineInfo {
/* The module ports are in general a vector of port_t
objects. Each port has a name and an ordered list of
@ -113,9 +111,6 @@ class Module : public LineInfo {
named array of PEident pointers. */
svector<port_t*> ports;
/* Keep a table of named events declared in the module. */
map<perm_string,PEvent*>events;
map<perm_string,PExpr*> attributes;
/* These are the timescale for this module. The default is
@ -132,15 +127,10 @@ class Module : public LineInfo {
list<PSpecPath*> specify_paths;
perm_string mod_name() const { return name_; }
// The mod_name() is the name of the module type.
perm_string mod_name() const { return pscope_name(); }
void add_gate(PGate*gate);
// The add_wire method adds a wire by name, but only if the
// wire name doesn't already exist. Either way, the result is
// the existing wire or the pointer passed in.
PWire* add_wire(PWire*wire);
void add_behavior(PProcess*behave);
void add_task(perm_string name, PTask*def);
void add_function(perm_string name, PFunction*def);
@ -149,9 +139,6 @@ class Module : public LineInfo {
const svector<PEIdent*>& get_port(unsigned idx) const;
unsigned find_port(const char*name) const;
// Find a wire by name. This is used for connecting gates to
// existing wires, etc.
PWire* get_wire(const pform_name_t&name) const;
PGate* get_gate(perm_string name);
const list<PGate*>& get_gates() const;
@ -166,9 +153,6 @@ class Module : public LineInfo {
bool elaborate_sig(Design*, NetScope*scope) const;
private:
perm_string name_;
map<pform_name_t,PWire*> wires_;
list<PGate*> gates_;
list<PProcess*> behaviors_;
map<perm_string,PTask*> tasks_;
@ -182,26 +166,4 @@ class Module : public LineInfo {
Module& operator= (const Module&);
};
/*
* $Log: Module.h,v $
* Revision 1.43 2007/05/24 04:07:11 steve
* Rework the heirarchical identifier parse syntax and pform
* to handle more general combinations of heirarch and bit selects.
*
* Revision 1.42 2007/04/19 02:52:53 steve
* Add support for -v flag in command file.
*
* Revision 1.41 2006/09/23 04:57:19 steve
* Basic support for specify timing.
*
* Revision 1.40 2006/04/10 00:37:42 steve
* Add support for generate loops w/ wires and gates.
*
* Revision 1.39 2006/03/30 01:49:07 steve
* Fix instance arrays indexed by overridden parameters.
*
* Revision 1.38 2005/07/11 16:56:50 steve
* Remove NetVariable and ivl_variable_t structures.
*/
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 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
@ -16,16 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PFunction.cc,v 1.7 2004/05/31 23:34:36 steve Exp $"
#endif
# include "config.h"
#include "PTask.h"
PFunction::PFunction(perm_string name)
: name_(name), ports_(0), statement_(0)
PFunction::PFunction(perm_string name, PScope*parent)
: PScope(name, parent), ports_(0), statement_(0)
{
return_type_.type = PTF_NONE;
}
@ -51,28 +48,3 @@ void PFunction::set_return(PTaskFuncArg t)
{
return_type_ = t;
}
/*
* $Log: PFunction.cc,v $
* Revision 1.7 2004/05/31 23:34:36 steve
* Rewire/generalize parsing an elaboration of
* function return values to allow for better
* speed and more type support.
*
* Revision 1.6 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.5 2001/07/25 03:10:48 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.4 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.3 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
*/

View File

@ -33,19 +33,9 @@ PGenerate::~PGenerate()
{
}
PWire* PGenerate::add_wire(PWire*wire)
PWire* PGenerate::get_wire(perm_string name) const
{
PWire*&ep = wires[wire->path()];
if (ep) return ep;
assert(ep == 0);
ep = wire;
return wire;
}
PWire* PGenerate::get_wire(const pform_name_t&name) const
{
map<pform_name_t,PWire*>::const_iterator obj = wires.find(name);
map<perm_string,PWire*>::const_iterator obj = wires.find(name);
if (obj == wires.end())
return 0;
else

View File

@ -71,9 +71,8 @@ class PGenerate : public LineInfo {
PExpr*loop_test;
PExpr*loop_step;
map<pform_name_t,PWire*>wires;
PWire* add_wire(PWire*);
PWire* get_wire(const pform_name_t&name) const;
map<perm_string,PWire*>wires;
PWire* get_wire(perm_string name) const;
list<PGate*> gates;
void add_gate(PGate*);

38
PScope.cc Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2008 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "PScope.h"
PScope::PScope(perm_string n, PScope*p)
: name_(n), parent_(p)
{
}
PScope::~PScope()
{
}
PWire* PScope::wires_find(perm_string name)
{
map<perm_string,PWire*>::const_iterator cur = wires.find(name);
if (cur == wires.end())
return 0;
else
return (*cur).second;
}

74
PScope.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef __PScope_H
#define __PScope_H
/*
* Copyright (c) 2008 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "StringHeap.h"
# include "pform_types.h"
# include <map>
class PEvent;
class PWire;
class Design;
class NetScope;
/*
* The PScope class is a base representation of an object that
* represents lexical scope. For example, a module, a function/task, a
* named block is derived from a PScope.
*
* NOTE: This is note the same concept as the "scope" of an elaborated
* hierarchy. That is represented by NetScope objects after elaboration.
*/
class PScope {
public:
// When created, a scope has a name and a parent. The name is
// the name of the definition. For example, if this is a
// module declaration, the name is the name after the "module"
// keyword, and if this is a task scope, the name is the task
// name. The parent is the lexical parent of this scope. Since
// modules do not nest in Verilog, the parent must be nil for
// modules. Scopes for tasks and functions point to their
// containing module.
PScope(perm_string name, PScope*parent);
virtual ~PScope();
perm_string pscope_name() const { return name_; }
PScope* pscope_parent() { return parent_; }
// Nets an variables (wires) in the scope
map<perm_string,PWire*>wires;
PWire* wires_find(perm_string name);
// Named events in the scope.
map<perm_string,PEvent*>events;
protected:
void dump_wires_(ostream&out, unsigned indent) const;
bool elaborate_sig_wires_(Design*des, NetScope*scope) const;
private:
perm_string name_;
PScope*parent_;
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 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
@ -16,16 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PTask.cc,v 1.7 2002/08/12 01:34:58 steve Exp $"
#endif
# include "config.h"
# include "PTask.h"
PTask::PTask()
: ports_(0), statement_(0)
PTask::PTask(perm_string name, PScope*parent)
: PScope(name, parent), ports_(0), statement_(0)
{
}

73
PTask.h
View File

@ -1,7 +1,7 @@
#ifndef __PTask_H
#define __PTask_H
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 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
@ -18,11 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PTask.h,v 1.14 2007/03/06 05:22:49 steve Exp $"
#endif
# include "LineInfo.h"
# include "PScope.h"
# include "svector.h"
# include "StringHeap.h"
# include <string>
@ -50,10 +48,10 @@ struct PTaskFuncArg {
/*
* The PTask holds the parsed definitions of a task.
*/
class PTask : public LineInfo {
class PTask : public PScope, public LineInfo {
public:
explicit PTask();
explicit PTask(perm_string name, PScope*parent);
~PTask();
void set_ports(svector<PWire *>*p);
@ -89,10 +87,10 @@ class PTask : public LineInfo {
*
* The output value is not elaborated until elaborate_sig.
*/
class PFunction : public LineInfo {
class PFunction : public PScope, public LineInfo {
public:
explicit PFunction(perm_string name);
explicit PFunction(perm_string name, PScope*parent);
~PFunction();
void set_ports(svector<PWire *>*p);
@ -110,68 +108,9 @@ class PFunction : public LineInfo {
void dump(ostream&, unsigned) const;
private:
perm_string name_;
PTaskFuncArg return_type_;
svector<PWire *> *ports_;
Statement *statement_;
};
/*
* $Log: PTask.h,v $
* Revision 1.14 2007/03/06 05:22:49 steve
* Support signed function return values.
*
* Revision 1.13 2004/05/31 23:34:36 steve
* Rewire/generalize parsing an elaboration of
* function return values to allow for better
* speed and more type support.
*
* Revision 1.12 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.11 2001/11/22 06:20:59 steve
* Use NetScope instead of string for scope path.
*
* Revision 1.10 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.9 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.8 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.7 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 1999/09/30 21:28:34 steve
* Handle mutual reference of tasks by elaborating
* task definitions in two passes, like functions.
*
* Revision 1.5 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.4 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.3 1999/07/31 19:14:47 steve
* Add functions up to elaboration (Ed Carter)
*
* Revision 1.2 1999/07/24 02:11:19 steve
* Elaborate task input ports.
*
* Revision 1.1 1999/07/03 02:12:51 steve
* Elaborate user defined tasks.
*
*/
#endif

View File

@ -22,11 +22,11 @@
# include "PExpr.h"
# include <assert.h>
PWire::PWire(const pform_name_t&n,
PWire::PWire(perm_string n,
NetNet::Type t,
NetNet::PortType pt,
ivl_variable_type_t dt)
: hname_(n), type_(t), port_type_(pt), data_type_(dt),
: name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false), isint_(false),
port_msb_(0), port_lsb_(0), port_set_(false),
net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0),
@ -44,9 +44,9 @@ NetNet::Type PWire::get_wire_type() const
return type_;
}
const pform_name_t& PWire::path() const
perm_string PWire::basename() const
{
return hname_;
return name_;
}
bool PWire::set_wire_type(NetNet::Type t)
@ -153,7 +153,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
switch (type) {
case SR_PORT:
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << hname_
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
} else {
@ -165,7 +165,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
case SR_NET:
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << hname_
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {
@ -178,12 +178,12 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
case SR_BOTH:
if (port_set_ || net_set_) {
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << hname_
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
}
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << hname_
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
}
@ -202,7 +202,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
{
if (lidx_ != 0 || ridx_ != 0) {
cerr << get_fileline() << ": error: Array ``" << hname_
cerr << get_fileline() << ": error: Array ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {

View File

@ -56,13 +56,13 @@ enum PWSRType {SR_PORT, SR_NET, SR_BOTH};
class PWire : public LineInfo {
public:
PWire(const pform_name_t&hname,
PWire(perm_string name,
NetNet::Type t,
NetNet::PortType pt,
ivl_variable_type_t dt);
// Return a hierarchical name.
const pform_name_t&path() const;
perm_string basename() const;
NetNet::Type get_wire_type() const;
bool set_wire_type(NetNet::Type);
@ -90,7 +90,7 @@ class PWire : public LineInfo {
NetNet* elaborate_sig(Design*, NetScope*scope) const;
private:
pform_name_t hname_;
perm_string name_;
NetNet::Type type_;
NetNet::PortType port_type_;
ivl_variable_type_t data_type_;

View File

@ -86,18 +86,13 @@ PAssignNB::~PAssignNB()
{
}
PBlock::PBlock(perm_string n, BL_TYPE t, const svector<Statement*>&st)
: name_(n), bl_type_(t), list_(st)
{
}
PBlock::PBlock(BL_TYPE t, const svector<Statement*>&st)
: bl_type_(t), list_(st)
PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t)
: PScope(n, parent), bl_type_(t)
{
}
PBlock::PBlock(BL_TYPE t)
: bl_type_(t)
: PScope(perm_string(),0), bl_type_(t)
{
}
@ -107,6 +102,11 @@ PBlock::~PBlock()
delete list_[idx];
}
void PBlock::set_statement(const svector<Statement*>&st)
{
list_ = st;
}
PCallTask::PCallTask(const pform_name_t&n, const svector<PExpr*>&p)
: path_(n), parms_(p)
{

View File

@ -27,6 +27,7 @@
# include "StringHeap.h"
# include "PDelays.h"
# include "PExpr.h"
# include "PScope.h"
# include "HName.h"
# include "LineInfo.h"
class PExpr;
@ -83,6 +84,7 @@ class Statement : public LineInfo {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
};
/*
@ -147,25 +149,27 @@ class PAssignNB : public PAssign_ {
* statements before constructing this object, so it knows a priori
* what is contained.
*/
class PBlock : public Statement {
class PBlock : public PScope, public Statement {
public:
enum BL_TYPE { BL_SEQ, BL_PAR };
explicit PBlock(perm_string n, BL_TYPE t, const svector<Statement*>&st);
explicit PBlock(BL_TYPE t, const svector<Statement*>&st);
// If the block has a name, it is a scope and also has a parent.
explicit PBlock(perm_string n, PScope*parent, BL_TYPE t);
// If it doesn't have a name, it's not a scope
explicit PBlock(BL_TYPE t);
~PBlock();
BL_TYPE bl_type() const { return bl_type_; }
void set_statement(const svector<Statement*>&st);
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
private:
perm_string name_;
const BL_TYPE bl_type_;
svector<Statement*>list_;
};
@ -215,6 +219,7 @@ class PCase : public Statement {
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@ -250,6 +255,7 @@ class PCondit : public Statement {
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@ -284,6 +290,7 @@ class PDelayStatement : public Statement {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
private:
PExpr*delay_;
@ -331,6 +338,7 @@ class PEventStatement : public Statement {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
// This method is used to elaborate, but attach a previously
// elaborated statement to the event.
@ -364,6 +372,7 @@ class PForever : public Statement {
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@ -379,6 +388,7 @@ class PForStatement : public Statement {
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:

View File

@ -309,8 +309,14 @@ void NetPow::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_POW (NetPow): " << name()
<< " scope=" << scope_path(scope())
<< " delay=(" << *rise_time() << "," << *fall_time() << ","
<< *decay_time() << ")" << endl;
<< " delay=(";
if (rise_time())
o << *rise_time() << "," << *fall_time() << ","
<< *decay_time();
else
o << "0,0,0";
o << ")" << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
@ -987,7 +993,10 @@ void NetScope::dump(ostream&o) const
o << " MISSING FUNCTION DEFINITION" << endl;
break;
case TASK:
if (task_def())
task_def()->dump(o, 4);
else
o << " MISSING TASK DEFINITION" << endl;
break;
default:
break;

View File

@ -794,8 +794,8 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
{
NetScope*my_scope = scope;
if (name_ != 0) {
hname_t use_name(name_);
if (pscope_name() != 0) {
hname_t use_name(pscope_name());
if (scope->child(use_name)) {
cerr << get_fileline() << ": error: block/scope name "
<< use_name << " already used in this context."

View File

@ -28,46 +28,58 @@
# include "PGenerate.h"
# include "PTask.h"
# include "PWire.h"
# include "Statement.h"
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "util.h"
# include "ivl_assert.h"
/*
* This local function checks if a named signal is connected to a
* port. It looks in the array of ports passed, for NetEIdent objects
* within the port_t that have a matching name.
*/
static bool signal_is_in_port(const svector<Module::port_t*>&ports,
NetNet*sig)
void Statement::elaborate_sig(Design*des, NetScope*scope) const
{
perm_string name = sig->name();
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
Module::port_t*pp = ports[idx];
// Skip internally unconnected ports.
if (pp == 0)
continue;
// This port has an internal connection. In this case,
// the port has 0 or more NetEIdent objects concatenated
// together that form the port.
// Note that module ports should not have any hierarchy
// in their names: they are in the root of the module
// scope by definition.
for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) {
perm_string pname = peek_tail_name(pp->expr[cc]->path());
assert(pp->expr[cc]);
if (pname == name)
return true;
}
}
return false;
bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
{
bool flag = true;
for (map<perm_string,PWire*>::const_iterator wt = wires.begin()
; wt != wires.end() ; wt ++ ) {
PWire*cur = (*wt).second;
NetNet*sig = cur->elaborate_sig(des, scope);
/* If the signal is an input and is also declared as a
reg, then report an error. */
if (sig && (sig->scope() == scope)
&& (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINPUT)
&& (sig->type() == NetNet::REG)) {
cerr << cur->get_fileline() << ": error: "
<< cur->basename() << " in "
<< scope->module_name()
<< " declared as input and as a reg type." << endl;
des->errors += 1;
}
if (sig && (sig->scope() == scope)
&& (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINOUT)
&& (sig->type() == NetNet::REG)) {
cerr << cur->get_fileline() << ": error: "
<< cur->basename() << " in "
<< scope->module_name()
<< " declared as inout and as a reg type." << endl;
des->errors += 1;
}
}
return flag;
}
bool Module::elaborate_sig(Design*des, NetScope*scope) const
@ -81,15 +93,27 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
if (pp == 0)
continue;
map<pform_name_t,PWire*>::const_iterator wt;
// The port has a name and an array of expressions. The
// expression are all identifiers that should reference
// wires within the scope.
map<perm_string,PWire*>::const_iterator wt;
for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) {
pform_name_t port_path (pp->expr[cc]->path());
wt = wires_.find(port_path);
// A concatenated wire of a port really should not
// have any hierarchy.
if (port_path.size() != 1) {
cerr << get_fileline() << ": internal error: "
<< "Port " << port_path << " has a funny name?"
<< endl;
des->errors += 1;
}
if (wt == wires_.end()) {
wt = wires.find(peek_tail_name(port_path));
if (wt == wires.end()) {
cerr << get_fileline() << ": error: "
<< "Port " << pp->expr[cc]->path() << " ("
<< (idx+1) << ") of module " << name_
<< "Port " << port_path << " ("
<< (idx+1) << ") of module " << mod_name()
<< " is not declared within module." << endl;
des->errors += 1;
continue;
@ -98,7 +122,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
if ((*wt).second->get_port_type() == NetNet::NOT_A_PORT) {
cerr << get_fileline() << ": error: "
<< "Port " << pp->expr[cc]->path() << " ("
<< (idx+1) << ") of module " << name_
<< (idx+1) << ") of module " << mod_name()
<< " has no direction declaration."
<< endl;
des->errors += 1;
@ -106,58 +130,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
}
}
for (map<pform_name_t,PWire*>::const_iterator wt = wires_.begin()
; wt != wires_.end() ; wt ++ ) {
PWire*cur = (*wt).second;
NetNet*sig = cur->elaborate_sig(des, scope);
// If this wire is a signal of the module (as opposed to
// a port of a function) and is a port, then check that
// the module knows about it. We know that the signal is
// the name of a signal within a subscope of a module
// (a task, a function, etc.) if the name for the PWire
// has hierarchy.
if (sig && (sig->scope() == scope)
&& (cur->get_port_type() != NetNet::NOT_A_PORT)) {
if (! signal_is_in_port(ports, sig)) {
cerr << cur->get_fileline() << ": error: Signal "
<< sig->name() << " has a declared direction "
<< "but is not a port." << endl;
des->errors += 1;
}
}
/* If the signal is an input and is also declared as a
reg, then report an error. */
if (sig && (sig->scope() == scope)
&& (sig->port_type() == NetNet::PINPUT)
&& (sig->type() == NetNet::REG)) {
cerr << cur->get_fileline() << ": error: "
<< cur->path() << " in module "
<< scope->module_name()
<< " declared as input and as a reg type." << endl;
des->errors += 1;
}
if (sig && (sig->scope() == scope)
&& (sig->port_type() == NetNet::PINOUT)
&& (sig->type() == NetNet::REG)) {
cerr << cur->get_fileline() << ": error: "
<< cur->path() << " in module "
<< scope->module_name()
<< " declared as inout and as a reg type." << endl;
des->errors += 1;
}
}
flag = elaborate_sig_wires_(des, scope) && flag;
// Run through all the generate schemes to elaborate the
// signals that they hold. Note that the generate schemes hold
@ -216,6 +189,18 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
(*cur).second->elaborate_sig(des, tscope);
}
// initial and always blocks may contain begin-end and
// fork-join blocks that can introduce scopes. Therefore, I
// get to scan processes here.
typedef list<PProcess*>::const_iterator proc_it_t;
for (proc_it_t cur = behaviors_.begin()
; cur != behaviors_.end() ; cur ++ ) {
(*cur) -> statement() -> elaborate_sig(des, scope);
}
return flag;
}
@ -276,7 +261,7 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
{
// Scan the declared PWires to elaborate the obvious signals
// in the current scope.
typedef map<pform_name_t,PWire*>::const_iterator wires_it_t;
typedef map<perm_string,PWire*>::const_iterator wires_it_t;
for (wires_it_t wt = wires.begin()
; wt != wires.end() ; wt ++ ) {
@ -284,7 +269,7 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
if (debug_elaborate)
cerr << get_fileline() << ": debug: Elaborate PWire "
<< cur->path() << " in scope " << scope_path(scope) << endl;
<< cur->basename() << " in scope " << scope_path(scope) << endl;
cur->elaborate_sig(des, scope);
}
@ -316,6 +301,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
perm_string fname = scope->basename();
assert(scope->type() == NetScope::FUNC);
elaborate_sig_wires_(des, scope);
/* Make sure the function has at least one input port. If it
fails this test, print an error message. Keep going so we
can find more errors. */
@ -416,19 +403,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
name. We know by design that the port name is given
as two components: <func>.<port>. */
pform_name_t path = (*ports_)[idx]->path();
ivl_assert(*this, path.size() == 2);
perm_string pname = peek_tail_name(path);
perm_string ppath = peek_head_name(path);
if (ppath != scope->basename()) {
cerr << get_fileline() << ": internal error: function "
<< "port " << (*ports_)[idx]->path()
<< " has wrong name for function "
<< scope_path(scope) << "." << endl;
des->errors += 1;
}
perm_string pname = (*ports_)[idx]->basename();
NetNet*tmp = scope->find_signal(pname);
if (tmp == 0) {
@ -449,6 +424,10 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
assert(def);
scope->set_func_def(def);
// Look for further signals in the sub-statement
if (statement_)
statement_->elaborate_sig(des, scope);
}
/*
@ -464,24 +443,12 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
{
assert(scope->type() == NetScope::TASK);
elaborate_sig_wires_(des, scope);
svector<NetNet*>ports (ports_? ports_->count() : 0);
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
/* Parse the port name into the task name and the reg
name. We know by design that the port name is given
as two components: <task>.<port>. */
pform_name_t path = (*ports_)[idx]->path();
ivl_assert(*this, path.size() == 2);
perm_string scope_name = peek_head_name(path);
perm_string port_name = peek_tail_name(path);
/* check that the current scope really does have the
name of the first component of the task port name. Do
this by looking up the task scope in the parent of
the current scope. */
ivl_assert(*this, scope->basename() == scope_name);
perm_string port_name = (*ports_)[idx]->basename();
/* Find the signal for the port. We know by definition
that it is in the scope of the task, so look only in
@ -493,6 +460,7 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
<< "Could not find port " << port_name
<< " in scope " << scope_path(scope) << endl;
scope->dump(cerr);
des->errors += 1;
}
ports[idx] = tmp;
@ -500,6 +468,82 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
NetTaskDef*def = new NetTaskDef(scope, ports);
scope->set_task_def(def);
// Look for further signals in the sub-statement
if (statement_)
statement_->elaborate_sig(des, scope);
}
void PBlock::elaborate_sig(Design*des, NetScope*scope) const
{
NetScope*my_scope = scope;
if (pscope_name() != 0) {
hname_t use_name (pscope_name());
my_scope = scope->child(use_name);
if (my_scope == 0) {
cerr << get_fileline() << ": internal error: "
<< "Unable to find child scope " << pscope_name()
<< " in this context?" << endl;
des->errors += 1;
my_scope = scope;
} else {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "elaborate_sig descending into "
<< scope_path(my_scope) << "." << endl;
elaborate_sig_wires_(des, my_scope);
}
}
// elaborate_sig in the statements included in the
// block. There may be named blocks in there.
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1)
list_[idx] -> elaborate_sig(des, my_scope);
}
void PCase::elaborate_sig(Design*des, NetScope*scope) const
{
if (items_ == 0)
return;
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
if ( (*items_)[idx]->stat )
(*items_)[idx]->stat ->elaborate_sig(des,scope);
}
}
void PCondit::elaborate_sig(Design*des, NetScope*scope) const
{
if (if_)
if_->elaborate_sig(des, scope);
if (else_)
else_->elaborate_sig(des, scope);
}
void PDelayStatement::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)
statement_->elaborate_sig(des, scope);
}
void PEventStatement::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)
statement_->elaborate_sig(des, scope);
}
void PForever::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)
statement_->elaborate_sig(des, scope);
}
void PForStatement::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)
statement_->elaborate_sig(des, scope);
}
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
@ -516,27 +560,6 @@ bool PGate::elaborate_sig(Design*des, NetScope*scope) const
*/
NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
{
/* The parser may produce hierarchical names for wires. I here
follow the scopes down to the base where I actually want to
elaborate the NetNet object. */
{ pform_name_t tmp_path = hname_;
tmp_path.pop_back();
while (! tmp_path.empty()) {
name_component_t cur = tmp_path.front();
tmp_path.pop_front();
scope = scope->child( hname_t(cur.name) );
if (scope == 0) {
cerr << get_fileline() << ": internal error: "
<< "Bad scope component for name "
<< hname_ << endl;
assert(scope);
}
}
}
NetNet::Type wtype = type_;
if (wtype == NetNet::IMPLICIT)
wtype = NetNet::WIRE;
@ -619,12 +642,12 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (port_msb_ == 0) {
if (!gn_io_range_error_flag) {
cerr << get_fileline()
<< ": warning: Scalar port ``" << hname_
<< ": warning: Scalar port ``" << name_
<< "'' has a vectored net declaration ["
<< nmsb << ":" << nlsb << "]." << endl;
} else {
cerr << get_fileline()
<< ": error: Scalar port ``" << hname_
<< ": error: Scalar port ``" << name_
<< "'' has a vectored net declaration ["
<< nmsb << ":" << nlsb << "]." << endl;
des->errors += 1;
@ -636,7 +659,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (net_msb_ == 0) {
cerr << port_msb_->get_fileline()
<< ": error: Vectored port ``"
<< hname_ << "'' [" << pmsb << ":" << plsb
<< name_ << "'' [" << pmsb << ":" << plsb
<< "] has a scalar net declaration at "
<< get_fileline() << "." << endl;
des->errors += 1;
@ -647,7 +670,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (port_msb_ != 0 && net_msb_ != 0) {
cerr << port_msb_->get_fileline()
<< ": error: Vectored port ``"
<< hname_ << "'' [" << pmsb << ":" << plsb
<< name_ << "'' [" << pmsb << ":" << plsb
<< "] has a net declaration [" << nmsb << ":"
<< nlsb << "] at " << net_msb_->get_fileline()
<< " that does not match." << endl;
@ -687,7 +710,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if ((lexp == 0) || (rexp == 0)) {
cerr << get_fileline() << ": internal error: There is "
<< "a problem evaluating indices for ``"
<< hname_ << "''." << endl;
<< name_ << "''." << endl;
des->errors += 1;
return 0;
}
@ -698,7 +721,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if ((lcon == 0) || (rcon == 0)) {
cerr << get_fileline() << ": internal error: The indices "
<< "are not constant for array ``"
<< hname_ << "''." << endl;
<< name_ << "''." << endl;
des->errors += 1;
return 0;
}
@ -748,24 +771,23 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
}
perm_string name = peek_tail_name(hname_);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal "
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name_
<< " in scope " << scope_path(scope) << endl;
}
NetNet*sig = array_dimensions > 0
? new NetNet(scope, name, wtype, msb, lsb, array_s0, array_e0)
: new NetNet(scope, name, wtype, msb, lsb);
? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0)
: new NetNet(scope, name_, wtype, msb, lsb);
ivl_variable_type_t use_data_type = data_type_;
if (use_data_type == IVL_VT_NO_TYPE) {
use_data_type = IVL_VT_LOGIC;
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Signal " << name
<< "Signal " << name_
<< " in scope " << scope_path(scope)
<< " defaults to data type " << use_data_type << endl;
}

View File

@ -1866,12 +1866,12 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
: NetBlock::SEQU;
NetScope*nscope = 0;
if (name_.str() != 0) {
nscope = scope->child(hname_t(name_));
if (pscope_name() != 0) {
nscope = scope->child(hname_t(pscope_name()));
if (nscope == 0) {
cerr << get_fileline() << ": internal error: "
"unable to find block scope " << scope_path(scope)
<< "<" << name_ << ">" << endl;
<< "<" << pscope_name() << ">" << endl;
des->errors += 1;
return 0;
}
@ -1889,7 +1889,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
// statement. There is no need to keep the block node. Also,
// don't elide named blocks, because they might be referenced
// elsewhere.
if ((list_.count() == 1) && (name_.str() == 0)) {
if ((list_.count() == 1) && (pscope_name() == 0)) {
assert(list_[0]);
NetProc*tmp = list_[0]->elaborate(des, nscope);
return tmp;
@ -2934,7 +2934,7 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
NetNet*sig = des->find_signal(scope, id1->path());
if (sig == 0) {
cerr << id1->get_fileline() << ": register ``" << id1->path()
<< "'' unknown in this context." << endl;
<< "'' unknown in " << scope_path(scope) << "." << endl;
des->errors += 1;
return 0;
}

View File

@ -295,10 +295,10 @@ void NetScope::rem_event(NetEvent*ev)
}
NetEvent* NetScope::find_event(const char*name)
NetEvent* NetScope::find_event(perm_string name)
{
for (NetEvent*cur = events_; cur ; cur = cur->snext_)
if (strcmp(cur->name(), name) == 0)
if (cur->name() == name)
return cur;
return 0;
@ -337,7 +337,7 @@ void NetScope::rem_signal(NetNet*net)
* is assumed to be the base name of the signal, so no sub-scopes are
* searched.
*/
NetNet* NetScope::find_signal(const char*key)
NetNet* NetScope::find_signal(perm_string key)
{
if (signals_ == 0)
return 0;

View File

@ -3275,7 +3275,7 @@ class NetScope : public Attrib {
void add_event(NetEvent*);
void rem_event(NetEvent*);
NetEvent*find_event(const char*name);
NetEvent*find_event(perm_string name);
/* These methods manage signals. The add_ and rem_signal
@ -3285,7 +3285,7 @@ class NetScope : public Attrib {
void add_signal(NetNet*);
void rem_signal(NetNet*);
NetNet* find_signal(const char*name);
NetNet* find_signal(perm_string name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */

182
parse.y
View File

@ -26,6 +26,7 @@
# include "pform.h"
# include "Statement.h"
# include "PSpec.h"
# include <stack>
# include <cstring>
# include <sstream>
@ -45,6 +46,12 @@ static struct {
svector<PExpr*>* range;
} port_declaration_context;
/* 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;
static PFunction* current_function = 0;
static stack<PBlock*> current_block_stack;
/* Later version of bison (including 1.35) will not compile in stack
extension if the output is compiled with C++ and either the YYSTYPE
or YYLTYPE are provided by the source code. However, I can get the
@ -191,7 +198,8 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
%type <perm_strings> udp_input_declaration_list
%type <strings> udp_entry_list udp_comb_entry_list udp_sequ_entry_list
%type <strings> udp_body udp_port_list
%type <strings> udp_body
%type <perm_strings> udp_port_list
%type <wires> udp_port_decl udp_port_decls
%type <statement> udp_initial udp_init_opt
%type <expr> udp_initial_expr_opt
@ -1405,28 +1413,18 @@ list_of_port_declarations
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(1);
(*tmp)[0] = $1;
/*
* Uncommenting this makes lopd always fully specified.
* Some wanted an implicit net to not be fully defined.
*
* pform_set_net_range($1[0].name);
*/
$$ = tmp;
}
| list_of_port_declarations ',' port_declaration
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, $3);
delete $1;
/*
* Same as above.
*
* pform_set_net_range($3[0].name);
*/
$$ = tmp;
}
| list_of_port_declarations ',' IDENTIFIER
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($3, @3.text,
perm_string name = lex_strings.make($3);
ptmp = pform_module_port_reference(name, @3.text,
@3.first_line);
svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, ptmp);
@ -1434,17 +1432,13 @@ list_of_port_declarations
/* Get the port declaration details, the port type
and what not, from context data stored by the
last port_declaration rule. */
pform_module_define_port(@3, $3,
pform_module_define_port(@3, name,
port_declaration_context.port_type,
port_declaration_context.port_net_type,
port_declaration_context.sign_flag,
port_declaration_context.range, 0);
delete $1;
/*
* Same as above.
*
* pform_set_net_range($3);
*/
delete $3;
$$ = tmp;
}
| list_of_port_declarations ','
@ -1463,9 +1457,10 @@ port_declaration
: attribute_list_opt
K_input net_type_opt signed_opt range_opt IDENTIFIER
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($6, @2.text,
perm_string name = lex_strings.make($6);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
pform_module_define_port(@2, $6, NetNet::PINPUT,
pform_module_define_port(@2, name, NetNet::PINPUT,
$3, $4, $5, $1);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = $3;
@ -1478,9 +1473,10 @@ port_declaration
| attribute_list_opt
K_inout net_type_opt signed_opt range_opt IDENTIFIER
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($6, @2.text,
perm_string name = lex_strings.make($6);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
pform_module_define_port(@2, $6, NetNet::PINOUT,
pform_module_define_port(@2, name, NetNet::PINOUT,
$3, $4, $5, $1);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.port_net_type = $3;
@ -1493,9 +1489,10 @@ port_declaration
| attribute_list_opt
K_output net_type_opt signed_opt range_opt IDENTIFIER
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($6, @2.text,
perm_string name = lex_strings.make($6);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
pform_module_define_port(@2, $6, NetNet::POUTPUT,
pform_module_define_port(@2, name, NetNet::POUTPUT,
$3, $4, $5, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = $3;
@ -1508,9 +1505,10 @@ port_declaration
| attribute_list_opt
K_output var_type signed_opt range_opt IDENTIFIER
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($6, @2.text,
perm_string name = lex_strings.make($6);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
pform_module_define_port(@2, $6, NetNet::POUTPUT,
pform_module_define_port(@2, name, NetNet::POUTPUT,
$3, $4, $5, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = $3;
@ -1523,9 +1521,10 @@ port_declaration
| attribute_list_opt
K_output var_type signed_opt range_opt IDENTIFIER '=' expression
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($6, @2.text,
perm_string name = lex_strings.make($6);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
pform_module_define_port(@2, $6, NetNet::POUTPUT,
pform_module_define_port(@2, name, NetNet::POUTPUT,
$3, $4, $5, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = $3;
@ -1535,7 +1534,7 @@ port_declaration
if (! pform_expression_is_constant($8))
yyerror(@8, "error: register declaration assignment"
" value must be a constant expression.");
pform_make_reginit(@6, $6, $8);
pform_make_reginit(@6, name, $8);
delete $1;
delete $6;
@ -1843,33 +1842,33 @@ module_item
extension. */
| K_task IDENTIFIER ';'
{ pform_push_scope($2); }
{ assert(current_task == 0);
current_task = pform_push_task_scope($2);
FILE_NAME(current_task, @1);
}
task_item_list_opt
statement_or_null
K_endtask
{ PTask*tmp = new PTask;
perm_string tmp2 = lex_strings.make($2);
FILE_NAME(tmp, @1);
tmp->set_ports($5);
tmp->set_statement($6);
pform_set_task(tmp2, tmp);
{ current_task->set_ports($5);
current_task->set_statement($6);
pform_pop_scope();
current_task = 0;
delete $2;
}
| K_task IDENTIFIER
{ pform_push_scope($2); }
{ assert(current_task == 0);
current_task = pform_push_task_scope($2);
FILE_NAME(current_task, @1);
}
'(' task_port_decl_list ')' ';'
task_item_list_opt
statement_or_null
K_endtask
{ PTask*tmp = new PTask;
perm_string tmp2 = lex_strings.make($2);
FILE_NAME(tmp, @1);
tmp->set_ports($5);
tmp->set_statement($9);
pform_set_task(tmp2, tmp);
{ current_task->set_ports($5);
current_task->set_statement($9);
pform_pop_scope();
current_task = 0;
delete $2;
}
@ -1879,17 +1878,16 @@ module_item
instead of the module. */
| K_function function_range_or_type_opt IDENTIFIER ';'
{ pform_push_scope($3); }
{ assert(current_function == 0);
current_function = pform_push_function_scope($3);
}
function_item_list statement
K_endfunction
{ perm_string name = lex_strings.make($3);
PFunction *tmp = new PFunction(name);
FILE_NAME(tmp, @1);
tmp->set_ports($6);
tmp->set_statement($7);
tmp->set_return($2);
pform_set_function(name, tmp);
{ current_function->set_ports($6);
current_function->set_statement($7);
current_function->set_return($2);
pform_pop_scope();
current_function = 0;
delete $3;
}
@ -2039,8 +2037,9 @@ net_decl_assign
: IDENTIFIER '=' expression
{ net_decl_assign_t*tmp = new net_decl_assign_t;
tmp->next = tmp;
tmp->name = $1;
tmp->name = lex_strings.make($1);
tmp->expr = $3;
delete $1;
$$ = tmp;
}
;
@ -2319,7 +2318,8 @@ port_reference
: IDENTIFIER
{ Module::port_t*ptmp;
ptmp = pform_module_port_reference($1, @1.text, @1.first_line);
perm_string name = lex_strings.make($1);
ptmp = pform_module_port_reference(name, @1.text, @1.first_line);
delete $1;
$$ = ptmp;
}
@ -2530,7 +2530,8 @@ function_range_or_type_opt
so that bit ranges can be assigned. */
register_variable
: IDENTIFIER dimensions_opt
{ pform_makewire(@1, $1, NetNet::REG,
{ perm_string ident_name = lex_strings.make($1);
pform_makewire(@1, ident_name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
if ($2 != 0) {
index_component_t index;
@ -2539,19 +2540,19 @@ register_variable
"are currently supported.");
}
index = $2->front();
pform_set_reg_idx($1, index.msb, index.lsb);
pform_set_reg_idx(ident_name, index.msb, index.lsb);
delete $2;
}
$$ = $1;
}
| IDENTIFIER '=' expression
{ pform_makewire(@1, $1, NetNet::REG,
NetNet::NOT_A_PORT,
IVL_VT_NO_TYPE, 0);
{ perm_string ident_name = lex_strings.make($1);
pform_makewire(@1, ident_name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
if (! pform_expression_is_constant($3))
yyerror(@3, "error: register declaration assignment"
" value must be a constant expression.");
pform_make_reginit(@1, $1, $3);
pform_make_reginit(@1, ident_name, $3);
$$ = $1;
}
;
@ -2573,7 +2574,8 @@ register_variable_list
real_variable
: IDENTIFIER dimensions_opt
{ pform_makewire(@1, $1, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
if ($2 != 0) {
yyerror(@2, "sorry: real variables do not currently support arrays.");
delete $2;
@ -2581,8 +2583,9 @@ real_variable
$$ = $1;
}
| IDENTIFIER '=' expression
{ pform_makewire(@1, $1, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
pform_make_reginit(@1, $1, $3);
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
pform_make_reginit(@1, name, $3);
$$ = $1;
}
;
@ -2604,7 +2607,8 @@ real_variable_list
net_variable
: IDENTIFIER dimensions_opt
{ pform_makewire(@1, $1, NetNet::IMPLICIT,
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::IMPLICIT,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
if ($2 != 0) {
index_component_t index;
@ -2613,12 +2617,13 @@ net_variable
"are currently supported.");
}
index = $2->front();
pform_set_reg_idx($1, index.msb, index.lsb);
pform_set_reg_idx(name, index.msb, index.lsb);
delete $2;
}
$$ = $1;
}
;
net_variable_list
: net_variable
{ list<perm_string>*tmp = new list<perm_string>;
@ -2962,19 +2967,24 @@ statement
the declarations. The scope is popped at the end of the block. */
| K_begin statement_list K_end
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ, *$2);
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ);
FILE_NAME(tmp, @1);
tmp->set_statement(*$2);
delete $2;
$$ = tmp;
}
| K_begin ':' IDENTIFIER
{ pform_push_scope($3); }
{ PBlock*tmp = pform_push_block_scope($3, PBlock::BL_SEQ);
FILE_NAME(tmp, @1);
current_block_stack.push(tmp);
}
block_item_decls_opt
statement_list K_end
{ pform_pop_scope();
PBlock*tmp = new PBlock(lex_strings.make($3),
PBlock::BL_SEQ, *$6);
FILE_NAME(tmp, @1);
assert(! current_block_stack.empty());
PBlock*tmp = current_block_stack.top();
current_block_stack.pop();
tmp->set_statement(*$6);
delete $3;
delete $6;
$$ = tmp;
@ -2998,13 +3008,17 @@ statement
code generator can do the right thing. */
| K_fork ':' IDENTIFIER
{ pform_push_scope($3); }
{ PBlock*tmp = pform_push_block_scope($3, PBlock::BL_PAR);
FILE_NAME(tmp, @1);
current_block_stack.push(tmp);
}
block_item_decls_opt
statement_list K_join
{ pform_pop_scope();
PBlock*tmp = new PBlock(lex_strings.make($3),
PBlock::BL_PAR, *$6);
FILE_NAME(tmp, @1);
assert(! current_block_stack.empty());
PBlock*tmp = current_block_stack.top();
current_block_stack.pop();
tmp->set_statement(*$6);
delete $3;
delete $6;
$$ = tmp;
@ -3039,8 +3053,9 @@ statement
$$ = tmp;
}
| K_fork statement_list K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2);
{ PBlock*tmp = new PBlock(PBlock::BL_PAR);
FILE_NAME(tmp, @1);
tmp->set_statement(*$2);
delete $2;
$$ = tmp;
}
@ -3672,8 +3687,7 @@ udp_port_decl
: K_input list_of_identifiers ';'
{ $$ = pform_make_udp_input_ports($2); }
| K_output IDENTIFIER ';'
{ pform_name_t pname;
pname.push_back(name_component_t(lex_strings.make($2)));
{ perm_string pname = lex_strings.make($2);
PWire*pp = new PWire(pname, NetNet::IMPLICIT, NetNet::POUTPUT, IVL_VT_LOGIC);
svector<PWire*>*tmp = new svector<PWire*>(1);
(*tmp)[0] = pp;
@ -3681,8 +3695,7 @@ udp_port_decl
delete $2;
}
| K_reg IDENTIFIER ';'
{ pform_name_t pname;
pname.push_back(name_component_t(lex_strings.make($2)));
{ perm_string pname = lex_strings.make($2);
PWire*pp = new PWire(pname, NetNet::REG, NetNet::PIMPLICIT, IVL_VT_LOGIC);
svector<PWire*>*tmp = new svector<PWire*>(1);
(*tmp)[0] = pp;
@ -3690,8 +3703,7 @@ udp_port_decl
delete $2;
}
| K_reg K_output IDENTIFIER ';'
{ pform_name_t pname;
pname.push_back(name_component_t(lex_strings.make($3)));
{ perm_string pname = lex_strings.make($3);
PWire*pp = new PWire(pname, NetNet::REG, NetNet::POUTPUT, IVL_VT_LOGIC);
svector<PWire*>*tmp = new svector<PWire*>(1);
(*tmp)[0] = pp;
@ -3713,14 +3725,14 @@ udp_port_decls
udp_port_list
: IDENTIFIER
{ list<string>*tmp = new list<string>;
tmp->push_back($1);
{ list<perm_string>*tmp = new list<perm_string>;
tmp->push_back(lex_strings.make($1));
delete $1;
$$ = tmp;
}
| udp_port_list ',' IDENTIFIER
{ list<string>*tmp = $1;
tmp->push_back($3);
{ list<perm_string>*tmp = $1;
tmp->push_back(lex_strings.make($3));
delete $3;
$$ = tmp;
}

230
pform.cc
View File

@ -38,6 +38,7 @@
# include "ivl_assert.h"
map<perm_string,Module*> pform_modules;
map<perm_string,PUdp*> pform_primitives;
@ -88,40 +89,55 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
}
/*
* The scope stack and the following functions handle the processing
* of scope. As I enter a scope, the push function is called, and as I
* leave a scope the pop function is called. Entering tasks, functions
* and named blocks causes scope to be pushed and popped. The module
* name is not included in this scope stack.
* The lexical_scope keeps track of the current lexical scope that is
* being parsed. The lexical scope may stack, so the current scope may
* have a parent, that is restored when the current scope ends.
*
* The hier_name function, therefore, converts the name to the scoped
* name within the module currently in progress. It never includes an
* instance name.
*
* The scope stack does not include any scope created by a generate
* scheme.
* Items that have scoped names are put in the lexical_scope object.
*/
static pform_name_t scope_stack;
void pform_push_scope(char*name)
{
scope_stack.push_back(name_component_t(lex_strings.make(name)));
}
static PScope* lexical_scope = 0;
void pform_pop_scope()
{
scope_stack.pop_back();
lexical_scope = lexical_scope->pscope_parent();
}
static pform_name_t hier_name(const char*tail)
PTask* pform_push_task_scope(char*name)
{
pform_name_t name = scope_stack;
name.push_back(name_component_t(lex_strings.make(tail)));
return name;
perm_string task_name = lex_strings.make(name);
PTask*task = new PTask(task_name, pform_cur_module);
// Add the task to the current module
pform_cur_module->add_task(task->pscope_name(), task);
// Make this the current lexical scope
lexical_scope = task;
return task;
}
static PWire*get_wire_in_module(const pform_name_t&name)
PFunction* pform_push_function_scope(char*name)
{
perm_string func_name = lex_strings.make(name);
PFunction*func = new PFunction(func_name, lexical_scope);
// Add the task to the current module
pform_cur_module->add_function(func->pscope_name(), func);
// Make this the current lexical scope
lexical_scope = func;
return func;
}
PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
{
perm_string block_name = lex_strings.make(name);
PBlock*block = new PBlock(block_name, lexical_scope, bt);
// Make this the current lexical scope
lexical_scope = block;
return block;
}
static PWire*get_wire_in_scope(perm_string name)
{
/* Note that if we are processing a generate, then the
scope depth will be empty because generate schemes
@ -130,7 +146,7 @@ static PWire*get_wire_in_module(const pform_name_t&name)
if (pform_cur_generate)
return pform_cur_generate->get_wire(name);
return pform_cur_module->get_wire(name);
return lexical_scope->wires_find(name);
}
void pform_set_default_nettype(NetNet::Type type,
@ -259,6 +275,9 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno,
FILE_NAME(pform_cur_module, file, lineno);
pform_cur_module->library_flag = pform_library_flag;
ivl_assert(*pform_cur_module, lexical_scope == 0);
lexical_scope = pform_cur_module;
/* The generate scheme numbering starts with *1*, not
zero. That's just the way it is, thanks to the standard. */
scope_generate_counter = 1;
@ -285,14 +304,14 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno,
* reference. This is a name without a .X(...), so the internal name
* should be generated to be the same as the X.
*/
Module::port_t* pform_module_port_reference(char*name,
Module::port_t* pform_module_port_reference(perm_string name,
const char*file,
unsigned lineno)
{
Module::port_t*ptmp = new Module::port_t;
PEIdent*tmp = new PEIdent(lex_strings.make(name));
PEIdent*tmp = new PEIdent(name);
FILE_NAME(tmp, file, lineno);
ptmp->name = lex_strings.make(name);
ptmp->name = name;
ptmp->expr = svector<PEIdent*>(1);
ptmp->expr[0] = tmp;
@ -334,6 +353,13 @@ void pform_endmodule(const char*name)
pform_cur_module = 0;
return;
}
// The current lexical scope should be this module by now, and
// this module should not have a parent lexical scope.
ivl_assert(*pform_cur_module, lexical_scope == pform_cur_module);
lexical_scope = pform_cur_module->pscope_parent();
ivl_assert(*pform_cur_module, lexical_scope == 0);
pform_modules[mod_name] = pform_cur_module;
pform_cur_module = 0;
}
@ -545,6 +571,11 @@ PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max)
return res;
}
template <> inline svector<perm_string>::svector(unsigned size)
: nitems_(size), items_(new perm_string[size])
{
}
static void process_udp_table(PUdp*udp, list<string>*table,
const char*file, unsigned lineno)
{
@ -612,7 +643,7 @@ static void process_udp_table(PUdp*udp, list<string>*table,
udp->toutput = output;
}
void pform_make_udp(perm_string name, list<string>*parms,
void pform_make_udp(perm_string name, list<perm_string>*parms,
svector<PWire*>*decl, list<string>*table,
Statement*init_expr,
const char*file, unsigned lineno)
@ -624,11 +655,10 @@ void pform_make_udp(perm_string name, list<string>*parms,
off with the parameters in the list. If the port is already
in the map, merge the port type. I will rebuild a list
of parameters for the PUdp object. */
map<string,PWire*> defs;
map<perm_string,PWire*> defs;
for (unsigned idx = 0 ; idx < decl->count() ; idx += 1) {
pform_name_t pname = (*decl)[idx]->path();
string port_name = peek_tail_name(pname).str();
perm_string port_name = (*decl)[idx]->basename();
if (PWire*cur = defs[port_name]) {
bool rc = true;
@ -654,8 +684,8 @@ void pform_make_udp(perm_string name, list<string>*parms,
UDP declaration, and the defs map maps that name to a
PWire* created by an input or output declaration. */
svector<PWire*> pins (parms->size());
svector<string> pin_names (parms->size());
{ list<string>::iterator cur;
svector<perm_string> pin_names (parms->size());
{ list<perm_string>::iterator cur;
unsigned idx;
for (cur = parms->begin(), idx = 0
; cur != parms->end()
@ -789,7 +819,7 @@ void pform_make_udp(perm_string name, list<string>*parms,
// Make the port list for the UDP
for (unsigned idx = 0 ; idx < pins.count() ; idx += 1)
udp->ports[idx] = peek_tail_name(pins[idx]->path());
udp->ports[idx] = pins[idx]->basename();
process_udp_table(udp, table, file, lineno);
udp->initial = init;
@ -814,10 +844,9 @@ void pform_make_udp(perm_string name, bool synchronous_flag,
svector<PWire*> pins(parms->size() + 1);
/* Make the PWire for the output port. */
pins[0] = new PWire(hier_name(out_name),
pins[0] = new PWire(out_name,
synchronous_flag? NetNet::REG : NetNet::WIRE,
NetNet::POUTPUT,
IVL_VT_LOGIC);
NetNet::POUTPUT, IVL_VT_LOGIC);
FILE_NAME(pins[0], file, lineno);
/* Make the PWire objects for the input ports. */
@ -827,10 +856,8 @@ void pform_make_udp(perm_string name, bool synchronous_flag,
; cur != parms->end()
; idx += 1, cur++) {
assert(idx < pins.count());
pins[idx] = new PWire(hier_name(*cur),
NetNet::WIRE,
NetNet::PINPUT,
IVL_VT_LOGIC);
pins[idx] = new PWire(*cur, NetNet::WIRE,
NetNet::PINPUT, IVL_VT_LOGIC);
FILE_NAME(pins[idx], file, lineno);
}
assert(idx == pins.count());
@ -871,7 +898,7 @@ void pform_make_udp(perm_string name, bool synchronous_flag,
// Make the port list for the UDP
for (unsigned idx = 0 ; idx < pins.count() ; idx += 1)
udp->ports[idx] = peek_tail_name(pins[idx]->path());
udp->ports[idx] = pins[idx]->basename();
assert(udp);
assert(table);
@ -886,39 +913,18 @@ void pform_make_udp(perm_string name, bool synchronous_flag,
delete init_expr;
}
/*
* This function is used to set the net range for a port that uses
* the new (1364-2001) list_of_port_declarations, but omitted a
* register/wire/etc. that would have triggered it to be set elsewhere.
*/
/*
* Since implicitly defined list of port declarations are no longer
* considered fully defined we no longer need this routine to force
* them to be fully defined.
*
void pform_set_net_range(const char* name)
{
PWire*cur = get_wire_in_module(hier_name(name));
if (cur == 0) {
VLerror("error: name is not a valid net.");
return;
}
cur->set_net_range();
}
*/
/*
* This function attaches a range to a given name. The function is
* only called by the parser within the scope of the net declaration,
* and the name that I receive only has the tail component.
*/
static void pform_set_net_range(const char* name,
static void pform_set_net_range(perm_string name,
const svector<PExpr*>*range,
bool signed_flag,
ivl_variable_type_t dt,
PWSRType rt)
{
PWire*cur = get_wire_in_module(hier_name(name));
PWire*cur = get_wire_in_scope(name);
if (cur == 0) {
VLerror("error: name is not a valid net.");
return;
@ -1233,17 +1239,16 @@ void pform_make_pgassign_list(svector<PExpr*>*alist,
* BTF-B14.
*/
void pform_make_reginit(const struct vlltype&li,
const char*name, PExpr*expr)
perm_string name, PExpr*expr)
{
const pform_name_t sname = hier_name(name);
PWire*cur = pform_cur_module->get_wire(sname);
PWire*cur = lexical_scope->wires_find(name);
if (cur == 0) {
VLerror(li, "internal error: reginit to non-register?");
delete expr;
return;
}
PEIdent*lval = new PEIdent(sname);
PEIdent*lval = new PEIdent(name);
FILE_NAME(lval, li);
PAssign*ass = new PAssign(lval, expr);
FILE_NAME(ass, li);
@ -1264,18 +1269,17 @@ void pform_make_reginit(const struct vlltype&li,
* as is done for the old method.
*/
void pform_module_define_port(const struct vlltype&li,
const char*nm,
perm_string name,
NetNet::PortType port_type,
NetNet::Type type,
bool signed_flag,
svector<PExpr*>*range,
svector<named_pexpr_t*>*attr)
{
pform_name_t name = hier_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = lexical_scope->wires_find(name);
if (cur) {
ostringstream msg;
msg << nm << " definition conflicts with "
msg << name << " definition conflicts with "
<< "definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
@ -1306,7 +1310,7 @@ void pform_module_define_port(const struct vlltype&li,
cur->attributes[tmp->name] = tmp->parm;
}
}
pform_cur_module->add_wire(cur);
lexical_scope->wires[name] = cur;
}
/*
@ -1334,14 +1338,12 @@ void pform_module_define_port(const struct vlltype&li,
* the variable/net. Other forms of pform_makewire ultimately call
* this one to create the wire and stash it.
*/
void pform_makewire(const vlltype&li, const char*nm,
void pform_makewire(const vlltype&li, perm_string name,
NetNet::Type type, NetNet::PortType pt,
ivl_variable_type_t dt,
svector<named_pexpr_t*>*attr)
{
pform_name_t name = hier_name(nm);
PWire*cur = get_wire_in_module(name);
PWire*cur = get_wire_in_scope(name);
// If this is not implicit ("implicit" meaning we don't know
// what the type is yet) then set the type now.
@ -1349,7 +1351,7 @@ void pform_makewire(const vlltype&li, const char*nm,
bool rc = cur->set_wire_type(type);
if (rc == false) {
ostringstream msg;
msg << nm << " definition conflicts with "
msg << name << " definition conflicts with "
<< "definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
@ -1393,9 +1395,9 @@ void pform_makewire(const vlltype&li, const char*nm,
if (new_wire_flag) {
if (pform_cur_generate)
pform_cur_generate->add_wire(cur);
pform_cur_generate->wires[name] = cur;
else
pform_cur_module->add_wire(cur);
lexical_scope->wires[name] = cur;
}
}
@ -1455,32 +1457,28 @@ void pform_makewire(const vlltype&li,
SR_NET);
}
perm_string first_name = lex_strings.make(first->name);
pform_name_t name = hier_name(first_name);
PWire*cur = get_wire_in_module(name);
PWire*cur = get_wire_in_scope(first->name);
if (cur != 0) {
PEIdent*lval = new PEIdent(first_name);
PEIdent*lval = new PEIdent(first->name);
FILE_NAME(lval, li.text, li.first_line);
PGAssign*ass = pform_make_pgassign(lval, first->expr,
delay, str);
FILE_NAME(ass, li.text, li.first_line);
}
free(first->name);
delete first;
first = next;
}
}
void pform_set_port_type(perm_string nm, NetNet::PortType pt,
void pform_set_port_type(perm_string name, NetNet::PortType pt,
const char*file, unsigned lineno)
{
pform_name_t name = hier_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = lexical_scope->wires_find(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
FILE_NAME(cur, file, lineno);
pform_cur_module->add_wire(cur);
lexical_scope->wires[name] = cur;
}
switch (cur->get_port_type()) {
@ -1491,14 +1489,14 @@ void pform_set_port_type(perm_string nm, NetNet::PortType pt,
case NetNet::NOT_A_PORT:
cerr << file << ":" << lineno << ": error: "
<< "port " << nm << " is not in the port list."
<< "port " << name << " is not in the port list."
<< endl;
error_count += 1;
break;
default:
cerr << file << ":" << lineno << ": error: "
<< "port " << nm << " already has a port declaration."
<< "port " << name << " already has a port declaration."
<< endl;
error_count += 1;
break;
@ -1558,18 +1556,17 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; cur ++ ) {
perm_string txt = *cur;
pform_name_t name = hier_name(txt);
perm_string name = *cur;
/* Look for a preexisting wire. If it exists, set the
port direction. If not, create it. */
PWire*curw = pform_cur_module->get_wire(name);
PWire*curw = lexical_scope->wires_find(name);
if (curw) {
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
FILE_NAME(curw, file, lineno);
pform_cur_module->add_wire(curw);
lexical_scope->wires[name] = curw;
}
curw->set_signed(signed_flag);
@ -1590,22 +1587,9 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
return res;
}
void pform_set_task(perm_string name, PTask*task)
{
pform_cur_module->add_task(name, task);
}
void pform_set_function(perm_string name, PFunction*func)
{
pform_cur_module->add_function(name, func);
}
void pform_set_attrib(perm_string name, perm_string key, char*value)
{
pform_name_t path = hier_name(name);
if (PWire*cur = pform_cur_module->get_wire(path)) {
if (PWire*cur = lexical_scope->wires_find(name)) {
cur->attributes[key] = new PEString(value);
} else if (PGate*cur = pform_cur_module->get_gate(name)) {
@ -1639,13 +1623,13 @@ void pform_set_type_attrib(perm_string name, const string&key,
* This function attaches a memory index range to an existing
* register. (The named wire must be a register.
*/
void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r)
void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
{
PWire*cur = 0;
if (pform_cur_generate) {
cur = pform_cur_generate->get_wire(hier_name(name));
cur = pform_cur_generate->get_wire(name);
} else {
cur = pform_cur_module->get_wire(hier_name(name));
cur = lexical_scope->wires_find(name);
}
if (cur == 0) {
VLerror("internal error: name is not a valid memory for index.");
@ -1792,16 +1776,15 @@ void pform_set_port_type(const struct vlltype&li,
delete range;
}
static void pform_set_reg_integer(const char*nm)
static void pform_set_reg_integer(perm_string name)
{
pform_name_t name = hier_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = lexical_scope->wires_find(name);
if (cur == 0) {
cur = new PWire(name, NetNet::INTEGER,
NetNet::NOT_A_PORT,
IVL_VT_LOGIC);
cur->set_signed(true);
pform_cur_module->add_wire(cur);
lexical_scope->wires[name] = cur;
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
@ -1827,13 +1810,12 @@ void pform_set_reg_integer(list<perm_string>*names)
delete names;
}
static void pform_set_reg_time(const char*nm)
static void pform_set_reg_time(perm_string name)
{
pform_name_t name = hier_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = lexical_scope->wires_find(name);
if (cur == 0) {
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
pform_cur_module->add_wire(cur);
lexical_scope->wires[name] = cur;
} else {
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
@ -1867,9 +1849,7 @@ svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names)
; cur != names->end()
; cur ++ ) {
perm_string txt = *cur;
pform_name_t tmp;
tmp.push_back(name_component_t(txt));
PWire*pp = new PWire(tmp,
PWire*pp = new PWire(txt,
NetNet::IMPLICIT,
NetNet::PINPUT,
IVL_VT_LOGIC);

22
pform.h
View File

@ -95,7 +95,7 @@ struct parmvalue_t {
struct str_pair_t { PGate::strength_t str0, str1; };
struct net_decl_assign_t {
char*name;
perm_string name;
PExpr*expr;
struct net_decl_assign_t*next;
};
@ -138,19 +138,19 @@ extern void pform_module_set_ports(svector<Module::port_t*>*);
port_definition_list. In this case, we have everything needed to
define the port, all in one place. */
extern void pform_module_define_port(const struct vlltype&li,
const char*name,
perm_string name,
NetNet::PortType,
NetNet::Type type,
bool signed_flag,
svector<PExpr*>*range,
svector<named_pexpr_t*>*attr);
extern Module::port_t* pform_module_port_reference(char*name,
extern Module::port_t* pform_module_port_reference(perm_string name,
const char*file,
unsigned lineno);
extern void pform_endmodule(const char*);
extern void pform_make_udp(perm_string name, list<string>*parms,
extern void pform_make_udp(perm_string name, list<perm_string>*parms,
svector<PWire*>*decl, list<string>*table,
Statement*init,
const char*file, unsigned lineno);
@ -167,9 +167,12 @@ extern void pform_make_udp(perm_string name,
* name string onto the scope hierarchy. The pop pulls it off and
* deletes it. Thus, the string pushed must be allocated.
*/
extern void pform_push_scope(char*name);
extern void pform_pop_scope();
extern PTask*pform_push_task_scope(char*name);
extern PFunction*pform_push_function_scope(char*name);
extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
extern verinum* pform_verinum_with_size(verinum*s, verinum*val,
const char*file, unsigned loneno);
@ -198,7 +201,7 @@ extern void pform_endgenerate();
* The makewire functions announce to the pform code new wires. These
* go into a module that is currently opened.
*/
extern void pform_makewire(const struct vlltype&li, const char*name,
extern void pform_makewire(const struct vlltype&li, perm_string name,
NetNet::Type type,
NetNet::PortType pt,
ivl_variable_type_t,
@ -226,7 +229,7 @@ extern void pform_makewire(const struct vlltype&li,
ivl_variable_type_t);
extern void pform_make_reginit(const struct vlltype&li,
const char*name, PExpr*expr);
perm_string name, PExpr*expr);
/* Look up the names of the wires, and set the port type,
i.e. input, output or inout. If the wire does not exist, create
@ -239,17 +242,14 @@ extern void pform_set_port_type(const struct vlltype&li,
extern void pform_set_port_type(perm_string nm, NetNet::PortType pt,
const char*file, unsigned lineno);
extern void pform_set_net_range(const char* name);
extern void pform_set_net_range(list<perm_string>*names,
svector<PExpr*>*,
bool signed_flag,
ivl_variable_type_t,
PWSRType rt = SR_NET);
extern void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r);
extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r);
extern void pform_set_reg_integer(list<perm_string>*names);
extern void pform_set_reg_time(list<perm_string>*names);
extern void pform_set_task(perm_string name, PTask*);
extern void pform_set_function(perm_string name, PFunction*);
/* pform_set_attrib and pform_set_type_attrib exist to support the
$attribute syntax, which can only set string values to

View File

@ -296,7 +296,7 @@ void PWire::dump(ostream&out, unsigned ind) const
}
}
out << " " << hname_;
out << " " << name_;
// If the wire has indices, dump them.
if (lidx_ || ridx_) {
@ -504,10 +504,13 @@ void PAssignNB::dump(ostream&out, unsigned ind) const
void PBlock::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "begin";
if (name_ != 0)
out << " : " << name_;
if (pscope_name() != 0)
out << " : " << pscope_name();
out << endl;
if (pscope_name() != 0)
dump_wires_(out, ind+2);
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {
if (list_[idx])
list_[idx]->dump(out, ind+2);
@ -697,15 +700,17 @@ void PFunction::dump(ostream&out, unsigned ind) const
out << "] ";
}
out << name_ << ";" << endl;
out << pscope_name() << ";" << endl;
if (ports_)
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
out << setw(ind) << "";
out << "input ";
out << (*ports_)[idx]->path() << ";" << endl;
out << (*ports_)[idx]->basename() << ";" << endl;
}
dump_wires_(out, ind);
if (statement_)
statement_->dump(out, ind);
else
@ -743,9 +748,11 @@ void PTask::dump(ostream&out, unsigned ind) const
assert(0);
break;
}
out << (*ports_)[idx]->path() << ";" << endl;
out << (*ports_)[idx]->basename() << ";" << endl;
}
dump_wires_(out, ind);
if (statement_)
statement_->dump(out, ind);
else
@ -870,7 +877,7 @@ void PGenerate::dump(ostream&out, unsigned indent) const
out << endl;
for (map<pform_name_t,PWire*>::const_iterator idx = wires.begin()
for (map<perm_string,PWire*>::const_iterator idx = wires.begin()
; idx != wires.end() ; idx++) {
(*idx).second->dump(out, indent+2);
@ -894,6 +901,16 @@ void PGenerate::dump(ostream&out, unsigned indent) const
out << setw(indent) << "" << "endgenerate" << endl;
}
void PScope::dump_wires_(ostream&out, unsigned indent) const
{
// Iterate through and display all the wires.
for (map<perm_string,PWire*>::const_iterator wire = wires.begin()
; wire != wires.end() ; wire ++ ) {
(*wire).second->dump(out, indent);
}
}
void Module::dump(ostream&out) const
{
if (attributes.begin() != attributes.end()) {
@ -911,7 +928,7 @@ void Module::dump(ostream&out) const
out << " *) ";
}
out << "module " << name_ << ";" << endl;
out << "module " << mod_name() << ";" << endl;
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
port_t*cur = ports[idx];
@ -995,12 +1012,7 @@ void Module::dump(ostream&out) const
}
// Iterate through and display all the wires.
for (map<pform_name_t,PWire*>::const_iterator wire = wires_.begin()
; wire != wires_.end()
; wire ++ ) {
(*wire).second->dump(out);
}
dump_wires_(out, 4);
// Dump the task definitions.
typedef map<perm_string,PTask*>::const_iterator task_iter_t;