Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
f926cbcc59
23
Makefile.in
23
Makefile.in
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
6
Module.h
6
Module.h
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
@ -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
|
||||
4
PExpr.cc
4
PExpr.cc
|
|
@ -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
27
PExpr.h
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
15
PScope.cc
15
PScope.cc
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
24
PScope.h
24
PScope.h
|
|
@ -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
|
||||
|
|
|
|||
8
PTask.h
8
PTask.h
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
80
PWire.cc
80
PWire.cc
|
|
@ -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
21
PWire.h
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
17
Statement.h
17
Statement.h
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
263
elab_expr.cc
263
elab_expr.cc
|
|
@ -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
|
||||
|
|
|
|||
220
elab_lval.cc
220
elab_lval.cc
|
|
@ -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 "
|
||||
|
|
|
|||
77
elab_net.cc
77
elab_net.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
328
elab_sig.cc
328
elab_sig.cc
|
|
@ -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);
|
||||
|
|
|
|||
106
elaborate.cc
106
elaborate.cc
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
36
functor.cc
36
functor.cc
|
|
@ -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*)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
3
ivl.def
3
ivl.def
|
|
@ -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
|
||||
|
|
|
|||
31
ivl_target.h
31
ivl_target.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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@
|
||||
|
||||
|
|
|
|||
22
lexor.lex
22
lexor.lex
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ bool Nexus::assign_lval() const
|
|||
if (net == 0)
|
||||
continue;
|
||||
|
||||
if (net->peek_lref())
|
||||
if (net->peek_lref() > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
229
netlist.cc
229
netlist.cc
|
|
@ -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;
|
||||
|
|
|
|||
89
netlist.h
89
netlist.h
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
184
netmisc.cc
184
netmisc.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
47
netmisc.h
47
netmisc.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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. */
|
||||
}
|
||||
|
||||
|
|
|
|||
12
parse_misc.h
12
parse_misc.h
|
|
@ -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
428
pform.cc
|
|
@ -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
78
pform.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -19,3 +19,7 @@
|
|||
|
||||
|
||||
# include "pform_types.h"
|
||||
|
||||
data_type_t::~data_type_t()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
18
synth.cc
18
synth.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
30
t-dll-api.cc
30
t-dll-api.cc
|
|
@ -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)
|
||||
|
|
|
|||
18
t-dll.cc
18
t-dll.cc
|
|
@ -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()) {
|
||||
|
|
|
|||
7
t-dll.h
7
t-dll.h
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
# include "pcb_priv.h"
|
||||
# include <cassert>
|
||||
# include <cstdio>
|
||||
|
||||
using namespace std;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
# include "pcb_config.h"
|
||||
# include "pcb_priv.h"
|
||||
# include <cassert>
|
||||
# include <cstdio>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 $@
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, "\"");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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" : "";
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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[])() = {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
943
vvp/array.cc
943
vvp/array.cc
File diff suppressed because it is too large
Load Diff
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue