Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Stephen Williams 2012-04-26 09:03:20 -07:00
commit f926cbcc59
132 changed files with 7382 additions and 4405 deletions

View File

@ -107,12 +107,13 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
load_module.o netlist.o netmisc.o net_analog.o net_assign.o net_design.o \
netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_types.o \
pform_disciplines.o pform_dump.o pform_pclass.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 PDelays.o PEvent.o PExpr.o PGate.o \
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \
Statement.o AStatement.o $M $(FF) $(TT)
@ -150,8 +151,8 @@ endif
clean:
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
rm -f *.o parse.cc parse.h lexor.cc
rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps parse.output
rm -f syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp
rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps
rm -f parse.output syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp
rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc
rm -rf dep
rm -f version.exe
@ -244,15 +245,17 @@ lexor.o: lexor.cc parse.h
parse.o: parse.cc
parse.cc parse.h: $(srcdir)/parse.y
$(YACC) --verbose -t -p VL -d -o parse.cc $(srcdir)/parse.y
mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h
# Build this in two steps to avoid parallel build issues (see pr3462585)
parse.cc: $(srcdir)/parse.y
$(YACC) --verbose -t -p VL -d -o $@ $<
parse.h: parse.cc
mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@
syn-rules.cc: $(srcdir)/syn-rules.y
$(YACC) --verbose -p syn_ -o syn-rules.cc $(srcdir)/syn-rules.y
$(YACC) --verbose -t -p syn_ -o $@ $<
lexor.cc: $(srcdir)/lexor.lex
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
$(LEX) -s -t $< > $@
lexor_keyword.o: lexor_keyword.cc parse.h

View File

@ -28,7 +28,7 @@ list<Module::named_expr_t> Module::user_defparms;
/* n is a permallocated string. */
Module::Module(perm_string n)
: PScope(n)
: PScopeExtra(n)
{
library_flag = false;
is_cell = false;

View File

@ -49,7 +49,7 @@ class NetScope;
* therefore the handle for grasping the described circuit.
*/
class Module : public PScope, public LineInfo {
class Module : public PScopeExtra, public LineInfo {
/* The module ports are in general a vector of port_t
objects. Each port has a name and an ordered list of
@ -112,10 +112,6 @@ class Module : public PScope, public LineInfo {
bool time_from_timescale;
bool timescale_warn_done;
/* Task definitions within this module */
map<perm_string,PTask*> tasks;
map<perm_string,PFunction*> funcs;
/* The module has a list of generate schemes that appear in
the module definition. These are used at elaboration time. */
list<PGenerate*> generate_schemes;

30
PClass.cc Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2012 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 "PClass.h"
PClass::PClass(perm_string name, LexicalScope*parent)
: PScopeExtra(name, parent)
{
}
PClass::~PClass()
{
}

40
PClass.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef __PClass_H
#define __PClass_H
/*
* Copyright (c) 2012 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"
# include "LineInfo.h"
# include "StringHeap.h"
/*
* SystemVerilog supports class declarations with their own lexical
* scope, etc. The parser arranges for these to be created and
* collected.
*/
class PClass : public PScopeExtra, public LineInfo {
public:
explicit PClass (perm_string name, LexicalScope*parent);
~PClass();
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams <steve@icarus.com>
* Copyright (c) 1998-2012 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
@ -346,7 +346,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
PWire*net = new PWire(name, type, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
net->set_file(get_file());
net->set_lineno(get_lineno());
net->set_range(0, 0, SR_NET, true);
net->set_range_scalar(SR_NET);
scope->wires[name] = net;
if (warn_implicit) {
cerr << get_fileline() << ": warning: implicit "

27
PExpr.h
View File

@ -343,18 +343,33 @@ class PEIdent : public PExpr {
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
// Evaluate the prefix indices. All but the final index in a
// chain of indices must be a single value and must evaluate
// to constants at compile time. For example:
// [x] - OK
// [1][2][x] - OK
// [1][x:y] - OK
// [2:0][x] - BAD
// [y][x] - BAD
// Leave the last index for special handling.
bool calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
std::list<long>&prefix_indices) const;
private:
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
index_component_t::ctype_t) const;
bool elaborate_lval_net_packed_member_(Design*, NetScope*,
NetAssign_*,
const perm_string&) const;
private:
NetExpr*elaborate_expr_param_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb,
unsigned expr_wid,
@ -362,21 +377,21 @@ class PEIdent : public PExpr {
NetExpr*elaborate_expr_param_part_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb,
unsigned expr_wid) const;
NetExpr*elaborate_expr_param_idx_up_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb,
bool need_const) const;
NetExpr*elaborate_expr_param_idx_do_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb,
bool need_const) const;
@ -494,6 +509,10 @@ class PEUnary : public PExpr {
unsigned flags) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const;
public:
inline char get_op() const { return op_; }
inline PExpr*get_expr() const { return expr_; }
private:
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;

View File

@ -41,3 +41,18 @@ PWire* LexicalScope::wires_find(perm_string name)
else
return (*cur).second;
}
PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent)
: PScope(n, parent)
{
}
PScopeExtra::PScopeExtra(perm_string n)
: PScope(n)
{
}
PScopeExtra::~PScopeExtra()
{
}

View File

@ -27,8 +27,10 @@
class PEvent;
class PExpr;
class PFunction;
class AProcess;
class PProcess;
class PTask;
class PWire;
class Design;
@ -83,6 +85,9 @@ class LexicalScope {
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
// Defined types in the scope.
map<perm_string,data_type_t*>typedefs;
// Named events in the scope.
map<perm_string,PEvent*>events;
@ -105,6 +110,8 @@ class LexicalScope {
LexicalScope* parent_scope() const { return parent_; }
protected:
void dump_typedefs_(ostream&out, unsigned indent) const;
void dump_parameters_(ostream&out, unsigned indent) const;
void dump_localparams_(ostream&out, unsigned indent) const;
@ -145,4 +152,21 @@ class PScope : public LexicalScope {
perm_string name_;
};
/*
* Some scopes can carry definitions. These include Modules and PClass
* scopes. These derive from PScopeExtra so that they hold the maps of
* extra definitions.
*/
class PScopeExtra : public PScope {
public:
PScopeExtra(perm_string, LexicalScope*parent);
PScopeExtra(perm_string);
~PScopeExtra();
/* Task definitions within this module */
map<perm_string,PTask*> tasks;
map<perm_string,PFunction*> funcs;
};
#endif

View File

@ -1,7 +1,7 @@
#ifndef __PTask_H
#define __PTask_H
/*
* Copyright (c) 1999-2008,2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008,2010,2012 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
@ -41,12 +41,14 @@ enum PTaskFuncEnum {
PTF_REALTIME,
PTF_TIME,
PTF_ATOM2,
PTF_ATOM2_S
PTF_ATOM2_S,
PTF_STRING,
PTF_VOID
};
struct PTaskFuncArg {
PTaskFuncEnum type;
vector<PExpr*>*range;
std::list<pform_range_t>*range;
};
/*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -28,9 +28,9 @@ PWire::PWire(perm_string n,
ivl_variable_type_t 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), is_scalar_(false),
error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), discipline_(0)
port_set_(false), net_set_(false), is_scalar_(false),
error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0),
discipline_(0)
{
if (t == NetNet::INTEGER) {
type_ = NetNet::REG;
@ -148,8 +148,9 @@ bool PWire::get_scalar() const
return is_scalar_;
}
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
void PWire::set_range_scalar(PWSRType type)
{
is_scalar_ = true;
switch (type) {
case SR_PORT:
if (port_set_) {
@ -157,10 +158,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
} else {
port_msb_ = m;
port_lsb_ = l;
port_set_ = true;
is_scalar_ = is_scalar;
}
return;
@ -170,10 +168,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {
net_msb_ = m;
net_lsb_ = l;
net_set_ = true;
is_scalar_ = is_scalar;
}
return;
@ -190,13 +185,58 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
error_cnt_ += 1;
}
} else {
port_msb_ = m;
port_lsb_ = l;
port_set_ = true;
net_msb_ = m;
net_lsb_ = l;
net_set_ = true;
is_scalar_ = is_scalar;
}
return;
}
}
void PWire::set_range(const list<pform_range_t>&rlist, PWSRType type)
{
switch (type) {
case SR_PORT:
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
} else {
port_ = rlist;
port_set_ = true;
is_scalar_ = false;
}
return;
case SR_NET:
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {
net_ = rlist;
net_set_ = true;
is_scalar_ = false;
}
return;
case SR_BOTH:
if (port_set_ || net_set_) {
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
}
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
}
} else {
port_ = rlist;
port_set_ = true;
net_ = rlist;
net_set_ = true;
is_scalar_ = false;
}
return;
}
@ -217,9 +257,17 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
void PWire::set_enumeration(enum_type_t*enum_type)
{
assert(enum_type_ == 0);
assert(struct_type_ == 0);
enum_type_ = enum_type;
}
void PWire::set_struct_type(struct_type_t*type)
{
assert(enum_type_ == 0);
assert(struct_type_ == 0);
struct_type_ = type;
}
void PWire::set_discipline(ivl_discipline_t d)
{
assert(discipline_ == 0);

21
PWire.h
View File

@ -1,7 +1,7 @@
#ifndef __PWire_H
#define __PWire_H
/*
* Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2009,2012 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
@ -21,8 +21,8 @@
# include "netlist.h"
# include "LineInfo.h"
# include <list>
# include <map>
# include "svector.h"
# include "StringHeap.h"
#ifdef HAVE_IOSFWD
@ -75,11 +75,13 @@ class PWire : public LineInfo {
bool set_data_type(ivl_variable_type_t dt);
ivl_variable_type_t get_data_type() const;
void set_range(PExpr*msb, PExpr*lsb, PWSRType type, bool is_scalar);
void set_range_scalar(PWSRType type);
void set_range(const std::list<pform_range_t>&ranges, PWSRType type);
void set_memory_idx(PExpr*ldx, PExpr*rdx);
void set_enumeration(enum_type_t*enum_type);
void set_struct_type(struct_type_t*type);
void set_discipline(ivl_discipline_t);
ivl_discipline_t get_discipline(void) const;
@ -100,12 +102,14 @@ class PWire : public LineInfo {
bool isint_; // original type of integer
// These members hold expressions for the bit width of the
// wire. If they do not exist, the wire is 1 bit wide.
PExpr*port_msb_;
PExpr*port_lsb_;
// wire. If they do not exist, the wire is 1 bit wide. If they
// do exist, they represent the packed dimensions of the
// bit. The first item in the list is the first range, and so
// on. For example "reg [3:0][7:0] ..." will contains the
// range_t object for [3:0] first and [7:0] last.
std::list<pform_range_t>port_;
bool port_set_;
PExpr*net_msb_;
PExpr*net_lsb_;
std::list<pform_range_t>net_;
bool net_set_;
bool is_scalar_;
unsigned error_cnt_;
@ -116,6 +120,7 @@ class PWire : public LineInfo {
PExpr*ridx_;
enum_type_t*enum_type_;
struct_type_t*struct_type_;
ivl_discipline_t discipline_;

View File

@ -276,9 +276,8 @@ PForever::~PForever()
}
PForStatement::PForStatement(PExpr*n1, PExpr*e1, PExpr*cond,
PExpr*n2, PExpr*e2, Statement*st)
: name1_(n1), expr1_(e1), cond_(cond), name2_(n2), expr2_(e2),
statement_(st)
Statement*step, Statement*st)
: name1_(n1), expr1_(e1), cond_(cond), step_(step), statement_(st)
{
}

View File

@ -196,18 +196,6 @@ class PCallTask : public Statement {
const pform_name_t& path() const;
unsigned nparms() const { return parms_.size(); }
PExpr*&parm(unsigned idx)
{ assert(idx < parms_.size());
return parms_[idx];
}
PExpr* parm(unsigned idx) const
{ assert(idx < parms_.size());
return parms_[idx];
}
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
@ -403,7 +391,7 @@ class PForStatement : public Statement {
public:
PForStatement(PExpr*n1, PExpr*e1, PExpr*cond,
PExpr*n2, PExpr*e2, Statement*st);
Statement*step, Statement*body);
~PForStatement();
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
@ -417,8 +405,7 @@ class PForStatement : public Statement {
PExpr*cond_;
PExpr* name2_;
PExpr* expr2_;
Statement*step_;
Statement*statement_;
};

View File

@ -47,8 +47,6 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
LDFLAGS = @LDFLAGS@
SHARED = @shared@
O = cadpli.o
all: dep cadpli.vpl $(ALL32)
@ -80,7 +78,7 @@ ifeq (@MINGW32@,yes)
endif
cadpli.vpl: $O ../vvp/libvpi.a ../libveriuser/libveriuser.o
$(CC) @shared@ -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS)
install: all installdirs $(vpidir)/cadpli.vpl

View File

@ -1,3 +1,3 @@
// These are correct and are used to find the base (zero) pin.
thisSubtraction:netlist.h:4168
thisSubtraction:netlist.h:4177
thisSubtraction:netlist.h:4169
thisSubtraction:netlist.h:4178

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -187,6 +187,15 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
dump_node_pins(o, ind+4);
}
ostream&operator<<(ostream&out, const list<NetNet::range_t>&rlist)
{
for (list<NetNet::range_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
out << "[" << cur->msb << ":" << cur->lsb << "]";
}
return out;
}
/* Dump a net. This can be a wire or register. */
void NetNet::dump_net(ostream&o, unsigned ind) const
{
@ -212,11 +221,16 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
case NetNet::PINOUT:
o << " inout";
break;
case NetNet::PREF:
o <<" ref";
break;
}
if (ivl_discipline_t dis = get_discipline())
o << " discipline=" << dis->name();
o << " packed dims: " << packed_dims_;
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
if (scope())
o << " scope=" << scope_path(scope());
@ -1045,8 +1059,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
if (result_sig_) {
o << setw(ind+2) << "" << "Return signal: ";
if (result_sig_->get_signed()) o << "+";
o << result_sig_->name() << "[" << result_sig_->msb() << ":"
<< result_sig_->lsb() << "]" << endl;
o << result_sig_->name() << result_sig_->packed_dims() << endl;
}
o << setw(ind+2) << "" << "Arguments: ";
if (port_count() == 0) o << "<none>";
@ -1068,8 +1081,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
break;
}
if (port(idx)->get_signed()) o << "+";
o << port(idx)->name() << "[" << port(idx)->msb() << ":"
<< port(idx)->lsb() << "]" << endl;
o << port(idx)->name() << port(idx)->packed_dims() << endl;
}
if (statement_)
statement_->dump(o, ind+2);
@ -1509,7 +1521,7 @@ void NetESignal::dump(ostream&o) const
o << "+";
o << name();
if (word_) o << "[word=" << *word_ << "]";
o << "[" << msi()<<":"<<lsi() << "]";
o << sig()->packed_dims();
}
void NetETernary::dump(ostream&o) const

View File

@ -79,11 +79,13 @@ dep:
iverilog@EXEEXT@: $O
$(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@ @EXTRALIBS@
cflexor.c: cflexor.lex
$(LEX) -s -ocflexor.c $(srcdir)/cflexor.lex
cflexor.c: $(srcdir)/cflexor.lex
$(LEX) -s -t $< > $@
cfparse.h cfparse.c: cfparse.y
$(YACC) --verbose -t -d -o cfparse.c --name-prefix=cf $(srcdir)/cfparse.y
# Build this in two steps to avoid parallel build issues (see pr3462585)
cfparse.c: $(srcdir)/cfparse.y
$(YACC) --verbose -t -p cf -d -o $@ $<
cfparse.h: cfparse.c
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -29,6 +29,7 @@
# include "netenum.h"
# include "discipline.h"
# include "netmisc.h"
# include "netstruct.h"
# include "util.h"
# include "ivl_assert.h"
@ -1418,6 +1419,50 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
return sys_expr;
}
/*
* If the method matches a structure member then return the member otherwise
* return 0. Also return the offset of the member.
*/
static const netstruct_t::member_t*get_struct_member(const LineInfo*li,
Design*des, NetScope*,
NetNet*net,
perm_string method_name,
unsigned long&off)
{
netstruct_t*type = net->struct_type();
ivl_assert(*li, type);
if (! type->packed()) {
cerr << li->get_fileline()
<< ": sorry: unpacked structures not supported here. "
<< "Method=" << method_name << endl;
des->errors += 1;
return 0;
}
return type->packed_member(method_name, off);
}
static NetExpr* check_for_struct_members(const LineInfo*li,
Design*des, NetScope*,
NetNet*net, perm_string method_name)
{
unsigned long off;
const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net,
method_name, off);
if (mem == 0) return 0;
if (debug_elaborate) {
cerr << li->get_fileline() << ": debug: Found struct member " <<mem->name
<< " At offset " << off << endl;
}
NetESignal*sig = new NetESignal(net);
NetEConst*base = make_const_val(off);
NetESelect*sel = new NetESelect(sig, base, mem->width());
return sel;
}
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned flags) const
{
@ -1456,8 +1501,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
// enumeration? If so then check to see if this is an
// enumeration method call.
if (net != 0) {
netenum_t*netenum = net->enumeration();
if (netenum) {
if (netenum_t*netenum = net->enumeration()) {
// We may need the net expression for the
// enumeration variable so get it.
NetESignal*expr = new NetESignal(net);
@ -1472,6 +1516,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
expr_wid, tmp,
parms_.size());
}
}
}
@ -1823,6 +1868,17 @@ NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
return tmp;
}
bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
list<long>&prefix_indices) const
{
list<index_component_t> index;
index = path_.back().index;
for (size_t idx = 0 ; idx < net->array_dimensions() ; idx += 1)
index.pop_front();
return evaluate_index_prefix(des, scope, prefix_indices, index);
}
/*
* Given that the msb_ and lsb_ are part select expressions, this
* function calculates their values. Note that this method does *not*
@ -1968,7 +2024,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
const NetExpr*ex1, *ex2;
symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2);
NetScope*found_in = symbol_search(0, des, scope, path_, net, par, eve,
ex1, ex2);
// If there is a part/bit select expression, then process it
// here. This constrains the results no matter what kind the
@ -2104,6 +2161,37 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
return expr_width_;
}
// If this is SystemVerilog then maybe this is a structure element.
if (gn_system_verilog() && found_in==0 && path_.size() >= 2) {
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
found_in = symbol_search(this, des, scope, use_path,
net, par, eve, ex1, ex2);
// Check to see if we have a net and if so is it a structure?
if (net != 0) {
// If this net is a struct, the method name may be
// a struct member.
if (net->struct_type() != 0) {
ivl_assert(*this, use_path.back().index.empty());
const netstruct_t::member_t*mem;
unsigned long unused;
mem = get_struct_member(this, des, scope, net,
method_name, unused);
if (mem) {
expr_type_ = mem->data_type();
expr_width_ = mem->width();
min_width_ = expr_width_;
signed_flag_ = mem->get_signed();
return expr_width_;
}
}
}
}
// Not a net, and not a parameter? Give up on the type, but
// set the width to 0.
expr_type_ = IVL_VT_NO_TYPE;
@ -2289,8 +2377,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
// enumeration? If so then check to see if this is an
// enumeration method call.
if (net != 0) {
netenum_t*netenum = net->enumeration();
if (netenum) {
// If this net is actually an enum, the method may
// be an enumeration method.
if (netenum_t*netenum = net->enumeration()) {
// We may need the net expression for the
// enumeration variable so get it.
NetESignal*expr = new NetESignal(net);
@ -2303,6 +2392,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
use_path, method_name,
expr, expr_wid, NULL, 0);
}
// If this net is a struct, the method name may be
// a struct member.
if (net->struct_type() != 0) {
ivl_assert(*this, use_path.back().index.empty());
return check_for_struct_members(this, des, scope,
net, method_name);
}
}
}
@ -2540,7 +2639,7 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined,
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb,
bool need_const) const
@ -2613,6 +2712,12 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
base = normalize_variable_base(base, par_msv, par_lsv, wid, true);
NetExpr*tmp = par->dup_expr();
if (!tmp) return 0;
/* The numeric parameter value needs to have the file and line
* information for the actual parameter not the expression. */
NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_));
tmp->set_line((*pref).second);
tmp = new NetESelect(tmp, base, wid, IVL_SEL_IDX_UP);
tmp->set_line(*this);
return tmp;
@ -2620,7 +2725,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb,
bool need_const) const
@ -2694,6 +2799,12 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
base = normalize_variable_base(base, par_msv, par_lsv, wid, false);
NetExpr*tmp = par->dup_expr();
if (!tmp) return 0;
/* The numeric parameter value needs to have the file and line
* information for the actual parameter not the expression. */
NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_));
tmp->set_line((*pref).second);
tmp = new NetESelect(tmp, base, wid, IVL_SEL_IDX_DOWN);
tmp->set_line(*this);
return tmp;
@ -2748,8 +2859,14 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
// rewritten in the above format, as I get to it.
NetExpr*tmp = par->dup_expr();
if (!tmp)
return 0;
if (!tmp) return 0;
/* The numeric parameter value needs to have the file and line
* information for the actual parameter not the expression. */
if (! dynamic_cast<NetEConstEnum*>(tmp)) {
NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_));
tmp->set_line((*pref).second);
}
if (use_sel == index_component_t::SEL_BIT) {
ivl_assert(*this, !name_tail.index.empty());
@ -2846,6 +2963,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
NetEConst*re2 = new NetEConst(verinum(rb, 1));
re2->set_line(*this);
delete tmp;
delete mtmp;
tmp = re2;
@ -2911,7 +3029,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
}
}
tmp->set_line(*this);
return tmp;
}
@ -3041,6 +3158,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
unsigned expr_wid) const
{
list<long> prefix_indices;
bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
ivl_assert(*this, rc);
long msv, lsv;
bool parts_defined_flag;
bool flag = calculate_parts_(des, scope, msv, lsv, parts_defined_flag);
@ -3073,9 +3194,8 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
tmp->set_line(*this);
return tmp;
}
long sb_lsb = net->sig()->sb_to_idx(lsv);
long sb_msb = net->sig()->sb_to_idx(msv);
long sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv);
long sb_msb = net->sig()->sb_to_idx(prefix_indices, msv);
if (sb_msb < sb_lsb) {
cerr << get_fileline() << ": error: part select " << net->name();
@ -3147,6 +3267,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
ivl_assert(*this, rc);
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
unsigned long wid = 0;
@ -3160,27 +3284,32 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetExpr*ex;
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long offset = 0;
// Get the signal range.
const list<NetNet::range_t>&packed = net->sig()->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
// We want the last range, which is where we work.
const NetNet::range_t&rng = packed.back();
if (rng.msb < rng.lsb) {
offset = -wid + 1;
}
long rel_base = net->sig()->sb_to_idx(prefix_indices, lsv);
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sig()->sb_to_idx(lsv) == 0 &&
wid == net->vector_width()) {
if (rel_base == 0 && wid == net->vector_width()) {
delete base;
net->cast_signed(false);
return net;
}
long offset = 0;
if (net->msi() < net->lsi()) {
offset = -wid + 1;
}
// Otherwise, make a part select that covers the right
// range.
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
offset));
ex = new NetEConst(verinum(rel_base + offset));
if (warn_ob_select) {
long rel_base = net->sig()->sb_to_idx(lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
@ -3216,7 +3345,12 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
return ss;
}
base = normalize_variable_base(base, net->msi(), net->lsi(), wid, true);
ivl_assert(*this, prefix_indices.size()+1 == net->sig()->packed_dims().size());
// Convert the non-constant part select index expression into
// an expression that returns a canonical base.
base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, true);
NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP);
ss->set_line(*this);
@ -3236,6 +3370,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
ivl_assert(*this, rc);
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
unsigned long wid = 0;
@ -3252,7 +3390,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
if (net->sig()->sb_to_idx(prefix_indices,lsv) == (signed) (wid-1) &&
wid == net->vector_width()) {
delete base;
net->cast_signed(false);
@ -3265,10 +3403,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
}
// Otherwise, make a part select that covers the right
// range.
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
offset));
ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset));
if (warn_ob_select) {
long rel_base = net->sig()->sb_to_idx(lsv) + offset;
long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
@ -3321,6 +3458,10 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
ivl_assert(*this, rc);
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
@ -3328,12 +3469,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
NetExpr*ex = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
if (NetEConst*msc = dynamic_cast<NetEConst*> (ex)) {
if (NetEConst*msc = dynamic_cast<NetEConst*> (mux)) {
// Special case: The bit select expression is constant
// x/z. The result of the expression is 1'bx.
@ -3354,12 +3495,35 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
delete ex;
delete mux;
return tmp;
}
long msv = msc->value().as_long();
long idx = net->sig()->sb_to_idx(msv);
const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
if (prefix_indices.size()+2 <= sig_packed.size()) {
// Special case: this is a slice of a multi-dimensional
// packed array. For example:
// reg [3:0][7:0] x;
// ... x[2] ...
// This shows up as the prefix_indices being too short
// for the packed dimensions of the vector. What we do
// here is convert to a "slice" of the vector.
unsigned long lwid;
long idx;
rc = net->sig()->sb_to_slice(prefix_indices, msv, idx, lwid);
// Make an expression out of the index
NetEConst*idx_c = new NetEConst(verinum(idx));
idx_c->set_line(*net);
NetESelect*res = new NetESelect(net, idx_c, lwid);
res->set_line(*net);
return res;
}
long idx = net->sig()->sb_to_idx(prefix_indices,msv);
if (idx >= (long)net->vector_width() || idx < 0) {
/* The bit select is out of range of the
@ -3375,8 +3539,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
else cerr << "vector ";
cerr << net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << net->sig()->msb() << ":"
<< net->sig()->lsb() << "]." << endl;
cerr << net->sig()->packed_dims() << "." << endl;
cerr << get_fileline() << ": : "
<< "Replacing select with a constant 1'bx."
<< endl;
@ -3385,7 +3548,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
delete ex;
delete mux;
return tmp;
}
@ -3405,15 +3568,35 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
return res;
}
const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
if (prefix_indices.size()+2 <= sig_packed.size()) {
// Special case: this is a slice of a multi-dimensional
// packed array. For example:
// reg [3:0][7:0] x;
// x[2] = ...
// This shows up as the prefix_indices being too short
// for the packed dimensions of the vector. What we do
// here is convert to a "slice" of the vector.
unsigned long lwid;
mux = normalize_variable_slice_base(prefix_indices, mux,
net->sig(), lwid);
mux->set_line(*net);
// Make a PART select with the canonical index
NetESelect*res = new NetESelect(net, mux, lwid);
res->set_line(*net);
return res;
}
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net. This is a fairly
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(),
1, true);
mux = normalize_variable_bit_base(prefix_indices, mux, net->sig());
NetESelect*ss = new NetESelect(net, ex, 1);
NetESelect*ss = new NetESelect(net, mux, 1);
ss->set_line(*this);
return ss;
}
@ -3446,6 +3629,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
return 0;
}
list<long> prefix_indices;
bool rc = evaluate_index_prefix(des, scope, prefix_indices, path_.back().index);
if (!rc) return 0;
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits. The lsb_ and msb_ expressions are from

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2012 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
@ -22,6 +22,7 @@
# include "PExpr.h"
# include "netlist.h"
# include "netmisc.h"
# include "netstruct.h"
# include "compiler.h"
# include <cstdlib>
# include <iostream>
@ -152,8 +153,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
NetNet* reg = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
perm_string method_name;
symbol_search(this, des, scope, path_, reg, par, eve);
/* If the signal is not found, check to see if this is a
member of a struct. Take the name of the form "a.b.member",
remove the member and store it into method_name, and retry
the search with "a.b". */
if (reg == 0 && path_.size() >= 2) {
pform_name_t use_path = path_;
method_name = peek_tail_name(use_path);
use_path.pop_back();
symbol_search(this, des, scope, use_path, reg, par, eve);
if (reg && reg->struct_type() == 0) {
method_name = perm_string();
reg = 0;
}
}
if (reg == 0) {
cerr << get_fileline() << ": error: Could not find variable ``"
<< path_ << "'' in ``" << scope_path(scope) <<
@ -164,16 +183,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
ivl_assert(*this, reg);
// We are processing the tail of a string of names. For
// example, the verilog may be "a.b.c", so we are processing
// "c" at this point.
const name_component_t&name_tail = path_.back();
// Use the last index to determine what kind of select
// (bit/part/etc) we are processing. For example, the verilog
// may be "a.b.c[1][2][<index>]". All but the last index must
// be simple expressions, only the <index> may be a part
// select etc., so look at it to determine how we will be
// proceeding.
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
// This is the special case that the l-value is an entire
// memory. This is, in fact, an error.
if (reg->array_dimensions() > 0 && name_tail.index.empty()) {
// Special case: The l-value is an entire memory, or array
// slice. This is, in fact, an error in l-values. Detect the
// situation by noting if the index count is less than the
// array dimensions (unpacked).
if (reg->array_dimensions() > name_tail.index.size()) {
cerr << get_fileline() << ": error: Cannot assign to array "
<< path_ << ". Did you forget a word index?" << endl;
des->errors += 1;
@ -181,7 +210,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
/* Get the signal referenced by the identifier, and make sure
it is a register. Wires are not allows in this context,
it is a register. Wires are not allowed in this context,
unless this is the l-value of a force. */
if ((reg->type() != NetNet::REG) && !is_force) {
cerr << get_fileline() << ": error: " << path_ <<
@ -193,6 +222,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return 0;
}
if (reg->struct_type() && !method_name.nil()) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_packed_member_(des, scope, lv, method_name);
return lv;
}
if (reg->array_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg);
@ -322,7 +357,13 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
if (!rc) return false;
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
@ -340,20 +381,43 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
mux = 0;
}
if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select expression.
mux = normalize_variable_base(mux, reg->msb(), reg->lsb(), 1, true);
if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
// Special case: this is a slice of a multi-dimensional
// packed array. For example:
// reg [3:0][7:0] x;
// x[2] = ...
// This shows up as the prefix_indices being too short
// for the packed dimensions of the vector. What we do
// here is convert to a "slice" of the vector.
if (mux == 0) {
long loff;
unsigned long lwid;
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
ivl_assert(*this, rcl);
lv->set_part(new NetEConst(verinum(loff)), lwid);
} else {
unsigned long lwid;
mux = normalize_variable_slice_base(prefix_indices, mux,
reg, lwid);
lv->set_part(mux, lwid);
}
} else if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select
// expression.
mux = normalize_variable_bit_base(prefix_indices, mux, reg);
lv->set_part(mux, 1);
} else if (lsb == reg->msb() && lsb == reg->lsb()) {
} else if (reg->vector_width() == 1 && reg->sb_is_valid(prefix_indices,lsb)) {
// Constant bit mux that happens to select the only bit
// of the l-value. Don't bother with any select at all.
} else {
// Constant bit select that does something useful.
long loff = reg->sb_to_idx(lsb);
long loff = reg->sb_to_idx(prefix_indices,lsb);
if (loff < 0 || loff >= (long)reg->vector_width()) {
cerr << get_fileline() << ": error: bit select "
@ -373,6 +437,10 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
list<long> prefix_indices;
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
ivl_assert(*this, rc);
// The range expressions of a part select must be
// constant. The calculate_parts_ function calculates the
// values into msb and lsb.
@ -385,41 +453,50 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
ivl_assert(*this, parts_defined_flag);
NetNet*reg = lv->sig();
assert(reg);
ivl_assert(*this, reg);
if (msb == reg->msb() && lsb == reg->lsb()) {
const list<NetNet::range_t>&packed = reg->packed_dims();
/* Part select covers the entire vector. Simplest case. */
} else {
/* Get the canonical offsets into the vector. */
long loff = reg->sb_to_idx(lsb);
long moff = reg->sb_to_idx(msb);
long wid = moff - loff + 1;
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return false;
}
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if (loff < 0 || moff >= (signed)reg->vector_width()) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
}
lv->set_part(new NetEConst(verinum(loff)), wid);
// Part selects cannot select slices. So there must be enough
// prefix_indices to get all the way to the final dimension.
if (prefix_indices.size()+1 < packed.size()) {
cerr << get_fileline() << ": error: Cannot select a range "
<< "of slices from a packed array." << endl;
des->errors += 1;
return false;
}
long loff = reg->sb_to_idx(prefix_indices,lsb);
long moff = reg->sb_to_idx(prefix_indices,msb);
long wid = moff - loff + 1;
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return false;
}
// Special case: The range winds up selecting the entire
// vector. Treat this as no part select at all.
if (loff == 0 && moff == (long)(reg->vector_width()-1)) {
return true;
}
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if (loff < 0 || moff >= (long)reg->vector_width()) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
}
lv->set_part(new NetEConst(verinum(loff)), wid);
return true;
}
@ -428,6 +505,10 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
NetAssign_*lv,
index_component_t::ctype_t use_sel) const
{
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
ivl_assert(*this, rc);
const name_component_t&name_tail = path_.back();;
ivl_assert(*this, !name_tail.index.empty());
@ -462,14 +543,20 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long offset = 0;
if (((reg->msb() < reg->lsb()) &&
// Get the signal range.
const list<NetNet::range_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
// We want the last range, which is where we work.
const NetNet::range_t&rng = packed.back();
if (((rng.msb < rng.lsb) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((reg->msb() > reg->lsb()) &&
((rng.msb > rng.lsb) &&
use_sel == index_component_t::SEL_IDX_DO)) {
offset = -wid + 1;
}
delete base;
long rel_base = reg->sb_to_idx(lsv) + offset;
long rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset;
/* If we cover the entire lvalue just skip the select. */
if (rel_base == 0 && wid == reg->vector_width()) return true;
base = new NetEConst(verinum(rel_base));
@ -511,15 +598,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
}
}
} else {
ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size());
/* Correct the mux for the range of the vector. */
if (use_sel == index_component_t::SEL_IDX_UP) {
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
wid, true);
base = normalize_variable_part_base(prefix_indices, base,
reg, wid, true);
sel_type = IVL_SEL_IDX_UP;
} else {
// This is assumed to be a SEL_IDX_DO.
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
wid, false);
base = normalize_variable_part_base(prefix_indices, base,
reg, wid, false);
sel_type = IVL_SEL_IDX_DOWN;
}
}
@ -533,6 +621,38 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true;
}
bool PEIdent::elaborate_lval_net_packed_member_(Design*des,
NetScope*,
NetAssign_*lv,
const perm_string&member_name) const
{
NetNet*reg = lv->sig();
ivl_assert(*this, reg);
netstruct_t*struct_type = reg->struct_type();
ivl_assert(*this, struct_type);
if (! struct_type->packed()) {
cerr << get_fileline() << ": sorry: Only packed structures "
<< "are supported in l-value." << endl;
des->errors += 1;
return false;
}
unsigned long off;
const netstruct_t::member_t* member = struct_type->packed_member(member_name, off);
if (member == 0) {
cerr << get_fileline() << ": error: Member " << member_name
<< " is not a member of variable " << reg->name() << endl;
des->errors += 1;
return false;
}
lv->set_part(new NetEConst(verinum(off)), member->width());
return true;
}
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
{
cerr << get_fileline() << ": error: Constant values not allowed "

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -22,6 +22,7 @@
# include "PExpr.h"
# include "netlist.h"
# include "netmisc.h"
# include "netstruct.h"
# include "compiler.h"
# include <cstdlib>
@ -199,6 +200,10 @@ bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
long&midx, long&lidx) const
{
list<long> prefix_indices;
bool rc = calculate_packed_indices_(des, scope, sig, prefix_indices);
ivl_assert(*this, rc);
const name_component_t&name_tail = path_.back();
// Only treat as part/bit selects any index that is beyond the
// word selects for an array. This is not an array, then
@ -257,13 +262,13 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
long midx_val = tmp->value().as_long();
midx = sig->sb_to_idx(midx_val);
midx = sig->sb_to_idx(prefix_indices, midx_val);
delete tmp_ex;
if (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(midx_val+wid-1);
lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1);
else
lidx = sig->sb_to_idx(midx_val-wid+1);
lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1);
if (midx < lidx) {
long tmpx = midx;
@ -312,8 +317,8 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
ivl_assert(*this, part_defined_flag);
long lidx_tmp = sig->sb_to_idx(lsb);
long midx_tmp = sig->sb_to_idx(msb);
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
/* Detect reversed indices of a part select. */
if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
@ -369,7 +374,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
assert(mval);
midx = sig->sb_to_idx(mval->as_long());
midx = sig->sb_to_idx(prefix_indices, mval->as_long());
if (midx >= (long)sig->vector_width()) {
cerr << get_fileline() << ": error: Index " << sig->name()
<< "[" << mval->as_long() << "] is out of range."
@ -405,6 +410,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
NetNet* sig = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
perm_string method_name;
symbol_search(this, des, scope, path_, sig, par, eve);
@ -416,6 +422,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
return 0;
}
/* If the signal is not found, check to see if this is a
member of a struct. Take the name of the form "a.b.member",
remove the member and store it into method_name, and retry
the search with "a.b". */
if (sig == 0 && path_.size() >= 2) {
pform_name_t use_path = path_;
method_name = peek_tail_name(use_path);
use_path.pop_back();
symbol_search(this, des, scope, use_path, sig, par, eve);
// Whoops, not a struct signal, so give up on this avenue.
if (sig && sig->struct_type() == 0) {
method_name = perm_string();
sig = 0;
}
}
if (sig == 0) {
cerr << get_fileline() << ": error: Net " << path_
<< " is not defined in this context." << endl;
@ -434,13 +457,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
sig->type(NetNet::UNRESOLVED_WIRE);
}
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked()) {
cerr << get_fileline() << ": error: Unresolved net/uwire "
<< sig->name() << " cannot have multiple drivers." << endl;
des->errors += 1;
return 0;
}
/* Don't allow registers as assign l-values. */
if (sig->type() == NetNet::REG) {
cerr << get_fileline() << ": error: reg " << sig->name()
@ -460,7 +476,26 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
const name_component_t&name_tail = path_.back();
if (sig->array_dimensions() > 0) {
netstruct_t*struct_type = 0;
if ((struct_type = sig->struct_type()) && !method_name.nil()) {
// Detect the variable is a structure and there was a
// method name detected.
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Signal " << sig->name() << " is a structure, "
<< "try to match member " << method_name << endl;
unsigned long member_off = 0;
const struct netstruct_t::member_t*member = struct_type->packed_member(method_name, member_off);
ivl_assert(*this, member);
// Rewrite a member select of a packed structure as a
// part select of the base variable.
lidx = member_off;
midx = lidx + member->width() - 1;
} else if (sig->array_dimensions() > 0) {
if (name_tail.index.empty()) {
cerr << get_fileline() << ": error: array " << sig->name()
@ -553,6 +588,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned subnet_wid = midx-lidx+1;
/* Check if the l-value bits are double-driven. */
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_part_lref(midx,lidx)) {
cerr << get_fileline() << ": error: Unresolved net/uwire "
<< sig->name() << " cannot have multiple drivers." << endl;
des->errors += 1;
return 0;
}
if (sig->pin_count() > 1) {
if (widx < 0 || widx >= (long) sig->pin_count()) {
cerr << get_fileline() << ": warning: ignoring out of "
@ -659,6 +702,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
case NetNet::PINPUT:
case NetNet::POUTPUT:
case NetNet::PINOUT:
case NetNet::PREF:
break;
/* If the name matches, but the signal is not a port,
@ -726,6 +770,9 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
sig = tmp;
break;
case NetNet::PREF:
// For the purposes of module ports, treat ref ports
// just like inout ports.
case NetNet::PINOUT:
ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(),
swid, lidx);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2012 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
@ -133,9 +133,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
enum_type_t*enum_type)
{
bool rc_flag;
assert(enum_type->range->size() == 2);
NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1);
NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1);
assert(enum_type->range->size() == 1);
pform_range_t&range = enum_type->range->front();
NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1);
NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1);
long msb = 0;
rc_flag = eval_as_long(msb, msb_ex);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2012 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
@ -32,6 +32,7 @@
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "netstruct.h"
# include "util.h"
# include "ivl_assert.h"
@ -84,6 +85,14 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
PWire*cur = (*wt).second;
NetNet*sig = cur->elaborate_sig(des, scope);
if (sig && (sig->scope() == scope)
&& (sig->port_type() == NetNet::PREF)) {
cerr << cur->get_fileline() << ": sorry: "
<< "Reference ports not supported yet." << endl;
des->errors += 1;
}
/* If the signal is an input and is also declared as a
reg, then report an error. */
@ -467,14 +476,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
case PTF_REG:
case PTF_REG_S:
if (return_type_.range) {
ivl_assert(*this, return_type_.range->size() == 2);
ivl_assert(*this, return_type_.range->size() == 1);
pform_range_t&return_range = return_type_.range->front();
NetExpr*me = elab_and_eval(des, scope,
return_type_.range->at(0), -1,
return_range.first, -1,
true);
assert(me);
NetExpr*le = elab_and_eval(des, scope,
return_type_.range->at(1), -1,
return_range.second, -1,
true);
assert(le);
@ -493,7 +503,9 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
des->errors += 1;
}
ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum);
list<NetNet::range_t> packed;
packed.push_back(NetNet::range_t(mnum, lnum));
ret_sig = new NetNet(scope, fname, NetNet::REG, packed);
ret_sig->set_scalar(false);
} else {
@ -539,17 +551,18 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
case PTF_ATOM2:
case PTF_ATOM2_S:
ivl_assert(*this, return_type_.range != 0);
long use_wid;
{
ivl_assert(*this, return_type_.range->size() == 1);
pform_range_t&return_range = return_type_.range->front();
NetExpr*me = elab_and_eval(des, scope,
(*return_type_.range)[0], -1,
return_range.first, -1,
true);
assert(me);
ivl_assert(*this, me);
NetExpr*le = elab_and_eval(des, scope,
(*return_type_.range)[1], -1,
return_range.second, -1,
true);
assert(le);
ivl_assert(*this, le);
long mnum = 0, lnum = 0;
if ( ! get_const_argument(me, mnum) ) {
@ -577,6 +590,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
ret_sig->data_type(IVL_VT_BOOL);
break;
case PTF_STRING:
cerr << get_fileline() << ": sorry: String functions are not supported yet" << endl;
break;
case PTF_VOID:
// Void functions have no return value, so there is no
// signal to create here.
break;
default:
if (ports_) {
cerr << get_fileline() << ": internal error: I don't know "
@ -780,6 +802,114 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const
statement_->elaborate_sig(des, scope);
}
static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope,
struct_type_t*struct_type)
{
netstruct_t*res = new netstruct_t;
res->packed(struct_type->packed_flag);
for (list<struct_member_t*>::iterator cur = struct_type->members->begin()
; cur != struct_type->members->end() ; ++ cur) {
struct_member_t*curp = *cur;
long use_msb = 0;
long use_lsb = 0;
if (curp->range.get() && ! curp->range->empty()) {
ivl_assert(*curp, curp->range->size() == 1);
pform_range_t&rangep = curp->range->front();
PExpr*msb_pex = rangep.first;
PExpr*lsb_pex = rangep.second;
NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true);
ivl_assert(*curp, tmp);
bool rc = eval_as_long(use_msb, tmp);
ivl_assert(*curp, rc);
tmp = elab_and_eval(des, scope, lsb_pex, -2, true);
ivl_assert(*curp, tmp);
rc = eval_as_long(use_lsb, tmp);
ivl_assert(*curp, rc);
}
for (list<decl_assignment_t*>::iterator name = curp->names->begin()
; name != curp->names->end() ; ++ name) {
decl_assignment_t*namep = *name;
netstruct_t::member_t memb;
memb.name = namep->name;
memb.type = curp->type;
memb.msb = use_msb;
memb.lsb = use_lsb;
res->append_member(memb);
}
}
return res;
}
static bool evaluate_ranges(Design*des, NetScope*scope,
list<NetNet::range_t>&llist,
const list<pform_range_t>&rlist)
{
bool bad_msb = false, bad_lsb = false;
for (list<pform_range_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
NetNet::range_t lrng;
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
if (! eval_as_long(lrng.msb, texpr)) {
cerr << cur->first->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << cur->first->get_fileline() << " : "
"This MSB expression violates the rule: "
<< *cur->first << endl;
des->errors += 1;
bad_msb = true;
}
delete texpr;
texpr = elab_and_eval(des, scope, cur->second, -1, true);
if (! eval_as_long(lrng.lsb, texpr)) {
cerr << cur->second->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << cur->second->get_fileline() << " : "
"This LSB expression violates the rule: "
<< *cur->second << endl;
des->errors += 1;
bad_lsb = true;
}
delete texpr;
llist.push_back(lrng);
}
return bad_msb | bad_lsb;
}
bool test_ranges_eeq(const list<NetNet::range_t>&lef, const list<NetNet::range_t>&rig)
{
if (lef.size() != rig.size())
return false;
list<NetNet::range_t>::const_iterator lcur = lef.begin();
list<NetNet::range_t>::const_iterator rcur = rig.begin();
while (lcur != lef.end()) {
if (lcur->msb != rcur->msb)
return false;
if (lcur->lsb != rcur->lsb)
return false;
++ lcur;
++ rcur;
}
return true;
}
/*
* Elaborate a source wire. The "wire" is the declaration of wires,
* registers, ports and memories. The parser has already merged the
@ -801,7 +931,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
unsigned wid = 1;
long lsb = 0, msb = 0;
list<NetNet::range_t>packed_dimensions;
des->errors += error_cnt_;
@ -841,135 +971,74 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
if (port_set_ || net_set_) {
long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0;
bool bad_lsb = false, bad_msb = false;
bool bad_range = false;
list<NetNet::range_t> plist, nlist;
/* If they exist get the port definition MSB and LSB */
if (port_set_ && port_msb_ != 0) {
NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true);
if (! eval_as_long(pmsb, texpr)) {
cerr << port_msb_->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << port_msb_->get_fileline() << " : "
"This MSB expression violates the rule: "
<< *port_msb_ << endl;
des->errors += 1;
bad_msb = true;
}
delete texpr;
texpr = elab_and_eval(des, scope, port_lsb_, -1, true);
if (! eval_as_long(plsb, texpr)) {
cerr << port_lsb_->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << port_lsb_->get_fileline() << " : "
"This LSB expression violates the rule: "
<< *port_lsb_ << endl;
des->errors += 1;
bad_lsb = true;
}
delete texpr;
nmsb = pmsb;
nlsb = plsb;
if (port_set_ && !port_.empty()) {
bad_range |= evaluate_ranges(des, scope, plist, port_);
nlist = plist;
/* An implicit port can have a range so note that here. */
is_implicit_scalar = false;
}
if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0);
if (port_msb_ == 0) assert(port_lsb_ == 0);
if (port_lsb_ == 0) assert(port_msb_ == 0);
assert(port_set_ || port_.empty());
/* If they exist get the net/etc. definition MSB and LSB */
if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) {
NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true);
if (! eval_as_long(nmsb, texpr)) {
cerr << net_msb_->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << net_msb_->get_fileline() << " : "
"This MSB expression violates the rule: "
<< *net_msb_ << endl;
des->errors += 1;
bad_msb = true;
}
delete texpr;
texpr = elab_and_eval(des, scope, net_lsb_, -1, true);
if (! eval_as_long(nlsb, texpr)) {
cerr << net_lsb_->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << net_lsb_->get_fileline() << " : "
"This LSB expression violates the rule: "
<< *net_lsb_ << endl;
des->errors += 1;
bad_lsb = true;
}
delete texpr;
if (net_set_ && !net_.empty() && !bad_range) {
nlist.clear();
bad_range |= evaluate_ranges(des, scope, nlist, net_);
}
if (!net_set_) assert(net_msb_ == 0 && net_lsb_ == 0);
if (net_msb_ == 0) assert(net_lsb_ == 0);
if (net_lsb_ == 0) assert(net_msb_ == 0);
assert(net_set_ || net_.empty());
/* If we find errors here, then give up on this signal. */
if (bad_range)
return 0;
/* We have a port size error */
if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) {
if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) {
/* Scalar port with a vector net/etc. definition */
if (port_msb_ == 0) {
if (port_.empty()) {
if (!gn_io_range_error_flag) {
cerr << get_fileline()
<< ": warning: Scalar port ``" << name_
<< "'' has a vectored net declaration ["
<< nmsb << ":" << nlsb << "]." << endl;
<< "'' has a vectored net declaration "
<< nlist << "." << endl;
} else {
cerr << get_fileline()
<< ": error: Scalar port ``" << name_
<< "'' has a vectored net declaration ["
<< nmsb << ":" << nlsb << "]." << endl;
<< "'' has a vectored net declaration "
<< nlist << "." << endl;
des->errors += 1;
return 0;
}
}
/* Vectored port with a scalar net/etc. definition */
if (net_msb_ == 0) {
cerr << port_msb_->get_fileline()
if (net_.empty()) {
cerr << port_.front().first->get_fileline()
<< ": error: Vectored port ``"
<< name_ << "'' [" << pmsb << ":" << plsb
<< "] has a scalar net declaration at "
<< name_ << "'' " << plist
<< " has a scalar net declaration at "
<< get_fileline() << "." << endl;
des->errors += 1;
return 0;
}
/* Both vectored, but they have different ranges. */
if (port_msb_ != 0 && net_msb_ != 0) {
cerr << port_msb_->get_fileline()
if (!port_.empty() && !net_.empty()) {
cerr << port_.front().first->get_fileline()
<< ": error: Vectored port ``"
<< name_ << "'' [" << pmsb << ":" << plsb
<< "] has a net declaration [" << nmsb << ":"
<< nlsb << "] at " << net_msb_->get_fileline()
<< name_ << "'' " << plist
<< " has a net declaration " << nlist
<< " at " << net_.front().first->get_fileline()
<< " that does not match." << endl;
des->errors += 1;
return 0;
}
}
/* Attempt to recover from errors. */
if (bad_lsb) nlsb = 0;
if (bad_msb) nmsb = nlsb;
lsb = nlsb;
msb = nmsb;
if (nmsb > nlsb)
wid = nmsb - nlsb + 1;
else
wid = nlsb - nmsb + 1;
packed_dimensions = nlist;
wid = NetNet::vector_width(packed_dimensions);
}
@ -1021,13 +1090,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
array_dimensions = 1;
}
if (data_type_ == IVL_VT_REAL && (msb != 0 || lsb != 0)) {
if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) {
cerr << get_fileline() << ": error: real ";
if (wtype == NetNet::REG) cerr << "variable";
else cerr << "net";
cerr << " '" << name_
<< "' cannot be declared as a vector, found a range ["
<< msb << ":" << lsb << "]." << endl;
<< "' cannot be declared as a vector, found a range "
<< packed_dimensions << "." << endl;
des->errors += 1;
return 0;
}
@ -1068,26 +1137,47 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
}
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype;
if (!get_scalar()) {
cerr << " ["<<msb<<":"<<lsb<<"]";
NetNet*sig = 0;
// If this is a struct type, then build the net with the
// struct type.
if (struct_type_) {
netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type_);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype;
if (use_type->packed())
cerr << " " << use_type->packed_width() << " bit packed struct ";
else
cerr << " struct <> ";
cerr << name_;
cerr << " in scope " << scope_path(scope) << endl;
}
cerr << " " << name_;
if (array_dimensions > 0) {
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
sig = new NetNet(scope, name_, wtype, use_type);
} else {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype;
if (!get_scalar()) {
cerr << " " << packed_dimensions;
}
cerr << " " << name_;
if (array_dimensions > 0) {
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
}
cerr << " in scope " << scope_path(scope) << endl;
}
cerr << " in scope " << scope_path(scope) << endl;
sig = array_dimensions > 0
? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0)
: new NetNet(scope, name_, wtype, packed_dimensions);
}
NetNet*sig = array_dimensions > 0
? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0)
: new NetNet(scope, name_, wtype, msb, lsb);
// If this is an enumeration, then set the enumeration set for
// the new signal. This turns it into an enumeration.
if (enum_type_) {
ivl_assert(*this, struct_type_ == 0);
ivl_assert(*this, ! enum_type_->names->empty());
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);

View File

@ -524,7 +524,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "tran device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, inst_name, IVL_SW_TRAN);
gate = new NetTran(scope, inst_name, IVL_SW_TRAN,
instance_width);
}
break;
@ -534,7 +535,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "rtran device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, inst_name, IVL_SW_RTRAN);
gate = new NetTran(scope, inst_name, IVL_SW_RTRAN,
instance_width);
}
break;
@ -544,7 +546,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "tranif0 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0);
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0,
instance_width);
}
break;
@ -554,7 +557,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "rtranif0 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0);
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0,
instance_width);
}
break;
@ -564,7 +568,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "tranif1 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1);
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1,
instance_width);
}
break;
@ -574,7 +579,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
<< "rtranif1 device." << endl;
des->errors += 1;
} else {
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1);
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1,
instance_width);
}
break;
@ -1063,6 +1069,10 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
ivl_assert(*this, 0);
break;
case NetNet::PREF:
ivl_assert(*this, 0);
break;
default:
ivl_assert(*this, 0);
}
@ -1500,6 +1510,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
} else {
/* Port type must be OUTPUT here. */
ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT);
/* Output from module. Elaborate the port
expression as the l-value of a continuous
@ -1634,6 +1645,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
/* This may not be correct! */
as_signed = prts[0]->get_signed() && sig->get_signed();
break;
case NetNet::PREF:
ivl_assert(*this, 0);
break;
default:
ivl_assert(*this, 0);
}
@ -1780,6 +1794,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
}
break;
case NetNet::PREF:
cerr << get_fileline() << ": sorry: "
<< "Reference ports not supported yet." << endl;
des->errors += 1;
break;
case NetNet::PIMPLICIT:
cerr << get_fileline() << ": internal error: "
<< "Unexpected IMPLICIT port" << endl;
@ -2805,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
des->errors += 1;
}
unsigned parm_count = nparms();
unsigned parm_count = parms_.size();
/* Catch the special case that the system task has no
parameters. The "()" string will be parsed as a single
empty parameter, when we really mean no parameters at all. */
if ((nparms() == 1) && (parm(0) == 0))
if ((parm_count== 1) && (parms_[0] == 0))
parm_count = 0;
svector<NetExpr*>eparms (parm_count);
@ -2818,7 +2838,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
perm_string name = peek_tail_name(path_);
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parm(idx);
PExpr*ex = parms_[idx];
if (ex != 0) {
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
} else {
@ -2910,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
}
assert(def);
if (nparms() != def->port_count()) {
unsigned parm_count = parms_.size();
// Handle special case that the definition has no arguments
// but the parser found a simgle nul argument. This is an
// argument of the parser allowing for the possibility of
// default values for argumets: The parser cannot tell the
// difference between "func()" and "func(<default>)".
if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0)
parm_count = 0;
if (parm_count != def->port_count()) {
cerr << get_fileline() << ": error: Port count mismatch in call to ``"
<< path_ << "''. Got " << nparms()
<< path_ << "''. Got " << parm_count
<< " ports, expecting " << def->port_count() << " ports." << endl;
des->errors += 1;
return 0;
@ -2922,7 +2953,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
/* Handle non-automatic tasks with no parameters specially. There is
no need to make a sequential block to hold the generated code. */
if ((nparms() == 0) && !task->is_auto()) {
if ((parm_count == 0) && !task->is_auto()) {
cur = new NetUTask(task);
cur->set_line(*this);
return cur;
@ -2954,7 +2985,23 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
expression the r-value. We know by definition that the port
is a reg type, so this elaboration is pretty obvious. */
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
if (parms_[idx] == 0 && !gn_system_verilog()) {
cerr << get_fileline() << ": error: "
<< "Missing argument " << (idx+1)
<< " of call to task." << endl;
des->errors += 1;
continue;
}
if (parms_[idx] == 0) {
cerr << get_fileline() << ": sorry: "
<< "Implicit arguments (arg " << (idx+1)
<< ") not supported." << endl;
des->errors += 1;
continue;
}
NetNet*port = def->port(idx);
assert(port->port_type() != NetNet::NOT_A_PORT);
@ -2965,7 +3012,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
unsigned wid = count_lval_width(lv);
ivl_variable_type_t lv_type = lv->expr_type();
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]);
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user "
@ -2995,7 +3042,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
expression that can be a target to a procedural
assignment, including a memory word. */
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
NetNet*port = def->port(idx);
@ -3774,8 +3821,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
const PEIdent*id1 = dynamic_cast<const PEIdent*>(name1_);
assert(id1);
const PEIdent*id2 = dynamic_cast<const PEIdent*>(name2_);
assert(id2);
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
top->set_line(*this);
@ -3820,32 +3865,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
body->append(tmp);
/* Elaborate the increment assignment statement at the end of
the for loop. This is also a very specific assignment
statement. Put this into the "body" block. */
sig = des->find_signal(scope, id2->path());
if (sig == 0) {
cerr << get_fileline() << ": error: Unable to find variable "
<< id2->path() << " in for-loop increment expression." << endl;
des->errors += 1;
return body;
}
assert(sig);
lv = new NetAssign_(sig);
/* Make the r-value of the increment assignment, and size it
properly. Then use it to build the assignment statement. */
etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
expr2_);
/* Now elaborate the for_step statement. I really should do
some error checking here to make sure the step statement
really does step the variable. */
if (debug_elaborate) {
cerr << get_fileline() << ": debug: FOR increment assign: "
cerr << get_fileline() << ": debug: Elaborate for_step statement "
<< sig->name() << " = " << *etmp << endl;
}
NetAssign*step = new NetAssign(lv, etmp);
step->set_line(*this);
NetProc*step = step_->elaborate(des, scope);
body->append(step);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -28,71 +28,71 @@ functor_t::~functor_t()
{
}
void functor_t::event(class Design*, class NetEvent*)
void functor_t::event(Design*, NetEvent*)
{
}
void functor_t::signal(class Design*, class NetNet*)
void functor_t::signal(Design*, NetNet*)
{
}
void functor_t::process(class Design*, class NetProcTop*)
void functor_t::process(Design*, NetProcTop*)
{
}
void functor_t::lpm_abs(class Design*, class NetAbs*)
void functor_t::lpm_abs(Design*, NetAbs*)
{
}
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
void functor_t::lpm_add_sub(Design*, NetAddSub*)
{
}
void functor_t::lpm_compare(class Design*, class NetCompare*)
void functor_t::lpm_compare(Design*, NetCompare*)
{
}
void functor_t::lpm_const(class Design*, class NetConst*)
void functor_t::lpm_const(Design*, NetConst*)
{
}
void functor_t::lpm_divide(class Design*, class NetDivide*)
void functor_t::lpm_divide(Design*, NetDivide*)
{
}
void functor_t::lpm_literal(class Design*, class NetLiteral*)
void functor_t::lpm_literal(Design*, NetLiteral*)
{
}
void functor_t::lpm_modulo(class Design*, class NetModulo*)
void functor_t::lpm_modulo(Design*, NetModulo*)
{
}
void functor_t::lpm_ff(class Design*, class NetFF*)
void functor_t::lpm_ff(Design*, NetFF*)
{
}
void functor_t::lpm_logic(class Design*, class NetLogic*)
void functor_t::lpm_logic(Design*, NetLogic*)
{
}
void functor_t::lpm_mult(class Design*, class NetMult*)
void functor_t::lpm_mult(Design*, NetMult*)
{
}
void functor_t::lpm_mux(class Design*, class NetMux*)
void functor_t::lpm_mux(Design*, NetMux*)
{
}
void functor_t::lpm_pow(class Design*, class NetPow*)
void functor_t::lpm_pow(Design*, NetPow*)
{
}
void functor_t::sign_extend(class Design*, class NetSignExtend*)
void functor_t::sign_extend(Design*, NetSignExtend*)
{
}
void functor_t::lpm_ureduce(class Design*, class NetUReduce*)
void functor_t::lpm_ureduce(Design*, NetUReduce*)
{
}

View File

@ -230,6 +230,9 @@ ivl_signal_msb
ivl_signal_name
ivl_signal_nex
ivl_signal_npath
ivl_signal_packed_dimensions
ivl_signal_packed_lsb
ivl_signal_packed_msb
ivl_signal_path
ivl_signal_port
ivl_signal_scope

View File

@ -1785,13 +1785,23 @@ extern int ivl_scope_time_units(ivl_scope_t net);
* If the signal has been declared with a domain (Verilog-AMS) then
* this function will return a non-nil ivl_discipline_t.
*
* ivl_signal_msb
* ivl_signal_lsb
* ivl_signal_msb (deprecated)
* ivl_signal_lsb (deprecated)
* ivl_signal_packed_dimensions
* ivl_signal_packed_msb
* ivl_signal_packed_lsb
* ivl_signal_width
* These functions return the left and right indices, respectively,
* of the signal. If the signal is a scalar, both return 0. However,
* it doesn't mean that the signal is a scalar if both return 0, one
* can have a vector with 0 as both indices.
* These functions return the msb and lsb packed indices. The
* packed dimensions are declared differently from array
* dimensions, like so:
* reg [4:1][7:0] sig...
* which has two packed dimensions. The [4:1] dimension is the
* first, and so forth. If the signal is a scalar, it has 0
* dimension.
*
* The ivl_signal_msb/ivl_signal_lsb functions are deprecated
* versions that only work with variables that have less than two
* dimensions. They will return msb==lsb==0 for scalars.
*
* ivl_signal_port
* If the signal is a port to a module, this function returns the
@ -1859,8 +1869,11 @@ extern unsigned ivl_signal_array_count(ivl_signal_t net);
extern unsigned ivl_signal_array_addr_swapped(ivl_signal_t net);
extern unsigned ivl_signal_dimensions(ivl_signal_t net);
extern ivl_discipline_t ivl_signal_discipline(ivl_signal_t net);
extern int ivl_signal_msb(ivl_signal_t net);
extern int ivl_signal_lsb(ivl_signal_t net);
extern unsigned ivl_signal_packed_dimensions(ivl_signal_t net);
extern int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim);
extern int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim);
extern int ivl_signal_msb(ivl_signal_t net) __attribute__((deprecated));
extern int ivl_signal_lsb(ivl_signal_t net) __attribute__((deprecated));
extern unsigned ivl_signal_width(ivl_signal_t net);
extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net);
extern int ivl_signal_signed(ivl_signal_t net);
@ -2000,7 +2013,7 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net);
* is the compressed operator used it statements like this:
* foo += <expr>
* The ivl_stmt_opcode() returns null (0) if this is not a compressed
* assignment statment.
* assignment statement.
*
* - IVL_ST_CASSIGN
* This reflects a procedural continuous assignment to an l-value. The

View File

@ -69,8 +69,8 @@ Makefile: $(srcdir)/Makefile.in ../config.status
ivlpp@EXEEXT@: $O
$(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@
lexor.c: lexor.lex
$(LEX) -olexor.c $(srcdir)/lexor.lex
lexor.c: $(srcdir)/lexor.lex
$(LEX) -t $< > $@
install: all installdirs $(libdir)/ivl$(suffix)/ivlpp@EXEEXT@

View File

@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -51,7 +51,7 @@
*/
extern YYLTYPE yylloc;
static char* strdupnew(char const *str)
char* strdupnew(char const *str)
{
return str ? strcpy(new char [strlen(str)+1], str) : 0;
}
@ -191,7 +191,7 @@ TU [munpf]
">>>=" { return K_RSS_EQ; }
"++" { return K_INCR; }
"--" {return K_DECR; }
"'{" { return K_LP; }
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
and ")", but since I know that this is really ( * ), replace it
@ -303,11 +303,22 @@ TU [munpf]
perm_string tmp = lex_strings.make(yylval.text);
map<perm_string,ivl_discipline_t>::iterator cur = disciplines.find(tmp);
if (cur != disciplines.end()) {
delete[]yylval.text;
yylval.discipline = (*cur).second;
rc = DISCIPLINE_IDENTIFIER;
}
}
/* If this identifier names a previously declared type, then
return this as a TYPE_IDENTIFIER instead. */
if (rc == IDENTIFIER && gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
delete[]yylval.text;
yylval.data_type = type;
rc = TYPE_IDENTIFIER;
}
}
return rc;
}
@ -366,8 +377,11 @@ TU [munpf]
<< "Using SystemVerilog 'N bit vector. Use at least "
<< "-g2005-sv to remove this warning." << endl;
}
generation_t generation_save = generation_flag;
generation_flag = GN_VER2005_SV;
yylval.number = make_unsized_binary(yytext);
return BASED_NUMBER; }
generation_flag = generation_save;
return UNBASED_NUMBER; }
[0-9][0-9_]* {
yylval.number = make_unsized_dec(yytext);

View File

@ -1,7 +1,7 @@
#ifndef __LineInfo_H
#define __LineInfo_H
/*
* Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2011 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
@ -40,7 +40,7 @@ class LineInfo {
// Get a fully formatted file/lineno
string get_fileline() const;
// Set the file/line fro another LineInfo object.
// Set the file/line from another LineInfo object.
void set_line(const LineInfo&that);
// Access parts of LineInfo data

View File

@ -46,7 +46,6 @@ endif
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
LDFLAGS = @LDFLAGS@
A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \
a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \

View File

@ -641,8 +641,8 @@ void NetScope::evaluate_parameters(Design*des)
cur->second->evaluate_parameters(des);
if (debug_scopes)
cerr << ":0" << ": debug: "
<< "Evaluate parameters in " << scope_path(this) << endl;
cerr << "debug: "
<< "Evaluating parameters in " << scope_path(this) << endl;
for (param_ref_t cur = parameters.begin()
; cur != parameters.end() ; ++ cur) {

View File

@ -278,7 +278,7 @@ bool Nexus::assign_lval() const
if (net == 0)
continue;
if (net->peek_lref())
if (net->peek_lref() > 0)
return true;
}

View File

@ -42,15 +42,15 @@ static bool has_enable(ivl_switch_type_t tt)
}
}
NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt)
: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt)
NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt,
unsigned width)
: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt), wid_(width)
{
pin(0).set_dir(Link::PASSIVE);
pin(1).set_dir(Link::PASSIVE);
if (pin_count() == 3) {
pin(2).set_dir(Link::INPUT); // Enable
}
wid_ = 0;
part_ = 0;
off_ = 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -27,6 +27,7 @@
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "netstruct.h"
# include "ivl_assert.h"
@ -450,12 +451,15 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0),
s0_(0), e0_(0), eref_count_(0), lref_count_(0)
enumeration_(0), struct_type_(0), discipline_(0),
dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0)
{
assert(s);
assert(npins>0);
// Synthesize a single range to describe this canonical vector.
packed_dims_.push_back(NetNet::range_t(npins-1, 0));
Link::DIR dir = Link::PASSIVE;
switch (t) {
@ -492,15 +496,15 @@ void NetNet::initialize_dir_(Link::DIR dir)
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls)
const list<NetNet::range_t>&packed)
: NetObj(s, n, 1), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), discipline_(0),
msb_(ms), lsb_(ls),
enumeration_(0), struct_type_(0), discipline_(0),
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
assert(s);
Link::DIR dir = Link::PASSIVE;
@ -540,15 +544,16 @@ static unsigned calculate_count(long s, long e)
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls, long array_s, long array_e)
const list<NetNet::range_t>&packed, long array_s, long array_e)
: NetObj(s, n, calculate_count(array_s, array_e)),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), discipline_(0),
msb_(ms), lsb_(ls),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0),
discipline_(0),
dimensions_(1), s0_(array_s), e0_(array_e),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
ivl_assert(*this, s);
if (pin_count() == 0) {
cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl;
@ -577,6 +582,52 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
s->add_signal(this);
}
static unsigned calculate_count(netstruct_t*type)
{
long wid = type->packed_width();
if (wid >= 0)
return wid;
else
return 1;
}
/*
* When we create a netnet for a packed struct, create a single
* vector with the msb_/lsb_ chosen to name enough bits for the entire
* packed structure.
*/
NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty),
discipline_(0),
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_.push_back(range_t(calculate_count(ty)-1, 0));
Link::DIR dir = Link::PASSIVE;
switch (t) {
case REG:
case IMPLICIT_REG:
dir = Link::OUTPUT;
break;
case SUPPLY0:
dir = Link::OUTPUT;
break;
case SUPPLY1:
dir = Link::OUTPUT;
break;
default:
break;
}
initialize_dir_(dir);
s->add_signal(this);
}
NetNet::~NetNet()
{
if (eref_count_ > 0) {
@ -692,10 +743,16 @@ netenum_t*NetNet::enumeration(void) const
void NetNet::set_enumeration(netenum_t*es)
{
ivl_assert(*this, struct_type_ == 0);
ivl_assert(*this, enumeration_ == 0);
enumeration_ = es;
}
netstruct_t*NetNet::struct_type(void) const
{
return struct_type_;
}
ivl_discipline_t NetNet::get_discipline() const
{
return discipline_;
@ -707,40 +764,121 @@ void NetNet::set_discipline(ivl_discipline_t dis)
discipline_ = dis;
}
long NetNet::lsb() const
unsigned long NetNet::vector_width(const list<NetNet::range_t>&packed)
{
return lsb_;
unsigned wid = 1;
for (list<NetNet::range_t>::const_iterator cur = packed.begin()
; cur != packed.end() ; ++cur) {
unsigned use_wid;
if (cur->msb >= cur->lsb)
use_wid = cur->msb - cur->lsb + 1;
else
use_wid = cur->lsb - cur->msb + 1;
wid *= use_wid;
}
return wid;
}
long NetNet::msb() const
bool NetNet::sb_is_valid(const list<long>&indices, long sb) const
{
return msb_;
}
unsigned long NetNet::vector_width() const
{
if (msb_ > lsb_)
return msb_ - lsb_ + 1;
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
assert(packed_dims_.size() == 1);
const range_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
return (sb <= rng.msb) && (sb >= rng.lsb);
else
return lsb_ - msb_ + 1;
return (sb <= rng.lsb) && (sb >= rng.msb);
}
bool NetNet::sb_is_valid(long sb) const
long NetNet::sb_to_idx(const list<long>&indices, long sb) const
{
if (msb_ >= lsb_)
return (sb <= msb_) && (sb >= lsb_);
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
list<range_t>::const_iterator pcur = packed_dims_.end();
-- pcur;
long acc_off;
long acc_wid = pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off = sb - pcur->lsb;
else
return (sb <= lsb_) && (sb >= msb_);
acc_off = pcur->lsb - sb;
// The acc_off is the possition within the innermost
// dimension. If this is a multi-dimension packed array then
// we need to add in the canonical address of the current slice.
if (indices.size() >= 1) {
list<long>::const_iterator icur = indices.end();
do {
-- icur;
-- pcur;
long tmp_off;
if (pcur->msb >= pcur->lsb)
tmp_off = *icur - pcur->lsb;
else
tmp_off = pcur->lsb - *icur;
acc_off += tmp_off * acc_wid;
acc_wid *= pcur->width();
} while (icur != indices.begin());
}
return acc_off;
}
long NetNet::sb_to_idx(long sb) const
bool NetNet::sb_to_slice(const list<long>&indices, long sb, long&loff, unsigned long&lwid) const
{
if (msb_ >= lsb_)
return sb - lsb_;
ivl_assert(*this, indices.size() < packed_dims_.size());
size_t acc_wid = 1;
list<range_t>::const_iterator pcur = packed_dims_.end();
for (size_t idx = indices.size()+1 ; idx < packed_dims_.size() ; idx += 1) {
-- pcur;
acc_wid *= pcur->width();
}
lwid = acc_wid;
-- pcur;
if (sb < pcur->msb && sb < pcur->lsb)
return false;
if (sb > pcur->msb && sb > pcur->lsb)
return false;
long acc_off = 0;
if (pcur->msb >= pcur->lsb)
acc_off += (sb - pcur->lsb) * acc_wid;
else
return lsb_ - sb;
acc_off += (sb - pcur->msb) * acc_wid;
if (indices.size() == 0) {
loff = acc_off;
return true;
}
lwid *= pcur->width();
list<long>::const_iterator icur = indices.end();
do {
-- pcur;
-- icur;
acc_wid *= pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off += (*icur - pcur->lsb) * acc_wid;
else
acc_off += (*icur - pcur->msb) * acc_wid;
} while (icur != indices.begin());
loff = acc_off;
return true;
}
unsigned NetNet::array_dimensions() const
{
return dimensions_;
@ -802,6 +940,26 @@ unsigned NetNet::peek_eref() const
return eref_count_;
}
/*
* Test each of the bits in the range, and set them. If any bits are
* already set then return true.
*/
bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb)
{
if (lref_mask_.size() == 0)
lref_mask_.resize(vector_width());
bool rc = false;
for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) {
if (lref_mask_[idx])
rc = true;
else
lref_mask_[idx] = true;
}
return rc;
}
void NetNet::incr_lref()
{
lref_count_ += 1;
@ -2296,14 +2454,23 @@ NetNet* NetESignal::sig()
return net_;
}
/*
* The lsi() and msi() methods should be removed from the NetESignal
* class, to be replaced with packed dimensions aware methods of
* getting at dimensions.
*/
long NetESignal::lsi() const
{
return net_->lsb();
const list<NetNet::range_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().lsb;
}
long NetESignal::msi() const
{
return net_->msb();
const list<NetNet::range_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().msb;
}
ivl_variable_type_t NetESignal::expr_type() const
@ -2429,7 +2596,7 @@ NetECast::~NetECast()
ivl_variable_type_t NetECast::expr_type() const
{
ivl_variable_type_t ret;
ivl_variable_type_t ret = IVL_VT_NO_TYPE;
switch (op_) {
case 'v':
ret = IVL_VT_LOGIC;

View File

@ -1,7 +1,7 @@
#ifndef __netlist_H
#define __netlist_H
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -75,6 +75,7 @@ class NetEvWait;
class PExpr;
class PFunction;
class netenum_t;
class netstruct_t;
struct target;
struct functor_t;
@ -549,7 +550,7 @@ class NetDelaySrc : public NetObj {
*
* NetNet objects are located by searching NetScope objects.
*
* The pin of a NetNet object are PASSIVE: they do not drive
* The pins of a NetNet object are PASSIVE: they do not drive
* anything and they are not a data sink, per se. The pins follow the
* values on the nexus.
*/
@ -560,8 +561,24 @@ class NetNet : public NetObj {
SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG,
UNRESOLVED_WIRE };
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT };
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF };
struct range_t {
inline range_t() : msb(0), lsb(0) { }
inline range_t(long m, long l) : msb(m), lsb(l) { }
inline range_t(const range_t&that)
: msb(that.msb), lsb(that.lsb) { }
inline range_t& operator = (const range_t&that)
{ msb = that.msb; lsb = that.lsb; return *this; }
long msb;
long lsb;
inline unsigned long width()const
{ if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; }
};
public:
// The width in this case is a shorthand for ms=width-1 and
// ls=0. Only one pin is created, the width is of the vector
// that passed through.
@ -572,9 +589,12 @@ class NetNet : public NetObj {
// dimensions. If s0==e0, then this is not an array after
// all.
explicit NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls);
const std::list<range_t>&packed);
explicit NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls, long s0, long e0);
const std::list<range_t>&packed, long s0, long e0);
// This form builds a NetNet from its record definition.
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
virtual ~NetNet();
@ -603,27 +623,49 @@ class NetNet : public NetObj {
void set_enumeration(netenum_t*enum_set);
netenum_t*enumeration(void) const;
netstruct_t*struct_type(void) const;
/* Attach a discipline to the net. */
ivl_discipline_t get_discipline() const;
void set_discipline(ivl_discipline_t dis);
/* These methods return the msb and lsb indices for the most
significant and least significant bits. These are signed
longs, and may be different from pin numbers. For example,
reg [1:8] has 8 bits, msb==1 and lsb==8. */
long msb() const;
long lsb() const;
unsigned long vector_width() const;
/* This method returns a reference to the packed dimensions
for the vector. These are arranged as a list where the
first range in the list (front) is the left-most range in
the verilog declaration. */
const std::list<range_t>& packed_dims() const { return packed_dims_; }
/* The vector_width returns the bit width of the packed array,
vector or scaler that is this NetNet object. The static
method is also a convenient way to convert a range list to
a vector width. */
static unsigned long vector_width(const std::list<NetNet::range_t>&);
unsigned long vector_width() const { return vector_width(packed_dims_); }
/* Given a prefix of indices, figure out how wide the
resulting slice would be. This is a generalization of the
vector_width(), where the depth would be 0. */
unsigned long slice_width(size_t depth) const;
/* This method converts a signed index (the type that might be
found in the Verilog source) to a pin number. It accounts
for variation in the definition of the reg/wire/whatever. */
long sb_to_idx(long sb) const;
found in the Verilog source) to canonical. It accounts
for variation in the definition of the
reg/wire/whatever. Note that a canonical index of a
multi-dimensioned packed array is a single dimension. For
example, "reg [4:1][3:0]..." has the canonical dimension
[15:0] and the sb_to_idx() method will convert [2][2] to
the canonical index [6]. */
long sb_to_idx(const std::list<long>&prefix, long sb) const;
/* This method converts a partial packed indices list and a
tail index, and generates a canonical slice offset and
width. */
bool sb_to_slice(const std::list<long>&prefix, long sb, long&off, unsigned long&wid) const;
/* This method checks that the signed index is valid for this
signal. If it is, the above sb_to_idx can be used to get
the pin# from the index. */
bool sb_is_valid(long sb) const;
bool sb_is_valid(const std::list<long>&prefix, long sb) const;
/* This method returns 0 for scalars and vectors, and greater
for arrays. The value is the number of array
@ -654,6 +696,7 @@ class NetNet : public NetObj {
void incr_lref();
void decr_lref();
unsigned peek_lref() const { return lref_count_; }
bool test_part_lref(unsigned msb, unsigned lsb);
unsigned get_refs() const;
@ -676,18 +719,25 @@ class NetNet : public NetObj {
bool is_scalar_ : 1;
bool local_flag_: 1;
netenum_t*enumeration_;
netstruct_t*struct_type_;
ivl_discipline_t discipline_;
long msb_, lsb_;
std::list<range_t> packed_dims_;
const unsigned dimensions_;
long s0_, e0_;
unsigned eref_count_;
unsigned lref_count_;
// When the signal is an unresolved wire, we need more detail
// which bits are assigned. This mask is true for each bit
// that is known to be driven.
std::vector<bool> lref_mask_;
vector<class NetDelaySrc*> delay_paths_;
};
extern std::ostream&operator << (std::ostream&out, const std::list<NetNet::range_t>&rlist);
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is
@ -1613,7 +1663,8 @@ class NetTran : public NetNode, public IslandBranch {
public:
// Tran devices other than TRAN_VP
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type,
unsigned wid);
// Create a TRAN_VP
NetTran(NetScope*scope, perm_string n, unsigned wid,
unsigned part, unsigned off);
@ -2315,6 +2366,8 @@ class NetAssign_ {
ivl_select_type_t select_type() const;
void set_word(NetExpr*);
// Set a part select expression for the l-value vector. Note
// that the expression calculates a CANONICAL bit address.
void set_part(NetExpr* loff, unsigned wid,
ivl_select_type_t = IVL_SEL_OTHER);

View File

@ -27,55 +27,6 @@
# include "compiler.h"
# include "ivl_assert.h"
// This routines is not currently used!
#if 0
NetNet* add_to_net(Design*des, NetNet*sig, long val)
{
if (val == 0)
return sig;
cerr << sig->get_fileline() << ": XXXX: Forgot how to implement add_to_net" << endl;
return 0;
NetScope*scope = sig->scope();
unsigned long abs_val = (val >= 0)? val : (-val);
unsigned width = sig->pin_count();
verinum val_v (abs_val, width);
NetConst*val_c = new NetConst(scope, scope->local_symbol(), val_v);
NetNet*val_s = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width);
val_s->local_flag(true);
NetNet*res = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width);
res->local_flag(true);
NetAddSub*add = new NetAddSub(scope, scope->local_symbol(), width);
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(sig->pin(idx), add->pin_DataA(idx));
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(val_c->pin(idx), add->pin_DataB(idx));
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(val_s->pin(idx), add->pin_DataB(idx));
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(res->pin(idx), add->pin_Result(idx));
if (val < 0)
add->attribute(perm_string::literal("LPM_Direction"), verinum("SUB"));
else
add->attribute(perm_string::literal("LPM_Direction"), verinum("ADD"));
des->add_node(add);
des->add_node(val_c);
return res;
}
#endif
NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig)
{
@ -247,6 +198,21 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val)
{
verinum val_v (val, expr->expr_width());
val_v.has_sign(true);
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
NetEBMult*res = new NetEBMult('*', expr, val_c, expr->expr_width(),
expr->has_sign());
res->set_line(*expr);
return res;
}
/*
* This routine is used to calculate the number of bits needed to
* contain the given number.
@ -273,10 +239,13 @@ static unsigned num_bits(long arg)
/*
* This routine generates the normalization expression needed for a variable
* bit select or a variable base expression for an indexed part select.
* bit select or a variable base expression for an indexed part
* select. This function doesn't actually look at the variable
* dimensions, it just does the final calculation using msb/lsb of the
* last slice, and the off of the slice in the variable.
*/
NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
unsigned long wid, bool is_up)
unsigned long wid, bool is_up, long soff)
{
long offset = lsb;
@ -309,13 +278,13 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
base = tmp;
}
/* Normalize the expression. */
base = make_sub_expr(offset, base);
base = make_sub_expr(offset+soff, base);
} else {
/* Correct the offset if needed. */
if (!is_up) offset += wid - 1;
/* If the offset is zero then just return the base (index)
* expression. */
if (offset == 0) return base;
if ((soff-offset) == 0) return base;
/* Calculate the space needed for the offset. */
unsigned min_wid = num_bits(-offset);
/* We need enough space for the larger of the offset or the
@ -338,12 +307,83 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
base = tmp;
}
/* Normalize the expression. */
base = make_add_expr(base, -offset);
base = make_add_expr(base, soff-offset);
}
return base;
}
/*
* This method is how indices should work except that the base should
* be a vector of expressions that matches the size of the dims list,
* so that we can generate an expression based on the entire packed
* vector. For now, we assert that there is only one set of dimensions.
*/
NetExpr *normalize_variable_base(NetExpr *base,
const list<NetNet::range_t>&dims,
unsigned long wid, bool is_up)
{
ivl_assert(*base, dims.size() == 1);
const NetNet::range_t&rng = dims.back();
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up);
}
NetExpr *normalize_variable_bit_base(const list<long>&indices, NetExpr*base,
const NetNet*reg)
{
const list<NetNet::range_t>&packed_dims = reg->packed_dims();
ivl_assert(*base, indices.size()+1 == packed_dims.size());
// Get the canonical offset of the slice within which we are
// addressing. We need that address as a slice offset to
// calculate the proper complete address
const NetNet::range_t&rng = packed_dims.back();
long slice_off = reg->sb_to_idx(indices, rng.lsb);
return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off);
}
NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*base,
const NetNet*reg,
unsigned long wid, bool is_up)
{
const list<NetNet::range_t>&packed_dims = reg->packed_dims();
ivl_assert(*base, indices.size()+1 == packed_dims.size());
// Get the canonical offset of the slice within which we are
// addressing. We need that address as a slice offset to
// calculate the proper complete address
const NetNet::range_t&rng = packed_dims.back();
long slice_off = reg->sb_to_idx(indices, rng.lsb);
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off);
}
NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
const NetNet*reg, unsigned long&lwid)
{
const list<NetNet::range_t>&packed_dims = reg->packed_dims();
ivl_assert(*base, indices.size() < packed_dims.size());
list<NetNet::range_t>::const_iterator pcur = packed_dims.end();
for (size_t idx = indices.size() ; idx < packed_dims.size(); idx += 1) {
-- pcur;
}
long sb;
if (pcur->msb >= pcur->lsb)
sb = pcur->lsb;
else
sb = pcur->msb;
long loff;
reg->sb_to_slice(indices, sb, loff, lwid);
base = make_mult_expr(base, lwid);
base = make_add_expr(base, loff);
return base;
}
/*
* This routine generates the normalization expression needed for a variable
* array word select.
@ -892,3 +932,39 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig)
delete ps_obj;
}
}
/*
* Evaluate the prefix indices. All but the final index in a
* chain of indices must be a single value and must evaluate
* to constants at compile time. For example:
* [x] - OK
* [1][2][x] - OK
* [1][x:y] - OK
* [2:0][x] - BAD
* [y][x] - BAD
* Leave the last index for special handling.
*/
bool evaluate_index_prefix(Design*des, NetScope*scope,
list<long>&prefix_indices,
const list<index_component_t>&indices)
{
list<index_component_t>::const_iterator icur = indices.begin();
for (size_t idx = 0 ; (idx+1) < indices.size() ; idx += 1, ++icur) {
assert(icur != indices.end());
assert(icur->sel == index_component_t::SEL_BIT);
NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, true);
long tmp;
if (texpr == 0 || !eval_as_long(tmp, texpr)) {
cerr << icur->msb->get_fileline() << ": error: "
"Array index expressions must be constant here." << endl;
des->errors += 1;
return false;
}
prefix_indices .push_back(tmp);
delete texpr;
}
return true;
}

View File

@ -99,7 +99,49 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
* the provided vector/array information.
*/
extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
unsigned long wid, bool is_up);
unsigned long wid, bool is_up,
long slice_off =0);
extern NetExpr*normalize_variable_base(NetExpr *base,
const list<NetNet::range_t>&dims,
unsigned long wid, bool is_up);
/*
* Calculate a canonicalizing expression for a bit select, when the
* base expression is the last index of an otherwise complete bit
* select. For example:
* reg [3:0][7:0] foo;
* ... foo[1][x] ...
* base is (x) and the generated expression will be (x+8).
*/
extern NetExpr*normalize_variable_bit_base(const list<long>&indices, NetExpr *base,
const NetNet*reg);
/*
* This is similar to normalize_variable_bit_base, but the tail index
* it a base and width, instead of a bit. This is used for handling
* indexed part selects:
* reg [3:0][7:0] foo;
* ... foo[1][x +: 2]
* base is (x), wid input is (2), and is_up is (true). The output
* expression is (x+8).
*/
extern NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*base,
const NetNet*reg,
unsigned long wid, bool is_up);
/*
* Calculate a canonicalizing expression for a slice select. The
* indices array is less than needed to fully address a bit, so the
* result is a slice of the packed array. The return value is an
* expression that gets to the base of the slice, and (lwid) becomes
* the width of the slice, in bits. For example:
* reg [4:1][7:0] foo
* ...foo[x]...
* base is (x) and the generated expression will be (x*8 - 8), with
* lwid set to (8).
*/
extern NetExpr*normalize_variable_slice_base(const list<long>&indices, NetExpr *base,
const NetNet*reg, unsigned long&lwid);
extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
unsigned count);
@ -235,4 +277,7 @@ extern uint64_t get_scaled_time_from_real(Design*des,
extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig);
extern bool evaluate_index_prefix(Design*des, NetScope*scope,
list<long>&prefix_indices,
const list<index_component_t>&indices);
#endif

68
netstruct.cc Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2011 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 "netstruct.h"
# include <iostream>
using namespace std;
netstruct_t::netstruct_t()
: packed_(false)
{
}
netstruct_t::~netstruct_t()
{
}
void netstruct_t::packed(bool flag)
{
packed_ = flag;
}
void netstruct_t::append_member(const netstruct_t::member_t&val)
{
members_.push_back(val);
}
const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsigned long&off) const
{
unsigned long count_off = 0;
for (size_t idx = members_.size() ; idx > 0 ; idx -= 1) {
if (members_[idx-1].name == name) {
off = count_off;
return &members_[idx-1];
}
count_off += members_[idx-1].width();
}
return 0;
}
long netstruct_t::packed_width(void) const
{
if (! packed_)
return -1;
long res = 0;
for (size_t idx = 0 ; idx < members_.size() ; idx += 1)
res += members_[idx].width();
return res;
}

73
netstruct.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef __netstruct_H
#define __netstruct_H
/*
* Copyright (c) 2011-2012 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 "LineInfo.h"
# include <vector>
# include "ivl_target.h"
class netstruct_t : public LineInfo {
public:
struct member_t {
perm_string name;
ivl_variable_type_t type;
long msb;
long lsb;
long width() const;
ivl_variable_type_t data_type() const { return type; };
// We need to keep the individual element sign information.
bool get_signed() const { return false; };
};
public:
netstruct_t();
~netstruct_t();
void packed(bool flag);
bool packed(void) const;
void append_member(const member_t&);
// Given the name of a member, return a pointer to the member
// description, and set the off value to be the offset into
// the packed value where the member begins.
const struct member_t* packed_member(perm_string name, unsigned long&off) const;
// Return the width (in bits) of the packed record, or -1 if
// the record is not packed.
long packed_width() const;
private:
bool packed_;
std::vector<member_t>members_;
};
inline bool netstruct_t::packed(void) const { return packed_; }
inline long netstruct_t::member_t::width() const
{
if (msb >= lsb)
return msb - lsb + 1;
else
return lsb - msb + 1;
}
#endif

2882
parse.y

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,8 @@
# include "config.h"
# include "parse_misc.h"
# include <cstdarg>
# include <cstdio>
# include <iostream>
extern const char*vl_file;
@ -42,10 +44,16 @@ void VLerror(const char*msg)
cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl;
}
void VLerror(const YYLTYPE&loc, const char*msg)
void VLerror(const YYLTYPE&loc, const char*msg, ...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s:%d: ", loc.text, loc.first_line);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
error_count += 1;
cerr << loc << ": " << msg << endl;
based_size = 0; /* Clear the base information if we have an error. */
}

View File

@ -56,7 +56,7 @@ extern YYLTYPE yylloc;
*/
extern int VLlex();
extern void VLerror(const char*msg);
extern void VLerror(const YYLTYPE&loc, const char*msg);
extern void VLerror(const YYLTYPE&loc, const char*msg, ...) __attribute__((format(printf,2,3)));
#define yywarn VLwarn
extern void VLwarn(const YYLTYPE&loc, const char*msg);
@ -77,6 +77,14 @@ extern UCDriveType uc_drive;
extern bool have_timeunit_decl;
extern bool have_timeprec_decl;
/*
* Test if this identifier is a type identifier in the current
* context. The pform code needs to help the lexor here because the
* parser detects typedefs and marks the typedef'ed identifiers as
* type names.
*/
extern data_type_t* pform_test_type_identifier(const char*txt);
/*
* Export these functions because we have to generate PENumber class
* in pform.cc for user defparam definition from command file.
@ -87,4 +95,6 @@ extern verinum*make_unsized_binary(const char*txt);
extern verinum*make_unsized_octal(const char*txt);
extern verinum*make_unsized_hex(const char*txt);
extern char* strdupnew(char const *str);
#endif

428
pform.cc
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -23,6 +23,7 @@
# include "pform.h"
# include "parse_misc.h"
# include "parse_api.h"
# include "PClass.h"
# include "PEvent.h"
# include "PUdp.h"
# include "PGenerate.h"
@ -267,12 +268,30 @@ void pform_pop_scope()
lexical_scope = lexical_scope->parent_scope();
}
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
{
PClass*class_scope = new PClass(name, lexical_scope);
FILE_NAME(class_scope, loc);
lexical_scope = class_scope;
return class_scope;
}
PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
{
perm_string task_name = lex_strings.make(name);
PTask*task = new PTask(task_name, lexical_scope, is_auto);
FILE_NAME(task, loc);
LexicalScope*scope = lexical_scope;
PScopeExtra*scopex = dynamic_cast<PScopeExtra*> (scope);
while (scope && !scopex) {
scope = scope->parent_scope();
scopex = dynamic_cast<PScopeExtra*> (scope);
}
assert(scopex);
if (pform_cur_generate) {
// Check if the task is already in the dictionary.
if (pform_cur_generate->tasks.find(task->pscope_name()) !=
@ -286,15 +305,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
pform_cur_generate->tasks[task->pscope_name()] = task;
} else {
// Check if the task is already in the dictionary.
if (pform_cur_module->tasks.find(task->pscope_name()) !=
pform_cur_module->tasks.end()) {
if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) {
cerr << task->get_fileline() << ": error: duplicate "
"definition for task '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
pform_cur_module->tasks[task->pscope_name()] = task;
scopex->tasks[task->pscope_name()] = task;
}
lexical_scope = task;
return task;
@ -307,6 +326,15 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name,
PFunction*func = new PFunction(func_name, lexical_scope, is_auto);
FILE_NAME(func, loc);
LexicalScope*scope = lexical_scope;
PScopeExtra*scopex = dynamic_cast<PScopeExtra*> (scope);
while (scope && !scopex) {
scope = scope->parent_scope();
scopex = dynamic_cast<PScopeExtra*> (scope);
}
assert(scopex);
if (pform_cur_generate) {
// Check if the function is already in the dictionary.
if (pform_cur_generate->funcs.find(func->pscope_name()) !=
@ -320,14 +348,13 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name,
pform_cur_generate->funcs[func->pscope_name()] = func;
} else {
// Check if the function is already in the dictionary.
if (pform_cur_module->funcs.find(func->pscope_name()) !=
pform_cur_module->funcs.end()) {
if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) {
cerr << func->get_fileline() << ": error: duplicate "
"definition for function '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
pform_cur_module->funcs[func->pscope_name()] = func;
scopex->funcs[func->pscope_name()] = func;
}
lexical_scope = func;
@ -385,7 +412,7 @@ static void pform_put_enum_type_in_scope(enum_type_t*enum_set)
lexical_scope->enum_sets.push_back(enum_set);
}
static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type)
PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
@ -401,6 +428,33 @@ static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_typ
return cur;
}
void pform_set_typedef(perm_string name, data_type_t*data_type)
{
data_type_t*&ref = lexical_scope->typedefs[name];
ivl_assert(*data_type, ref == 0);
ref = data_type;
}
data_type_t* pform_test_type_identifier(const char*txt)
{
// If there is no lexical_scope yet, then there is NO WAY the
// identifier can be a type_identifier.
if (lexical_scope == 0)
return 0;
perm_string name = lex_strings.make(txt);
map<perm_string,data_type_t*>::iterator cur;
LexicalScope*cur_scope = lexical_scope;
do {
cur = cur_scope->typedefs.find(name);
if (cur != cur_scope->typedefs.end())
return cur->second;
cur_scope = cur_scope->parent_scope();
} while (cur_scope);
return 0;
}
static void pform_put_behavior_in_scope(PProcess*pp)
{
lexical_scope->behaviors.push_back(pp);
@ -1464,7 +1518,7 @@ void pform_make_udp(perm_string name, bool synchronous_flag,
* and the name that I receive only has the tail component.
*/
static void pform_set_net_range(perm_string name,
const list<PExpr*>*range,
const list<pform_range_t>*range,
bool signed_flag,
ivl_variable_type_t dt,
PWSRType rt)
@ -1478,11 +1532,10 @@ static void pform_set_net_range(perm_string name,
if (range == 0) {
/* This is the special case that we really mean a
scalar. Set a fake range. */
cur->set_range(0, 0, rt, true);
cur->set_range_scalar(rt);
} else {
assert(range->size() == 2);
cur->set_range(range->front(), range->back(), rt, false);
cur->set_range(*range, rt);
}
cur->set_signed(signed_flag);
@ -1491,17 +1544,14 @@ static void pform_set_net_range(perm_string name,
}
void pform_set_net_range(list<perm_string>*names,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
ivl_variable_type_t dt,
PWSRType rt)
ivl_variable_type_t dt)
{
assert((range == 0) || (range->size() == 2));
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
perm_string txt = *cur;
pform_set_net_range(txt, range, signed_flag, dt, rt);
pform_set_net_range(txt, range, signed_flag, dt, SR_NET);
}
delete names;
@ -1565,8 +1615,8 @@ static void pform_makegate(PGBuiltin::Type type,
perm_string dev_name = lex_strings.make(info.name);
PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay);
if (info.range[0])
cur->set_range(info.range[0], info.range[1]);
if (info.range.first)
cur->set_range(info.range.first, info.range.second);
// The pform_makegates() that calls me will take care of
// deleting the attr pointer, so tell the
@ -1705,7 +1755,7 @@ void pform_make_modgates(perm_string type,
if (cur.parms_by_name) {
pform_make_modgate(type, cur_name, overrides,
cur.parms_by_name,
cur.range[0], cur.range[1],
cur.range.first, cur.range.second,
cur.file, cur.lineno);
} else if (cur.parms) {
@ -1719,14 +1769,14 @@ void pform_make_modgates(perm_string type,
}
pform_make_modgate(type, cur_name, overrides,
cur.parms,
cur.range[0], cur.range[1],
cur.range.first, cur.range.second,
cur.file, cur.lineno);
} else {
list<PExpr*>*wires = new list<PExpr*>;
pform_make_modgate(type, cur_name, overrides,
wires,
cur.range[0], cur.range[1],
cur.range.first, cur.range.second,
cur.file, cur.lineno);
}
}
@ -1799,8 +1849,8 @@ void pform_make_pgassign_list(list<PExpr*>*alist,
void pform_make_reginit(const struct vlltype&li,
perm_string name, PExpr*expr)
{
if (! pform_at_module_level()) {
VLerror(li, "variable declaration assignments are only "
if (! pform_at_module_level() && !gn_system_verilog()) {
VLerror(li, "error: variable declaration assignments are only "
"allowed at the module level.");
delete expr;
return;
@ -1839,7 +1889,7 @@ void pform_module_define_port(const struct vlltype&li,
NetNet::Type type,
ivl_variable_type_t data_type,
bool signed_flag,
list<PExpr*>*range,
list<pform_range_t>*range,
list<named_pexpr_t>*attr)
{
PWire*cur = pform_get_wire_in_scope(name);
@ -1862,17 +1912,10 @@ void pform_module_define_port(const struct vlltype&li,
cur->set_signed(signed_flag);
if (range == 0) {
cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT :
SR_BOTH,
true);
cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
} else {
assert(range->size() == 2);
assert(range->front());
assert(range->back());
cur->set_range(range->front(), range->back(),
(type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH,
false);
cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
}
pform_bind_attributes(cur->attributes, attr);
@ -1898,6 +1941,36 @@ void pform_module_define_port(const struct vlltype&li,
* function is called for every declaration.
*/
static PWire* pform_get_or_make_wire(const vlltype&li, perm_string name,
NetNet::Type type, NetNet::PortType ptype,
ivl_variable_type_t dtype)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur) {
// If this is not implicit ("implicit" meaning we don't
// know what the type is yet) then set the type now.
if (type != NetNet::IMPLICIT) {
bool rc = cur->set_wire_type(type);
if (rc == false) {
ostringstream msg;
msg << name << " " << type
<< " definition conflicts with " << cur->get_wire_type()
<< " definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
}
FILE_NAME(cur, li.text, li.first_line);
}
return cur;
}
cur = new PWire(name, type, ptype, dtype);
FILE_NAME(cur, li.text, li.first_line);
pform_put_wire_in_scope(name, cur);
return cur;
}
/*
* this is the basic form of pform_makewire. This takes a single simple
* name, port type, net type, data type, and attributes, and creates
@ -1909,33 +1982,13 @@ void pform_makewire(const vlltype&li, perm_string name,
ivl_variable_type_t dt,
list<named_pexpr_t>*attr)
{
PWire*cur = pform_get_wire_in_scope(name);
PWire*cur = pform_get_or_make_wire(li, name, type, pt, dt);
// If this is not implicit ("implicit" meaning we don't know
// what the type is yet) then set the type now.
if (cur && type != NetNet::IMPLICIT) {
bool rc = cur->set_wire_type(type);
if (rc == false) {
ostringstream msg;
msg << name << " " << type
<< " definition conflicts with " << cur->get_wire_type()
<< " definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
}
}
bool new_wire_flag = false;
if (! cur) {
new_wire_flag = true;
cur = new PWire(name, type, pt, dt);
FILE_NAME(cur, li.text, li.first_line);
}
if (type != NetNet::IMPLICIT)
FILE_NAME(cur, li.text, li.first_line);
bool flag;
switch (dt) {
case IVL_VT_REAL:
@ -1947,7 +2000,7 @@ void pform_makewire(const vlltype&li, perm_string name,
<< " to " << dt << "." << endl;
}
ivl_assert(*cur, flag);
cur->set_range(0, 0, SR_NET, true);
cur->set_range_scalar(SR_NET);
cur->set_signed(true);
break;
default:
@ -1960,9 +2013,6 @@ void pform_makewire(const vlltype&li, perm_string name,
cur->attributes[attr_cur->name] = attr_cur->parm;
}
}
if (new_wire_flag)
pform_put_wire_in_scope(name, cur);
}
/*
@ -1971,7 +2021,7 @@ void pform_makewire(const vlltype&li, perm_string name,
* pform_makewire above.
*/
void pform_makewire(const vlltype&li,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
list<perm_string>*names,
NetNet::Type type,
@ -1998,7 +2048,7 @@ void pform_makewire(const vlltype&li,
* This form makes nets with delays and continuous assignments.
*/
void pform_makewire(const vlltype&li,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
list<PExpr*>*delay,
str_pair_t str,
@ -2033,39 +2083,6 @@ void pform_makewire(const vlltype&li,
}
}
void pform_set_port_type(perm_string name, NetNet::PortType pt,
const char*file, unsigned lineno)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
FILE_NAME(cur, file, lineno);
pform_put_wire_in_scope(name, cur);
}
switch (cur->get_port_type()) {
case NetNet::PIMPLICIT:
if (! cur->set_port_type(pt))
VLerror("error setting port direction.");
break;
case NetNet::NOT_A_PORT:
cerr << file << ":" << lineno << ": error: "
<< "port " << name << " is not in the port list."
<< endl;
error_count += 1;
break;
default:
cerr << file << ":" << lineno << ": error: "
<< "port " << name << " already has a port declaration."
<< endl;
error_count += 1;
break;
}
}
/*
* This function is called by the parser to create task ports. The
* resulting wire (which should be a register) is put into a list to
@ -2105,15 +2122,15 @@ void pform_set_port_type(perm_string name, NetNet::PortType pt,
* constraints as those of tasks, so this works fine. Functions have
* no output or inout ports.
*/
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t vtype,
bool signed_flag,
list<PExpr*>*range,
list<pform_range_t>*range,
list<perm_string>*names,
const char* file,
unsigned lineno,
bool isint)
{
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(names);
svector<PWire*>*res = new svector<PWire*>(0);
for (list<perm_string>::iterator cur = names->begin()
@ -2128,7 +2145,7 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
FILE_NAME(curw, file, lineno);
FILE_NAME(curw, loc);
pform_put_wire_in_scope(name, curw);
}
@ -2137,8 +2154,7 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
/* If there is a range involved, it needs to be set. */
if (range) {
assert(range->size() == 2);
curw->set_range(range->front(), range->back(), SR_PORT, false);
curw->set_range(*range, SR_PORT);
}
svector<PWire*>*tmp = new svector<PWire*>(*res, curw);
@ -2152,6 +2168,71 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
return res;
}
svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
data_type_t*vtype,
list<perm_string>*names)
{
if (atom2_type_t*atype = dynamic_cast<atom2_type_t*> (vtype)) {
list<pform_range_t>*range_tmp = make_range_from_width(atype->type_code);
return pform_make_task_ports(loc, pt, IVL_VT_BOOL,
atype->signed_flag,
range_tmp, names);
}
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
return pform_make_task_ports(loc, pt, vec_type->base_type,
vec_type->signed_flag,
copy_range(vec_type->pdims.get()),
names);
}
if (/*real_type_t*real_type = */ dynamic_cast<real_type_t*> (vtype)) {
return pform_make_task_ports(loc, pt, IVL_VT_REAL,
true, 0, names);
}
VLerror(loc, "sorry: Given type not supported here.");
return 0;
}
/*
* The parser calls this in the rule that matches increment/decrement
* statements. The rule that does the matching creates a PEUnary with
* all the information we need, but here we convert that expression to
* a compressed assignment statement.
*/
PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp)
{
PEUnary*expu = dynamic_cast<PEUnary*> (exp);
ivl_assert(*exp, expu != 0);
char use_op = 0;
switch (expu->get_op()) {
case 'i':
case 'I':
use_op = '+';
break;
case 'd':
case 'D':
use_op = '-';
break;
default:
ivl_assert(*exp, 0);
break;
}
PExpr*lval = expu->get_expr();
PExpr*rval = new PENumber(new verinum((uint64_t)1, 1));
FILE_NAME(rval, loc);
PAssign*tmp = new PAssign(lval, use_op, rval);
FILE_NAME(tmp, loc);
delete exp;
return tmp;
}
void pform_set_attrib(perm_string name, perm_string key, char*value)
{
if (PWire*cur = lexical_scope->wires_find(name)) {
@ -2220,7 +2301,7 @@ LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag,
void pform_set_parameter(const struct vlltype&loc,
perm_string name, ivl_variable_type_t type,
bool signed_flag, list<PExpr*>*range, PExpr*expr,
bool signed_flag, list<pform_range_t>*range, PExpr*expr,
LexicalScope::range_t*value_range)
{
LexicalScope*scope = lexical_scope;
@ -2255,11 +2336,12 @@ void pform_set_parameter(const struct vlltype&loc,
parm.type = type;
if (range) {
assert(range->size() == 2);
assert(range->front());
assert(range->back());
parm.msb = range->front();
parm.lsb = range->back();
assert(range->size() == 1);
pform_range_t&rng = range->front();
assert(rng.first);
assert(rng.second);
parm.msb = rng.first;
parm.lsb = rng.second;
} else {
parm.msb = 0;
parm.lsb = 0;
@ -2273,7 +2355,7 @@ void pform_set_parameter(const struct vlltype&loc,
void pform_set_localparam(const struct vlltype&loc,
perm_string name, ivl_variable_type_t type,
bool signed_flag, list<PExpr*>*range, PExpr*expr)
bool signed_flag, list<pform_range_t>*range, PExpr*expr)
{
LexicalScope*scope = lexical_scope;
@ -2303,11 +2385,12 @@ void pform_set_localparam(const struct vlltype&loc,
parm.type = type;
if (range) {
assert(range->size() == 2);
assert(range->front());
assert(range->back());
parm.msb = range->front();
parm.lsb = range->back();
assert(range->size() == 1);
pform_range_t&rng = range->front();
assert(rng.first);
assert(rng.second);
parm.msb = rng.first;
parm.lsb = rng.second;
} else {
parm.msb = 0;
parm.lsb = 0;
@ -2404,12 +2487,48 @@ extern void pform_module_specify_path(PSpecPath*obj)
pform_cur_module->specify_paths.push_back(obj);
}
static void pform_set_port_type(perm_string name, NetNet::PortType pt,
const char*file, unsigned lineno)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
FILE_NAME(cur, file, lineno);
pform_put_wire_in_scope(name, cur);
}
switch (cur->get_port_type()) {
case NetNet::PIMPLICIT:
if (! cur->set_port_type(pt))
VLerror("error setting port direction.");
break;
case NetNet::NOT_A_PORT:
cerr << file << ":" << lineno << ": error: "
<< "port " << name << " is not in the port list."
<< endl;
error_count += 1;
break;
default:
cerr << file << ":" << lineno << ": error: "
<< "port " << name << " already has a port declaration."
<< endl;
error_count += 1;
break;
}
}
void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
NetNet::PortType pt)
{
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
perm_string txt = *cur;
@ -2427,9 +2546,12 @@ static void pform_set_reg_integer(perm_string name)
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
assert(cur);
cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)),
new PENumber(new verinum((uint64_t)0, integer_width)),
SR_NET, false);
pform_range_t rng;
rng.first = new PENumber(new verinum(integer_width-1, integer_width));
rng.second = new PENumber(new verinum((uint64_t)0, integer_width));
list<pform_range_t>rlist;
rlist.push_back(rng);
cur->set_range(rlist, SR_NET);
cur->set_signed(true);
}
@ -2448,9 +2570,12 @@ static void pform_set_reg_time(perm_string name)
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
assert(cur);
cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)),
new PENumber(new verinum((uint64_t)0, integer_width)),
SR_NET, false);
pform_range_t rng;
rng.first = new PENumber(new verinum(TIME_WIDTH-1, integer_width));
rng.second = new PENumber(new verinum((uint64_t)0, integer_width));
list<pform_range_t>rlist;
rlist.push_back(rng);
cur->set_range(rlist, SR_NET);
}
void pform_set_reg_time(list<perm_string>*names)
@ -2469,9 +2594,13 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin
assert(cur);
cur->set_signed(signed_flag);
cur->set_range(new PENumber(new verinum(width-1, integer_width)),
new PENumber(new verinum((uint64_t)0, integer_width)),
SR_NET, false);
pform_range_t rng;
rng.first = new PENumber(new verinum(width-1, integer_width));
rng.second = new PENumber(new verinum((uint64_t)0, integer_width));
list<pform_range_t>rlist;
rlist.push_back(rng);
cur->set_range(rlist, SR_NET);
}
void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>*names)
@ -2484,6 +2613,47 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>
delete names;
}
/*
* This function detects the derived class for the given type and
* dispatches the type to the proper subtype function.
*/
void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<perm_string>*names)
{
if (atom2_type_t*atom2_type = dynamic_cast<atom2_type_t*> (data_type)) {
pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names);
return;
}
if (struct_type_t*struct_type = dynamic_cast<struct_type_t*> (data_type)) {
pform_set_struct_type(struct_type, names);
return;
}
if (enum_type_t*enum_type = dynamic_cast<enum_type_t*> (data_type)) {
pform_set_enum(li, enum_type, names);
return;
}
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type)) {
pform_set_net_range(names, vec_type->pdims.get(),
vec_type->signed_flag,
vec_type->base_type);
return;
}
if (/*real_type_t*real_type =*/ dynamic_cast<real_type_t*> (data_type)) {
pform_set_net_range(names, 0, true, IVL_VT_REAL);
return;
}
if (/*class_type_t*class_type =*/ dynamic_cast<class_type_t*> (data_type)) {
VLerror(li, "sorry: Class types not supported.");
return;
}
assert(0);
}
static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
perm_string name)
{
@ -2494,8 +2664,8 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
cur->set_signed(enum_type->signed_flag);
assert(enum_type->range.get() != 0);
assert(enum_type->range->size() == 2);
cur->set_range(enum_type->range->front(), enum_type->range->back(), SR_NET, false);
assert(enum_type->range->size() == 1);
cur->set_range(*enum_type->range, SR_NET);
cur->set_enumeration(enum_type);
}
@ -2506,7 +2676,7 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_st
assert(enum_type->base_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL);
assert(enum_type->range.get() != 0);
assert(enum_type->range->size() == 2);
assert(enum_type->range->size() == 1);
// Add the file and line information to the enumeration type.
FILE_NAME(&(enum_type->li), li);

78
pform.h
View File

@ -1,7 +1,7 @@
#ifndef __pform_H
#define __pform_H
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -58,6 +58,7 @@
class PGate;
class PExpr;
class PSpecPath;
class PClass;
struct vlltype;
/*
@ -101,22 +102,23 @@ struct net_decl_assign_t {
/* The lgate is gate instantiation information. */
struct lgate {
lgate(int =0)
inline lgate(int =0)
: parms(0), parms_by_name(0), file(NULL), lineno(0)
{ range[0] = 0;
range[1] = 0;
}
{ }
string name;
list<PExpr*>*parms;
list<named_pexpr_t>*parms_by_name;
PExpr*range[2];
pform_range_t range;
const char* file;
unsigned lineno;
};
extern std::list<pform_range_t>* make_range_from_width(uint64_t wid);
extern std::list<pform_range_t>* copy_range(std::list<pform_range_t>* orig);
/* Use this function to transform the parted form of the attribute
list to the attribute map that is used later. */
extern void pform_bind_attributes(map<perm_string,PExpr*>&attributes,
@ -135,6 +137,8 @@ extern void pform_set_default_nettype(NetNet::Type net,
*/
extern PWire* pform_get_wire_in_scope(perm_string name);
extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type);
/*
* The parser uses startmodule and endmodule together to build up a
* module as it parses it. The startmodule tells the pform code that a
@ -156,7 +160,7 @@ extern void pform_module_define_port(const struct vlltype&li,
NetNet::Type type,
ivl_variable_type_t data_type,
bool signed_flag,
list<PExpr*>*range,
list<pform_range_t>*range,
list<named_pexpr_t>*attr);
extern Module::port_t* pform_module_port_reference(perm_string name,
@ -165,6 +169,10 @@ extern Module::port_t* pform_module_port_reference(perm_string name,
extern void pform_endmodule(const char*, bool inside_celldefine,
Module::UCDriveType uc_drive_def);
extern void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type);
extern void pform_end_class_declaration(void);
extern void pform_make_udp(perm_string name, list<perm_string>*parms,
svector<PWire*>*decl, list<string>*table,
Statement*init,
@ -184,6 +192,7 @@ extern void pform_make_udp(perm_string name,
*/
extern void pform_pop_scope();
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name);
extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name,
bool is_auto);
extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name,
@ -222,6 +231,8 @@ extern void pform_endgenerate();
*/
extern PGenerate* pform_parent_generate(void);
extern void pform_set_typedef(perm_string name, data_type_t*data_type);
/*
* The makewire functions announce to the pform code new wires. These
* go into a module that is currently opened.
@ -234,7 +245,7 @@ extern void pform_makewire(const struct vlltype&li, perm_string name,
/* This form handles simple declarations */
extern void pform_makewire(const struct vlltype&li,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
list<perm_string>*names,
NetNet::Type type,
@ -243,9 +254,15 @@ extern void pform_makewire(const struct vlltype&li,
list<named_pexpr_t>*attr,
PWSRType rt = SR_NET);
extern void pform_makewire(const struct vlltype&li,
struct_type_t*struct_type,
list<perm_string>*names,
NetNet::PortType,
list<named_pexpr_t>*attr);
/* This form handles assignment declarations. */
extern void pform_makewire(const struct vlltype&li,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
list<PExpr*>*delay,
str_pair_t str,
@ -253,6 +270,13 @@ extern void pform_makewire(const struct vlltype&li,
NetNet::Type type,
ivl_variable_type_t);
/* This form handles nets declared as structures. (See pform_struct_type.cc) */
extern void pform_makewire(const struct vlltype&li,
struct_type_t*struct_type,
NetNet::PortType,
list<perm_string>*names,
list<named_pexpr_t>*attr);
extern void pform_make_reginit(const struct vlltype&li,
perm_string name, PExpr*expr);
@ -261,25 +285,26 @@ extern void pform_make_reginit(const struct vlltype&li,
it. The second form takes a single name. */
extern void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names,
list<PExpr*>*range,
list<pform_range_t>*range,
bool signed_flag,
NetNet::PortType);
extern void pform_set_port_type(perm_string nm, NetNet::PortType pt,
const char*file, unsigned lineno);
extern void pform_set_net_range(list<perm_string>*names,
list<PExpr*>*,
list<pform_range_t>*,
bool signed_flag,
ivl_variable_type_t,
PWSRType rt = SR_NET);
ivl_variable_type_t);
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_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>*names);
extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list<perm_string>*names);
extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_string>*names);
extern void pform_set_struct_type(struct_type_t*struct_type, list<perm_string>*names);
/* pform_set_attrib and pform_set_type_attrib exist to support the
$attribute syntax, which can only set string values to
attributes. The functions keep the value strings that are
@ -297,13 +322,13 @@ extern void pform_set_parameter(const struct vlltype&loc,
perm_string name,
ivl_variable_type_t type,
bool signed_flag,
list<PExpr*>*range,
list<pform_range_t>*range,
PExpr*expr, LexicalScope::range_t*value_range);
extern void pform_set_localparam(const struct vlltype&loc,
perm_string name,
ivl_variable_type_t type,
bool signed_flag,
list<PExpr*>*range,
list<pform_range_t>*range,
PExpr*expr);
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
@ -363,15 +388,26 @@ extern void pform_make_pgassign_list(list<PExpr*>*alist,
/* Given a port type and a list of names, make a list of wires that
can be used as task port information. */
extern svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
extern svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t vtype,
bool signed_flag,
list<PExpr*>*range,
list<pform_range_t>*range,
list<perm_string>*names,
const char* file,
unsigned lineno,
bool isint = false);
extern svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
data_type_t*vtype,
list<perm_string>*names);
/*
* The parser uses this function to convert a unary
* increment/decrement expression to the equivalent compressed
* assignment statement.
*/
extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc,
PExpr*exp);
/*
* These are functions that the outside-the-parser code uses the do

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2012 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
@ -141,6 +141,11 @@ std::ostream& operator << (std::ostream&out, ivl_dis_domain_t dom)
return out;
}
void data_type_t::pform_dump(ostream&out, unsigned indent) const
{
out << setw(indent) << "" << typeid(*this).name() << endl;
}
static void dump_attributes_map(ostream&out,
const map<perm_string,PExpr*>&attributes,
int ind)
@ -331,6 +336,9 @@ void PWire::dump(ostream&out, unsigned ind) const
case NetNet::PINOUT:
out << " inout";
break;
case NetNet::PREF:
out << " ref";
break;
case NetNet::NOT_A_PORT:
break;
}
@ -346,17 +354,23 @@ void PWire::dump(ostream&out, unsigned ind) const
}
if (port_set_) {
if (port_msb_ == 0) {
if (port_.empty()) {
out << " port<scalar>";
} else {
out << " port[" << *port_msb_ << ":" << *port_lsb_ << "]";
out << " port";
for (list<pform_range_t>::const_iterator cur = port_.begin()
; cur != port_.end() ; ++cur)
out << "[" << *cur->first << ":" << *cur->second << "]";
}
}
if (net_set_) {
if (net_msb_ == 0) {
if (net_.empty()) {
out << " net<scalar>";
} else {
out << " net[" << *net_msb_ << ":" << *net_lsb_ << "]";
out << " net";
for (list<pform_range_t>::const_iterator cur = net_.begin()
; cur != net_.end() ; ++cur)
out << "[" << *cur->first << ":" << *cur->second << "]";
}
}
@ -563,7 +577,10 @@ void PAssign::dump(ostream&out, unsigned ind) const
if (delay_) out << "#" << *delay_ << " ";
if (count_) out << "repeat(" << *count_ << ") ";
if (event_) out << *event_ << " ";
out << *rval() << ";" << " /* " << get_fileline() << " */" << endl;
PExpr*rexpr = rval();
if (rexpr) out << *rval() << ";";
else out << "<no rval>;";
out << " /* " << get_fileline() << " */" << endl;
}
void PAssignNB::dump(ostream&out, unsigned ind) const
@ -763,8 +780,8 @@ void PForever::dump(ostream&out, unsigned ind) const
void PForStatement::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_
<< "; " << *cond_ << "; " << *name2_ << " = " << *expr2_ <<
")" << endl;
<< "; " << *cond_ << "; <for_step>)" << endl;
step_->dump(out, ind+6);
statement_->dump(out, ind+3);
}
@ -798,7 +815,13 @@ void PFunction::dump(ostream&out, unsigned ind) const
out << "int unsigned ";
break;
case PTF_ATOM2_S:
cout << "int signed ";
out << "int signed ";
break;
case PTF_STRING:
out << "string ";
break;
case PTF_VOID:
out << "void ";
break;
}
@ -849,6 +872,10 @@ void PTask::dump(ostream&out, unsigned ind) const
out << pscope_name() << ";" << endl;
if (ports_)
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
if ((*ports_)[idx] == 0) {
out << setw(ind) << "" << "ERROR PORT" << endl;
continue;
}
out << setw(ind) << "";
switch ((*ports_)[idx]->get_port_type()) {
case NetNet::PINPUT:
@ -860,6 +887,12 @@ void PTask::dump(ostream&out, unsigned ind) const
case NetNet::PINOUT:
out << "inout ";
break;
case NetNet::PIMPLICIT:
out << "PIMPLICIT";
break;
case NetNet::NOT_A_PORT:
out << "NOT_A_PORT";
break;
default:
assert(0);
break;
@ -1050,6 +1083,15 @@ void PGenerate::dump(ostream&out, unsigned indent) const
}
}
void LexicalScope::dump_typedefs_(ostream&out, unsigned indent) const
{
typedef map<perm_string,data_type_t*>::const_iterator iter_t;
for (iter_t cur = typedefs.begin() ; cur != typedefs.end() ; ++ cur) {
out << setw(indent) << "" << "typedef of " << cur->first << ":" << endl;
cur->second->pform_dump(out, indent+4);
}
}
void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const
{
typedef map<perm_string,param_expr_t>::const_iterator parm_iter_t;
@ -1189,6 +1231,8 @@ void Module::dump(ostream&out) const
out << ")" << endl;
}
dump_typedefs_(out, 4);
dump_parameters_(out, 4);
dump_localparams_(out, 4);

37
pform_pclass.cc Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2012 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 "pform.h"
# include "PClass.h"
static PClass*pform_cur_class = 0;
void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type)
{
PClass*class_scope = pform_push_class_scope(loc, type->name);
assert(pform_cur_class == 0);
pform_cur_class = class_scope;
}
void pform_end_class_declaration(void)
{
assert(pform_cur_class);
pform_cur_class = 0;
pform_pop_scope();
}

104
pform_struct_type.cc Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2011-2012 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 "pform.h"
# include "parse_misc.h"
# include "ivl_assert.h"
static ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type)
{
ivl_variable_type_t base_type = IVL_VT_BOOL;
for (list<struct_member_t*>::iterator cur = struct_type->members->begin()
; cur != struct_type->members->end() ; ++ cur) {
struct_member_t*tmp = *cur;
if (tmp->type == IVL_VT_BOOL) {
continue;
}
if (tmp->type == IVL_VT_LOGIC) {
base_type = IVL_VT_LOGIC;
continue;
}
}
return base_type;
}
/*
* When we parse a packed struct, we can early on (right here) figure
* out the base type of the packed variable. Elaboration, later on,
* well figure out the rest.
*/
static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name)
{
ivl_variable_type_t base_type = figure_struct_base_type(struct_type);
PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type);
net->set_struct_type(struct_type);
}
static void pform_set_struct_type(struct_type_t*struct_type, perm_string name)
{
if (struct_type->packed_flag) {
pform_set_packed_struct(struct_type, name);
return;
}
// For now, can only handle packed structs.
ivl_assert(*struct_type, 0);
}
void pform_set_struct_type(struct_type_t*struct_type, list<perm_string>*names)
{
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) {
pform_set_struct_type(struct_type, *cur);
}
}
static void pform_makewire(const struct vlltype&li,
struct_type_t*struct_type,
NetNet::PortType ptype,
perm_string name,
list<named_pexpr_t>*)
{
ivl_variable_type_t base_type = figure_struct_base_type(struct_type);
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type);
FILE_NAME(cur, li);
cur->set_struct_type(struct_type);
}
void pform_makewire(const struct vlltype&li,
struct_type_t*struct_type,
NetNet::PortType ptype,
list<perm_string>*names,
list<named_pexpr_t>*attr)
{
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
perm_string txt = *cur;
pform_makewire(li, struct_type, ptype, txt, attr);
}
delete names;
}

View File

@ -19,3 +19,7 @@
# include "pform_types.h"
data_type_t::~data_type_t()
{
}

View File

@ -1,7 +1,7 @@
#ifndef __pform_types_H
#define __pform_types_H
/*
* Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-2012 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
@ -37,6 +37,7 @@
class PExpr;
typedef named<verinum> named_number_t;
typedef named<PExpr*> named_pexpr_t;
typedef std::pair<PExpr*,PExpr*> pform_range_t;
struct index_component_t {
enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO };
@ -57,20 +58,76 @@ struct name_component_t {
std::list<index_component_t>index;
};
struct decl_assignment_t {
perm_string name;
std::list<pform_range_t>index;
std::auto_ptr<PExpr> expr;
};
/*
* This is the base class for data types that are matched by the
* "data_type" rule in the parse rule. We make the type virtual so
* that dynamic types will work.
*/
struct data_type_t : public LineInfo {
virtual ~data_type_t() = 0;
// This method is used by the pform dumper to diagnostic dump.
virtual void pform_dump(std::ostream&out, unsigned indent) const;
};
/*
* The enum_type_t holds the parsed declaration to represent an
* enumeration. Since this is in the pform, it represents the type
* before elaboration to the range, for example, man not be complete
* until it is elaborated in a scope.
*/
struct enum_type_t {
struct enum_type_t : public data_type_t {
ivl_variable_type_t base_type;
bool signed_flag;
std::auto_ptr< list<PExpr*> > range;
std::auto_ptr< list<pform_range_t> > range;
std::auto_ptr< list<named_pexpr_t> > names;
LineInfo li;
};
struct struct_member_t : public LineInfo {
ivl_variable_type_t type;
std::auto_ptr< list<pform_range_t> > range;
std::auto_ptr< list<decl_assignment_t*> > names;
};
struct struct_type_t : public data_type_t {
bool packed_flag;
std::auto_ptr< list<struct_member_t*> > members;
};
struct atom2_type_t : public data_type_t {
inline explicit atom2_type_t(int tc, bool flag)
: type_code(tc), signed_flag(flag) { }
int type_code;
bool signed_flag;
};
struct vector_type_t : public data_type_t {
inline explicit vector_type_t(ivl_variable_type_t bt, bool sf,
std::list<pform_range_t>*pd)
: base_type(bt), signed_flag(sf), pdims(pd) { }
ivl_variable_type_t base_type;
bool signed_flag;
std::auto_ptr< list<pform_range_t> > pdims;
};
struct real_type_t : public data_type_t {
inline explicit real_type_t(int tc) : type_code(tc) { }
int type_code;
};
struct class_type_t : public data_type_t {
inline explicit class_type_t(perm_string n)
: name(n) { }
perm_string name;
};
/*
* The pform_name_t is the general form for a hierarchical

View File

@ -20,6 +20,7 @@ debug:elaborate
debug:elab_pexpr
debug:scopes
debug:synth2
debug:optimizer
out:a.out
ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp
sys_func:scripts/devel-stub.sft

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -114,12 +114,12 @@ class synth_f : public functor_t {
public:
synth_f() { top_ = NULL; }
void process(class Design*, class NetProcTop*);
void process(Design*, NetProcTop*);
private:
void proc_always_(class Design*);
void proc_initial_(class Design*);
void proc_final_(class Design*);
void proc_always_(Design*);
void proc_initial_(Design*);
void proc_final_(Design*);
NetProcTop*top_;
};
@ -129,7 +129,7 @@ class synth_f : public functor_t {
* Look at a process, and divide the problem into always and initial
* threads.
*/
void synth_f::process(class Design*des, class NetProcTop*top)
void synth_f::process(Design*des, NetProcTop*top)
{
top_ = top;
switch (top->type()) {
@ -145,19 +145,19 @@ void synth_f::process(class Design*des, class NetProcTop*top)
}
}
void synth_f::proc_always_(class Design*des)
void synth_f::proc_always_(Design*des)
{
do_expr expr_pat(des, top_->scope());
top_->statement()->match_proc(&expr_pat);
}
void synth_f::proc_initial_(class Design*des)
void synth_f::proc_initial_(Design*des)
{
do_expr expr_pat(des, top_->scope());
top_->statement()->match_proc(&expr_pat);
}
void synth_f::proc_final_(class Design*des)
void synth_f::proc_final_(Design*des)
{
do_expr expr_pat(des, top_->scope());
top_->statement()->match_proc(&expr_pat);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2012 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
@ -900,7 +900,7 @@ bool NetProcTop::synth_sync(Design*des)
class synth2_f : public functor_t {
public:
void process(class Design*, class NetProcTop*);
void process(Design*, NetProcTop*);
private:
};
@ -910,7 +910,7 @@ class synth2_f : public functor_t {
* Look at a process. If it is asynchronous, then synthesize it as an
* asynchronous process and delete the process itself for its gates.
*/
void synth2_f::process(class Design*des, class NetProcTop*top)
void synth2_f::process(Design*des, NetProcTop*top)
{
if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0)
return;

View File

@ -2147,15 +2147,39 @@ extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word)
}
}
extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net)
{
return net->packed_dims.size();
}
extern "C" int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim)
{
assert(dim < net->packed_dims.size());
return net->packed_dims[dim].msb;
}
extern "C" int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim)
{
assert(dim < net->packed_dims.size());
return net->packed_dims[dim].lsb;
}
extern "C" int ivl_signal_msb(ivl_signal_t net)
{
assert(net->lsb_dist == 1 || net->lsb_dist == -1);
return net->lsb_index + net->lsb_dist * (net->width_ - 1);
if (net->packed_dims.size() == 0)
return 0;
assert(net->packed_dims.size() == 1);
return net->packed_dims[0].msb;
}
extern "C" int ivl_signal_lsb(ivl_signal_t net)
{
return net->lsb_index;
if (net->packed_dims.size() == 0)
return 0;
assert(net->packed_dims.size() == 1);
return net->packed_dims[0].lsb;
}
extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2012 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
@ -963,7 +963,7 @@ bool dll_target::tran(const NetTran*net)
{
struct ivl_switch_s*obj = new struct ivl_switch_s;
obj->type = net->type();
obj->width = 0;
obj->width = net->vector_width();
obj->part = 0;
obj->offset = 0;
obj->name = net->name();
@ -996,7 +996,6 @@ bool dll_target::tran(const NetTran*net)
}
if (obj->type == IVL_SW_TRAN_VP) {
obj->width = net->vector_width();
obj->part = net->part_width();
obj->offset= net->part_offset();
}
@ -2400,10 +2399,17 @@ void dll_target::signal(const NetNet*net)
/* Save the primitive properties of the signal in the
ivl_signal_t object. */
{ size_t idx = 0;
list<NetNet::range_t>::const_iterator cur;
obj->packed_dims.resize(net->packed_dims().size());
for (cur = net->packed_dims().begin(), idx = 0
; cur != net->packed_dims().end() ; ++cur, idx += 1) {
obj->packed_dims[idx] = *cur;
}
}
obj->width_ = net->vector_width();
obj->signed_= net->get_signed()? 1 : 0;
obj->lsb_index = net->lsb();
obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1;
obj->isint_ = false;
obj->local_ = net->local_flag()? 1 : 0;
obj->forced_net_ = (net->type() != NetNet::REG) &&
@ -2504,7 +2510,7 @@ void dll_target::signal(const NetNet*net)
obj->array_words = net->array_count();
obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0;
assert(obj->array_words == net->pin_count());
ivl_assert(*net, obj->array_words == net->pin_count());
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
"t-dll creating nexus array " << obj->array_words << " long" << endl;
if (obj->array_words > 1 && net->pins_are_virtual()) {

View File

@ -688,10 +688,9 @@ struct ivl_signal_s {
unsigned array_dimensions_ : 1;
unsigned array_addr_swapped : 1;
/* These encode the run-time index for the least significant
bit, and the distance to the second bit. */
signed lsb_index;
signed lsb_dist;
/* These encode the declared packed dimensions for the
signal, in case they are needed by the run-time */
std::vector<NetNet::range_t> packed_dims;
perm_string name_;
ivl_scope_t scope_;

View File

@ -65,7 +65,7 @@ cppcheck: $(O:.o=.c)
cppcheck --enable=all -f $(INCLUDE_PATH) $^
Makefile: $(srcdir)/Makefile.in ../config.status
cd ..; ./config.status --file=tgt-fpga$@
cd ..; ./config.status --file=tgt-fpga/$@
dep:
mkdir dep
@ -83,7 +83,7 @@ else
endif
fpga.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man
man -t $(srcdir)/iverilog-fpga.man > iverilog-fpga.ps

View File

@ -78,7 +78,7 @@ else
endif
null.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
install: all installdirs $(libdir)/ivl$(suffix)/null.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/null.conf $(libdir)/ivl$(suffix)/null-s.conf

View File

@ -77,7 +77,7 @@ else
endif
pal.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS) $(LDFLAGS) -lipal
$(CC) @shared@ $(LDFLAGS)-o $@ $O $(TGTLDFLAGS) $(LDFLAGS) -lipal
install: all installdirs $(libdir)/ivl/pal.tgt

View File

@ -58,8 +58,9 @@ clean:
distclean: clean
rm -f Makefile config.log
rm -f stamp-pcb_config-h pcb_config.h
cppcheck: $(O:.o=.c)
cppcheck: $(O:.o=.cc)
cppcheck --enable=all -f $(INCLUDE_PATH) $^
Makefile: $(srcdir)/Makefile.in ../config.status
@ -68,9 +69,10 @@ Makefile: $(srcdir)/Makefile.in ../config.status
dep:
mkdir dep
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
mv $*.d dep
stamp-pcb_config-h: $(srcdir)/pcb_config.h.in ../config.status
@rm -f $@
cd ..; ./config.status --header=tgt-pcb/pcb_config.h
pcb_config.h: stamp-pcb_config-h
%.o: %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
@ -92,7 +94,7 @@ else
endif
pcb.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CXX) @shared@ -o $@ $O $(TGTLDFLAGS)
install: all installdirs $(libdir)/ivl$(suffix)/pcb.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/pcb.conf $(libdir)/ivl$(suffix)/pcb-s.conf

View File

@ -24,7 +24,9 @@
# include "version_base.h"
# include "version_tag.h"
# include "pcb_config.h"
# include <string.h>
# include <cassert>
# include <cstdio>
# include <cstring>
# include "pcb_priv.h"
# include "ivl_target.h"

View File

@ -23,7 +23,7 @@
# include <set>
# include <list>
# include <map>
# include <ivl_target.h>
# include "ivl_target.h"
extern int scan_scope(ivl_scope_t scope);

View File

@ -21,6 +21,7 @@
# include <map>
# include <string>
# include <cassert>
# include <cstdio>
using namespace std;
@ -85,7 +86,7 @@ int scan_scope(ivl_scope_t scope)
return 0;
}
static int child_scan_fun(ivl_scope_t scope, void*)
extern "C" int child_scan_fun(ivl_scope_t scope, void*)
{
int rc = scan_scope(scope);
return 0;

View File

@ -18,6 +18,7 @@
*/
# include "pcb_priv.h"
# include <cassert>
# include <cstdio>
using namespace std;

View File

@ -19,6 +19,8 @@
# include "pcb_config.h"
# include "pcb_priv.h"
# include <cassert>
# include <cstdio>
using namespace std;

View File

@ -79,7 +79,7 @@ else
endif
stub.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
install: all installdirs $(libdir)/ivl$(suffix)/stub.tgt \
$(libdir)/ivl$(suffix)/stub.conf $(libdir)/ivl$(suffix)/stub-s.conf

View File

@ -1288,11 +1288,14 @@ static void show_signal(ivl_signal_t net)
for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) {
ivl_nexus_t nex = ivl_signal_nex(net, idx);
unsigned dim;
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] "
"<width=%u%s> <discipline=%s> ",
type, sign, port, data_type,
ivl_signal_msb(net), ivl_signal_lsb(net),
fprintf(out, " %s %s %s%s", type, sign, port, data_type);
for (dim = 0 ; dim < ivl_signal_packed_dimensions(net) ; dim += 1) {
fprintf(out, "[%d:%d]", ivl_signal_packed_msb(net,dim),
ivl_signal_packed_lsb(net,dim));
}
fprintf(out, " %s[word=%u, adr=%d] <width=%u%s> <discipline=%s> ",
ivl_signal_basename(net),
idx, ivl_signal_array_base(net)+idx,
ivl_signal_width(net),

View File

@ -77,7 +77,7 @@ else
endif
verilog.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
install: all installdirs $(libdir)/ivl/verilog.tgt \
$(includedir)/vpi_user.h

View File

@ -82,7 +82,7 @@ else
endif
vhdl.tgt: $O $(TGTDEPLIBS)
$(CXX) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CXX) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
stamp-vhdl_config-h: $(srcdir)/vhdl_config.h.in ../config.status
@rm -f $@

View File

@ -1,7 +1,7 @@
/*
* Generate code to convert between VHDL types.
*
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
* Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -219,6 +219,7 @@ vhdl_expr *vhdl_expr::to_std_ulogic()
}
else
assert(false);
return NULL;
}
/*

View File

@ -1,7 +1,7 @@
/*
* Helper functions for VHDL syntax elements.
*
* Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk)
* Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -64,6 +64,7 @@ static inline char vl_to_vhdl_bit(char bit)
return '-';
}
assert(false);
return 0;
}
#endif

View File

@ -78,7 +78,7 @@ else
endif
vlog95.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
install: all installdirs $(libdir)/ivl$(suffix)/vlog95.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/vlog95.conf $(libdir)/ivl$(suffix)/vlog95-s.conf

View File

@ -36,7 +36,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt)
for (idx = 0; idx < count; idx += 1) {
if (first) first = 0;
else fprintf(vlog_out, " or ");
emit_name_of_nexus(scope, ivl_event_any(event, idx));
emit_nexus_as_ca(scope, ivl_event_any(event, idx), 0);
}
/* Check for positive edge events. */
@ -46,7 +46,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt)
if (first) first = 0;
else fprintf(vlog_out, " or ");
fprintf(vlog_out, "posedge ");
emit_name_of_nexus(scope, ivl_event_pos(event, idx));
emit_nexus_as_ca(scope, ivl_event_pos(event, idx), 0);
}
/* Check for negative edge events. */
@ -56,7 +56,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt)
if (first) first = 0;
else fprintf(vlog_out, " or ");
fprintf(vlog_out, "negedge ");
emit_name_of_nexus(scope, ivl_event_neg(event, idx));
emit_nexus_as_ca(scope, ivl_event_neg(event, idx), 0);
}
/* We have a named event if there were no edge events. */

View File

@ -79,7 +79,7 @@ static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
char *oper = "<invalid>";
switch(ivl_expr_opcode(expr)) {
switch (ivl_expr_opcode(expr)) {
case '+': oper = "+"; break;
case '-': oper = "-"; break;
case '*': oper = "*"; break;
@ -108,7 +108,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
}
fprintf(vlog_out, "(");
switch(ivl_expr_opcode(expr)) {
switch (ivl_expr_opcode(expr)) {
case '%':
if (ivl_expr_value(expr) == IVL_VT_REAL) {
fprintf(stderr, "%s:%u: vlog95 error: Real modulus operator "
@ -427,6 +427,18 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
} else {
// HERE: Should this sign extend if the expression is signed?
emit_expr(scope, sig_expr, wid);
/* Select part of a signal when needed. */
if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) &&
(ivl_expr_width(expr) < ivl_expr_width(sig_expr))) {
ivl_signal_t sig = ivl_expr_signal(sig_expr);
int msb = ivl_signal_msb(sig);
int lsb = ivl_signal_lsb(sig);
int64_t value = lsb;
unsigned e_wid = ivl_expr_width(expr) - 1;
if (msb >= lsb) value += e_wid;
else value -= e_wid;
fprintf(vlog_out, "[%"PRId64":%u]", value, lsb);
}
}
}
@ -508,6 +520,46 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
/* A cast is a noop. */
emit_expr(scope, ivl_expr_oper1(expr), wid);
break;
case 'I':
fprintf(vlog_out, "(++");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment "
"operator is not currently translated.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
case 'i':
fprintf(vlog_out, "(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, "++)");
fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment "
"operator is not currently translated.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
case 'D':
fprintf(vlog_out, "(--");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement "
"operator is not currently translated.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
case 'd':
fprintf(vlog_out, "(");
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, "--)");
fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement "
"operator is not currently translated.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
default:
fprintf(vlog_out, "<unknown>");
emit_expr(scope, ivl_expr_oper1(expr), wid);
@ -516,13 +568,14 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
ivl_expr_file(expr),
ivl_expr_lineno(expr),
ivl_expr_opcode(expr));
vlog_errors += 1;
break;
}
}
void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
switch(ivl_expr_type(expr)) {
switch (ivl_expr_type(expr)) {
case IVL_EX_ARRAY:
emit_expr_array(scope, expr, wid);
break;
@ -535,6 +588,14 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
case IVL_EX_DELAY:
emit_expr_delay(scope, expr, wid);
break;
case IVL_EX_ENUMTYPE:
fprintf(vlog_out, "<enum>");
fprintf(stderr, "%s:%u: vlog95 error: Enum expressions "
"are not supported.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
break;
case IVL_EX_EVENT:
emit_expr_event(scope, expr, wid);
break;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -70,7 +70,7 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt)
ivl_signal_t sig = ivl_expr_signal(expr);
if (ivl_signal_local(sig)) {
assert(! is_stmt);
emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0));
emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0), 0);
return;
}
}
@ -412,9 +412,8 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex)
unsigned is_driver = 0;
unsigned is_array = 0;
int64_t array_idx = 0;
unsigned idx, count;
unsigned idx, count = ivl_nexus_ptrs(nex);
count = ivl_nexus_ptrs(nex);
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr);
@ -501,9 +500,11 @@ static void emit_number_as_string(ivl_net_const_t net_const)
/* Skip any NULL bytes. */
if (val == 0) continue;
/* Print some values that must be escapped. */
/* Print some values that can be escaped. */
if (val == '"') fprintf(vlog_out, "\\\"");
else if (val == '\\') fprintf(vlog_out, "\\\\");
else if (val == '\n') fprintf(vlog_out, "\\n");
else if (val == '\t') fprintf(vlog_out, "\\t");
/* Print the printable characters. */
else if (isprint((int)val)) fprintf(vlog_out, "%c", val);
/* Print the non-printable characters as an octal escape. */
@ -616,8 +617,84 @@ static unsigned find_const_nexus(ivl_scope_t scope, ivl_nexus_t nex)
return 0;
}
static unsigned find_driving_signal(ivl_scope_t scope, ivl_nexus_t nex)
{
ivl_signal_t sig = 0;
unsigned is_array = 0;
int64_t array_idx = 0;
unsigned idx, count = ivl_nexus_ptrs(nex);
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
if (! t_sig) continue;
if (ivl_signal_local(t_sig)) continue;
/* An output can be used if it is driven by this nexus. */
if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) &&
(ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ) &&
(ivl_signal_port(t_sig) != IVL_SIP_OUTPUT)) {
continue;
}
/* We have a signal that can be used to find the name. */
if (sig) {
// HERE: Which one should we use? For now it's the first one found.
// I believe this needs to be solved (see above).
fprintf(stderr, "%s:%u: vlog95 warning: Duplicate name (%s",
ivl_signal_file(t_sig), ivl_signal_lineno(t_sig),
ivl_signal_basename(t_sig));
if (ivl_signal_dimensions(t_sig) > 0) {
int64_t tmp_idx = ivl_nexus_ptr_pin(nex_ptr);
tmp_idx += ivl_signal_array_base(t_sig);
fprintf(stderr, "[%"PRId64"]", tmp_idx);
}
fprintf(stderr, ") found for nexus (%s",
ivl_signal_basename(sig));
if (is_array) fprintf(stderr, "[%"PRId64"]", array_idx);
fprintf(stderr, ")\n");
} else {
sig = t_sig;
if (ivl_signal_dimensions(sig) > 0) {
is_array = 1;
array_idx = ivl_nexus_ptr_pin(nex_ptr);
array_idx += ivl_signal_array_base(sig);
}
}
}
if (sig) {
emit_scope_call_path(scope, ivl_signal_scope(sig));
emit_id(ivl_signal_basename(sig));
if (is_array) fprintf(vlog_out, "[%"PRId64"]", array_idx);
return 1;
}
return 0;
}
static unsigned is_local_input(ivl_scope_t scope, ivl_nexus_t nex)
{
ivl_signal_t sig = 0;
unsigned idx, count = ivl_nexus_ptrs(nex);
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
if (! t_sig) continue;
if (! ivl_signal_local(t_sig)) continue;
if (ivl_signal_port(t_sig) != IVL_SIP_INPUT) continue;
assert(! sig);
assert(ivl_signal_dimensions(t_sig) == 0);
sig = t_sig;
}
if (sig) {
fprintf(vlog_out, "ivlog%s", ivl_signal_basename(sig));
return 1;
}
return 0;
}
// HERE: Does this work correctly with an array reference created from @*?
void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex)
void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD)
{
ivl_scope_t mod_scope;
/* First look in the local scope for the nexus name. */
@ -630,9 +707,16 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex)
if (find_signal_in_nexus(mod_scope, nex)) return;
}
/* Look to see if this is a up/down reference. */
if (allow_UD && find_driving_signal(scope, nex)) return;
/* If there is no signals driving this then look for a constant. */
if (find_const_nexus(scope, nex)) return;
/* Module inputs that are split (arg[7:4], arg[3:0]) need to use
* the local signal names. */
if (is_local_input(scope, nex)) return;
// HERE: Need to check arr[var]? Can this be rebuilt?
// Then look for down scopes and then any scope. For all this warn if
// multiples are found in a given scope. This all needs to be before
@ -641,7 +725,7 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex)
/* It is possible that the nexus does not have a name. For this
* case do not print an actual name. */
fprintf(vlog_out, "/* Empty */");
dump_nexus_information(scope, nex);
// dump_nexus_information(scope, nex);
}
/*
@ -758,6 +842,10 @@ static unsigned is_escaped(const char *id)
return 1;
}
}
/* Any Verilog keyword should also be escaped. */
// HERE: Create a keyword.gperf file to do this check.
if ((strcmp(id, "input") == 0) ||
(strcmp(id, "output") == 0) ) return 1;
/* We looked at all the digits, so this is a normal id. */
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -61,6 +61,8 @@ static int32_t get_int32_from_bits(const char *bits, unsigned nbits,
}
}
/* Sign extend as needed. */
// HERE: Need to emit 1 instead of -1 for some of the constants.
// if (is_signed && (nbits > 1) && (msb == '1') && (trim_wid < 32U)) {
if (is_signed && (msb == '1') && (trim_wid < 32U)) {
value |= ~(((int32_t)1 << trim_wid) - (int32_t)1);
}
@ -315,6 +317,17 @@ int32_t get_int32_from_number(ivl_expr_t expr, int *result_type)
ivl_expr_signed(expr), result_type);
}
/*
* Routine to remove two characters starting at the given address.
*/
static void remove_two_chars(char* str)
{
for (; str[2]; str += 1) {
str[0] = str[2];
}
str[0] = 0;
}
/*
* Routine to print a string value as a string after removing any leading
* escaped NULL bytes.
@ -322,12 +335,42 @@ int32_t get_int32_from_number(ivl_expr_t expr, int *result_type)
void emit_string(const char* string)
{
char *buffer = strdup(string);
char *cptr = buffer;
char *bptr = buffer;
char *cptr;
fprintf(vlog_out, "\"");
/* Prune any leading escaped NULL bytes. */
while ((cptr[0] == '\\') && (cptr[1] == '0') &&
(cptr[2] == '0') && (cptr[3] == '0')) cptr += 4;
if (*cptr) fprintf(vlog_out, "%s", cptr);
while ((bptr[0] == '\\') && (bptr[1] == '0') &&
(bptr[2] == '0') && (bptr[3] == '0')) bptr += 4;
for (cptr = bptr; *cptr; cptr += 1) {
if (*cptr == '\\') {
/* Replace any \011 with \t */
if ((cptr[1] == '0') && (cptr[2] == '1') &&
(cptr[3] == '1')) {
cptr[1] = 't';
remove_two_chars(cptr+2);
cptr += 1;
/* Replace any \012 with \n */
} else if ((cptr[1] == '0') && (cptr[2] == '1') &&
(cptr[3] == '2')) {
cptr[1] = 'n';
remove_two_chars(cptr+2);
cptr += 1;
/* Replace any \042 with \" */
} else if ((cptr[1] == '0') && (cptr[2] == '4') &&
(cptr[3] == '2')) {
cptr[1] = '"';
remove_two_chars(cptr+2);
cptr += 1;
/* Replace any \134 with \\ */
} else if ((cptr[1] == '1') && (cptr[2] == '3') &&
(cptr[3] == '4')) {
cptr[1] = '\\';
remove_two_chars(cptr+2);
cptr += 1;
} else cptr += 3;
}
}
if (*bptr) fprintf(vlog_out, "%s", bptr);
free(buffer);
fprintf(vlog_out, "\"");
}

View File

@ -204,7 +204,7 @@ void emit_net_def(ivl_scope_t scope, ivl_signal_t sig)
ivl_signal_lineno(sig), ivl_signal_basename(sig));
vlog_errors += 1;
} else {
switch(ivl_signal_type(sig)) {
switch (ivl_signal_type(sig)) {
case IVL_SIT_TRI:
case IVL_SIT_UWIRE:
// HERE: Need to add support for supply nets. Probably supply strength
@ -363,19 +363,21 @@ static void emit_module_ports(ivl_scope_t scope)
if (count == 0) return;
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0));
emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0), 0);
for (idx = 1; idx < count; idx += 1) {
fprintf(vlog_out, ", ");
emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx));
emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx), 0);
}
fprintf(vlog_out, ")");
}
static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex)
static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex,
unsigned *word)
{
assert(nex);
unsigned idx, count = ivl_nexus_ptrs(nex);
ivl_signal_t sig = 0;
*word = 0;
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
@ -383,6 +385,7 @@ static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex)
if (ivl_signal_scope(t_sig) != scope) continue;
assert(! sig);
sig = t_sig;
*word = ivl_nexus_ptr_pin(nex_ptr);
}
}
return sig;
@ -475,7 +478,12 @@ static void emit_port(ivl_signal_t port)
}
emit_sig_type(port);
fprintf(vlog_out, " ");
emit_id(ivl_signal_basename(port));
/* Split port (arg[7:4],arg[3:0]) are generated using local signals. */
if (ivl_signal_local(port)) {
fprintf(vlog_out, "ivlog%s", ivl_signal_basename(port));
} else {
emit_id(ivl_signal_basename(port));
}
fprintf(vlog_out, ";");
emit_sig_file_line(port);
fprintf(vlog_out, "\n");
@ -483,10 +491,11 @@ static void emit_port(ivl_signal_t port)
static void emit_module_port_defs(ivl_scope_t scope)
{
unsigned idx, count = ivl_scope_ports(scope);
unsigned word, idx, count = ivl_scope_ports(scope);
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
ivl_signal_t port = get_port_from_nexus(scope, nex);
ivl_signal_t port = get_port_from_nexus(scope, nex, &word);
// HERE: Do we need to use word?
if (port) emit_port(port);
else {
fprintf(vlog_out, "<missing>");
@ -502,15 +511,17 @@ static void emit_module_port_defs(ivl_scope_t scope)
static void emit_module_call_expr(ivl_scope_t scope, unsigned idx)
{
unsigned word;
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
ivl_signal_t port = get_port_from_nexus(scope, nex);
ivl_signal_t port = get_port_from_nexus(scope, nex, &word);
/* For an input port we need to emit the driving expression. */
if (ivl_signal_port(port) == IVL_SIP_INPUT) {
emit_nexus_port_driver_as_ca(ivl_scope_parent(scope),
ivl_signal_nex(port, 0));
ivl_signal_nex(port, word));
/* For an output we need to emit the signal the output is driving. */
} else {
emit_nexus_as_ca(ivl_scope_parent(scope), ivl_signal_nex(port, 0));
emit_nexus_as_ca(ivl_scope_parent(scope),
ivl_signal_nex(port, word), 0);
}
}
@ -536,6 +547,70 @@ static void emit_task_func_port_defs(ivl_scope_t scope)
if (count) fprintf(vlog_out, "\n");
}
/*
* Look at all the processes to see if we can find one with the expected
* scope. If we don't find one then we can assume the block only has
* variable definitions and needs to be emitted here in the scope code.
*/
static int no_stmts_in_process(ivl_process_t proc, ivl_scope_t scope)
{
ivl_statement_t stmt = ivl_process_stmt(proc);
switch (ivl_statement_type(stmt)) {
case IVL_ST_BLOCK:
case IVL_ST_FORK:
if (ivl_stmt_block_scope(stmt) == scope) return 1;
default: /* Do nothing. */ ;
}
return 0;
}
/*
* If a named block has no statements then we may need to emit it here if
* there are variable definitions in the scope. We translate all this to
* an initial and named begin since that is enough to hold the variables.
*/
static void emit_named_block_scope(ivl_scope_t scope)
{
unsigned idx, count = ivl_scope_events(scope);
unsigned named_ev = 0;
/* If there are no parameters, signals or named events then skip
* this block. */
for (idx = 0; idx < count; idx += 1) {
ivl_event_t event = ivl_scope_event(scope, idx);
/* If this event has any type of edge sensitivity then it is
* not a named event. */
if (ivl_event_nany(event)) continue;
if (ivl_event_npos(event)) continue;
if (ivl_event_nneg(event)) continue;
named_ev = 1;
break;
}
if ((ivl_scope_params(scope) == 0) && (ivl_scope_sigs(scope) == 0) &&
(named_ev == 0)) return;
/* Currently we only need to emit a named block for the variables
* if the parent scope is a module. This gets much more complicated
* if this is not true. */
if (ivl_scope_type(ivl_scope_parent(scope)) != IVL_SCT_MODULE) return;
/* Scan all the processes looking for one that matches this scope.
* If a match is found then this named block was already emitted by
* the process code. */
if (ivl_design_process(design, (ivl_process_f)no_stmts_in_process,
scope)) return;
/* A match was not found so emit the named block here to get the
* variable definitions. */
fprintf(vlog_out, "\n%*cinitial begin: ", indent, ' ');
emit_id(ivl_scope_tname(scope));
emit_scope_file_line(scope);
fprintf(vlog_out, "\n");
indent += indent_incr;
emit_scope_variables(scope);
indent -= indent_incr;
fprintf(vlog_out, "%*cend /* ", indent, ' ');
emit_id(ivl_scope_tname(scope));
fprintf(vlog_out, " */\n");
}
/*
* This search method may be slow for a large structural design with a
* large number of gate types. That's not what this converter was built
@ -652,6 +727,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
case IVL_SCT_BEGIN:
case IVL_SCT_FORK:
assert(indent != 0);
emit_named_block_scope(scope);
return 0; /* A named begin/fork is handled in line. */
default:
fprintf(stderr, "%s:%u: vlog95 error: Unsupported scope type "

View File

@ -780,7 +780,7 @@ static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt)
{
char *case_type;
unsigned idx, default_case, count = ivl_stmt_case_count(stmt);
switch(ivl_statement_type(stmt)) {
switch (ivl_statement_type(stmt)) {
case IVL_ST_CASE:
case IVL_ST_CASER:
case_type = "case";
@ -1047,7 +1047,7 @@ static void emit_stmt_while(ivl_scope_t scope, ivl_statement_t stmt)
void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
{
switch(ivl_statement_type(stmt)) {
switch (ivl_statement_type(stmt)) {
case IVL_ST_NOOP:
/* If this is a statement termination then just finish the
* statement, otherwise print an empty begin/end pair. */
@ -1159,7 +1159,8 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
void emit_process(ivl_scope_t scope, ivl_process_t proc)
{
ivl_statement_t stmt;
ivl_statement_t stmt = ivl_process_stmt(proc);
if (ivl_statement_type(stmt) == IVL_ST_NOOP) return;
fprintf(vlog_out, "\n%*c", get_indent(), ' ');
switch (ivl_process_type(proc)) {
case IVL_PR_INITIAL:
@ -1181,7 +1182,6 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc)
ivl_process_file(proc),
ivl_process_lineno(proc));
}
stmt = ivl_process_stmt(proc);
if (ivl_statement_type(stmt) == IVL_ST_NOOP) {
fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' ');
} else {

View File

@ -25,7 +25,7 @@
static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun)
{
const char *value = 0;
switch(entry) {
switch (entry) {
case '0':
value = " 0 ";
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2011 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,7 +30,7 @@
static const char*version_string =
"Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n"
"Copyright (C) 2010-2011 Cary R. (cygcary@yahoo.com)\n\n"
"Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com)\n\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 2 of the License, or\n"
@ -195,6 +195,10 @@ int target_design(ivl_design_t des)
fclose(vlog_out);
/* A do nothing call to prevent warnings about this routine not
* being used. */
dump_nexus_information(0, 0);
return vlog_errors;
}

View File

@ -85,8 +85,10 @@ extern void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope);
extern void emit_scope_variables(ivl_scope_t scope);
extern void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope);
extern void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope);
extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex);
extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex);
extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex,
unsigned allow_UD);
extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex,
unsigned allow_UD);
extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex);
extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net);
extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig);

View File

@ -85,7 +85,7 @@ else
endif
vvp.tgt: $O $(TGTDEPLIBS)
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
vvp.conf: $(srcdir)/vvp.conf.in Makefile
echo 'flag:VVP_EXECUTABLE=$(bindir)/vvp$(suffix)' | cat $(srcdir)/vvp.conf.in - > vvp.conf

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2010,2012 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
@ -38,7 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw)
ivl_expr_t fall_exp = ivl_switch_delay(sw, 1);
ivl_expr_t decay_exp= ivl_switch_delay(sw, 2);
/* We do not support tran delays. */
if ((rise_exp || fall_exp || decay_exp) &&
(!number_is_immediate(rise_exp, 64, 0) ||
number_is_unknown(rise_exp) ||
@ -76,15 +75,16 @@ void draw_switch_in_scope(ivl_switch_t sw)
processing doesn't have to deal with it. */
const char*raw = draw_net_input(enable);
snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw);
str_e = str_e_buf;
fprintf(vvp_out, "%s/d .delay 1 "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n",
raw, get_number_immediate64(rise_exp),
str_e, get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp), raw);
fprintf(vvp_out, "p%p .import I%p, %s/d;\n", enable, island, raw);
snprintf(str_e_buf, sizeof str_e_buf, "p%p", enable);
str_e = str_e_buf;
fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e);
} else if (enable) {
str_e = draw_island_net_input(island, enable);

View File

@ -170,6 +170,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
case IVL_EX_SELECT: {
ivl_expr_t vexpr = ivl_expr_oper1(expr);
ivl_expr_t bexpr;
ivl_expr_t wexpr;
assert(vexpr);
@ -179,20 +180,38 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
/* The signal is part of an array. */
/* Add &APV<> code here when it is finished. */
if (ivl_expr_oper1(vexpr)) return 0;
bexpr = ivl_expr_oper2(expr);
/* This is a pad operation. */
if (!bexpr) return 0;
wexpr = ivl_expr_oper1(vexpr);
/* If vexpr has an operand, then that operand is a word
index and we are taking a select from an array
word. This would come up in expressions like
"array[<word>][<part>]" where wexpr is <word> */
if (wexpr && number_is_immediate(wexpr, 64, 1)
&& number_is_immediate(bexpr, 64, 1)) {
assert(! number_is_unknown(bexpr));
assert(! number_is_unknown(wexpr));
snprintf(buffer, sizeof buffer, "&APV<v%p, %ld, %ld, %u>",
ivl_expr_signal(vexpr),
get_number_immediate(wexpr),
get_number_immediate(bexpr),
ivl_expr_width(expr));
} else if (wexpr) {
return 0;
/* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) {
} else if (number_is_immediate(bexpr, 64, 1)) {
assert(! number_is_unknown(bexpr));
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_number_immediate(bexpr),
ivl_expr_width(expr));
/* This is an indexed bit/part select. */
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL ||
ivl_expr_type(bexpr) == IVL_EX_SELECT) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2012 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
@ -2924,8 +2924,8 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid)
static struct vector_info increment(ivl_expr_t e, unsigned wid, bool pre)
{
ivl_signal_t s;
unsigned w;
ivl_signal_t s = 0;
unsigned w = 0;
struct vector_info r;
struct vector_info rc;
@ -3000,8 +3000,8 @@ static inline struct vector_info post_increment(ivl_expr_t e, unsigned wid)
static struct vector_info decrement(ivl_expr_t e, unsigned wid, bool pre)
{
ivl_signal_t s;
unsigned w;
ivl_signal_t s = 0;
unsigned w = 0;
struct vector_info r;
struct vector_info rc;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2012 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
@ -590,6 +590,7 @@ static int draw_unary_real(ivl_expr_t expr)
fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
ivl_expr_opcode(expr));
assert(0);
return 0;
}
int draw_eval_real(ivl_expr_t expr)

View File

@ -425,8 +425,17 @@ const char*draw_input_from_net(ivl_nexus_t nex)
*/
static void draw_reg_in_scope(ivl_signal_t sig)
{
int msb = ivl_signal_msb(sig);
int lsb = ivl_signal_lsb(sig);
int msb;
int lsb;
if (ivl_signal_packed_dimensions(sig) > 1) {
// FIX ME: Improve this when vvp becomes aware of packed
// arrays.
msb = ivl_signal_width(sig) - 1;
lsb = 0;
} else {
msb = ivl_signal_msb(sig);
lsb = ivl_signal_lsb(sig);
}
const char*datatype_flag = ivl_signal_integer(sig) ? "/i" :
ivl_signal_signed(sig)? "/s" : "";

View File

@ -110,9 +110,11 @@ parse.o: parse.cc
lexor.cc: $(srcdir)/lexor.lex
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
parse.cc parse.h: $(srcdir)/parse.y
$(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y
mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h
# Build this in two steps to avoid parallel build issues (see pr3462585)
parse.cc: $(srcdir)/parse.y
$(YACC) --verbose -t -d -o $@ $<
parse.h: parse.cc
mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@
lexor_keyword.o: lexor_keyword.cc parse.h

View File

@ -124,24 +124,28 @@ endif
system.vpi: $O $(OPP) ../vvp/libvpi.a
$(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
sys_readmem_lex.c: sys_readmem_lex.lex
$(LEX) -t $(srcdir)/sys_readmem_lex.lex > sys_readmem_lex.c
sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex
$(LEX) -t $< > $@
sdf_lexor.o: sdf_lexor.c sdf_parse.h
sdf_lexor.c: sdf_lexor.lex
$(LEX) -t $(srcdir)/sdf_lexor.lex > sdf_lexor.c
sdf_lexor.c: $(srcdir)/sdf_lexor.lex
$(LEX) -t $< > $@
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
$(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y
# Build this in two steps to avoid parallel build issues (see pr3462585)
sdf_parse.c: $(srcdir)/sdf_parse.y
$(YACC) --verbose -t -p sdf -d -o $@ $<
sdf_parse.h: sdf_parse.c
table_mod_lexor.o: table_mod_lexor.c table_mod_parse.h
table_mod_lexor.c: $(srcdir)/table_mod_lexor.lex
$(LEX) -t $< > $@
table_mod_parse.c table_mod_parse.h: $(srcdir)/table_mod_parse.y
$(YACC) --verbose -d -p tblmod -o table_mod_parse.c $<
# Build this in two steps to avoid parallel build issues (see pr3462585)
table_mod_parse.c: $(srcdir)/table_mod_parse.y
$(YACC) --verbose -t -p tblmod -d -o $@ $<
table_mod_parse.h: table_mod_parse.c
v2005_math.vpi: $M ../vvp/libvpi.a
$(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -182,7 +182,6 @@ static char * format_as_string(int ljust, int plus, int ld_zero, int width,
static void get_time(char *rtn, const char *value, int prec,
PLI_INT32 time_units)
{
int head, tail;
int shift = time_units - timeformat_info.units;
/* Strip any leading zeros, but leave a single zero. */
@ -203,7 +202,9 @@ static void get_time(char *rtn, const char *value, int prec,
/* We need to scale the number down. */
} else {
head = strlen(value) + shift;
int len = strlen(value);
int head = len + shift;
int tail;
/* We have digits to the left of the decimal point. */
if (head > 0) {
strncpy(rtn, value, head);
@ -222,18 +223,18 @@ static void get_time(char *rtn, const char *value, int prec,
strcpy(rtn, "0");
if (prec > 0) strcat(rtn, ".");
/* Add leading zeros as needed. */
head = -shift - 1;
head = -head;
if (head > prec) head = prec;
while (head > 0) {
strcat(rtn, "0");
head -= 1;
}
/* Add digits from the value if they fit. */
tail = prec + shift + 1;
tail = prec + len + shift;
if (tail > 0) {
strncat(rtn, value, tail);
/* Add trailing zeros to fill out the precision. */
tail = prec + shift + 1 - strlen(value);
tail = prec + shift + 1 - len;
while (tail > 0) {
strcat(rtn, "0");
tail -= 1;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2012 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
@ -680,7 +680,8 @@ static PLI_INT32 sys_fread_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
vpi_free_object(argv);
}
words = (width+31)/32;
assert(width > 0);
words = (width - 1)/32 + 1;
vector = calloc(words, sizeof(s_vpi_vecval));
bpe = (width+7)/8;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -587,7 +587,7 @@ static unsigned check_numeric_args(vpiHandle argv, unsigned count,
/* Check that the first count arguments are numeric. Currently
* only three are needed/supported. */
for (idx = 0; idx < count; idx += 1) {
char *loc;
char *loc = NULL;
vpiHandle arg = vpi_scan(argv);
/* Get the name for this argument. */

View File

@ -104,7 +104,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
vpi_register_cb(&cb);
vpi_put_userdata(sys, mon);
/* Check that there are no more then one argument. */
/* Check that there is no more than one argument. */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2012 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
@ -104,6 +104,7 @@ void sys_register()
tf_data.sizetf = 0;
tf_data.user_data = "$vpi_tree";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
}
void (*vlog_startup_routines[])() = {

View File

@ -1,7 +1,7 @@
#ifndef __vpi_user_H
#define __vpi_user_H
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2012 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
@ -46,7 +46,11 @@ EXTERN_C_START
# include "_pli_types.h"
#define ICARUS_VPI_CONST
#ifdef __cplusplus
typedef class __vpiHandle *vpiHandle;
#else
typedef struct __vpiHandle *vpiHandle;
#endif
/*
* This structure is created by the VPI application to provide hooks

View File

@ -129,7 +129,7 @@ vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
else
libvpi.a: libvpi.c
$(CC) $(CFLAGS) -c $<
$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
rm -f libvpi.a
$(AR) cqv libvpi.a libvpi.o
$(RANLIB) libvpi.a
@ -157,11 +157,11 @@ parse.o: parse.cc
tables.o: tables.cc
# Build this in two steps to avoid parallel build issues (see pr3462585)
parse.cc: $(srcdir)/parse.y
$(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y
$(YACC) --verbose -t -d -o $@ $<
parse.h: parse.cc
mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h
mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@
lexor.cc: $(srcdir)/lexor.lex
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
#include "vpi_user.h"
typedef struct __vpiArray* vvp_array_t;
class value_callback;
/*
* This function tries to find the array (by label) in the global
@ -48,8 +49,8 @@ extern double array_get_word_r(vvp_array_t array, unsigned address);
/* VPI hooks */
extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word);
extern void vpip_array_change(struct __vpiCallback*cb, vpiHandle word);
extern value_callback* vpip_array_word_change(p_cb_data data);
extern value_callback* vpip_array_change(p_cb_data data);
/* Compile hooks */
extern void compile_varw_real(char*label, vvp_array_t array,

View File

@ -1,7 +1,7 @@
#ifndef __codes_H
#define __codes_H
/*
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2012 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
@ -186,7 +186,7 @@ struct vvp_code_s {
vvp_net_t *net;
vvp_code_t cptr;
vvp_array_t array;
struct __vpiHandle*handle;
class __vpiHandle*handle;
struct __vpiScope*scope;
};

Some files were not shown because too many files have changed in this diff Show More