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 \
|
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 \
|
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 \
|
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_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 \
|
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 \
|
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 \
|
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \
|
||||||
Statement.o AStatement.o $M $(FF) $(TT)
|
Statement.o AStatement.o $M $(FF) $(TT)
|
||||||
|
|
||||||
|
|
@ -150,8 +151,8 @@ endif
|
||||||
clean:
|
clean:
|
||||||
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
|
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
|
||||||
rm -f *.o parse.cc parse.h lexor.cc
|
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 ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps
|
||||||
rm -f syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp
|
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 -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc
|
||||||
rm -rf dep
|
rm -rf dep
|
||||||
rm -f version.exe
|
rm -f version.exe
|
||||||
|
|
@ -244,15 +245,17 @@ lexor.o: lexor.cc parse.h
|
||||||
|
|
||||||
parse.o: parse.cc
|
parse.o: parse.cc
|
||||||
|
|
||||||
parse.cc parse.h: $(srcdir)/parse.y
|
# Build this in two steps to avoid parallel build issues (see pr3462585)
|
||||||
$(YACC) --verbose -t -p VL -d -o parse.cc $(srcdir)/parse.y
|
parse.cc: $(srcdir)/parse.y
|
||||||
mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h
|
$(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
|
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
|
lexor.cc: $(srcdir)/lexor.lex
|
||||||
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
|
$(LEX) -s -t $< > $@
|
||||||
|
|
||||||
lexor_keyword.o: lexor_keyword.cc parse.h
|
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. */
|
/* n is a permallocated string. */
|
||||||
Module::Module(perm_string n)
|
Module::Module(perm_string n)
|
||||||
: PScope(n)
|
: PScopeExtra(n)
|
||||||
{
|
{
|
||||||
library_flag = false;
|
library_flag = false;
|
||||||
is_cell = false;
|
is_cell = false;
|
||||||
|
|
|
||||||
6
Module.h
6
Module.h
|
|
@ -49,7 +49,7 @@ class NetScope;
|
||||||
* therefore the handle for grasping the described circuit.
|
* 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
|
/* The module ports are in general a vector of port_t
|
||||||
objects. Each port has a name and an ordered list of
|
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 time_from_timescale;
|
||||||
bool timescale_warn_done;
|
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 has a list of generate schemes that appear in
|
||||||
the module definition. These are used at elaboration time. */
|
the module definition. These are used at elaboration time. */
|
||||||
list<PGenerate*> generate_schemes;
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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);
|
PWire*net = new PWire(name, type, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
|
||||||
net->set_file(get_file());
|
net->set_file(get_file());
|
||||||
net->set_lineno(get_lineno());
|
net->set_lineno(get_lineno());
|
||||||
net->set_range(0, 0, SR_NET, true);
|
net->set_range_scalar(SR_NET);
|
||||||
scope->wires[name] = net;
|
scope->wires[name] = net;
|
||||||
if (warn_implicit) {
|
if (warn_implicit) {
|
||||||
cerr << get_fileline() << ": warning: 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;
|
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:
|
private:
|
||||||
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
|
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
|
||||||
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
|
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
|
||||||
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
||||||
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
||||||
index_component_t::ctype_t) const;
|
index_component_t::ctype_t) const;
|
||||||
|
bool elaborate_lval_net_packed_member_(Design*, NetScope*,
|
||||||
|
NetAssign_*,
|
||||||
|
const perm_string&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetExpr*elaborate_expr_param_(Design*des,
|
NetExpr*elaborate_expr_param_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*found,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb,
|
const NetExpr*par_lsb,
|
||||||
unsigned expr_wid,
|
unsigned expr_wid,
|
||||||
|
|
@ -362,21 +377,21 @@ class PEIdent : public PExpr {
|
||||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*found,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb,
|
const NetExpr*par_lsb,
|
||||||
unsigned expr_wid) const;
|
unsigned expr_wid) const;
|
||||||
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*found,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb,
|
const NetExpr*par_lsb,
|
||||||
bool need_const) const;
|
bool need_const) const;
|
||||||
NetExpr*elaborate_expr_param_idx_do_(Design*des,
|
NetExpr*elaborate_expr_param_idx_do_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*found,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb,
|
const NetExpr*par_lsb,
|
||||||
bool need_const) const;
|
bool need_const) const;
|
||||||
|
|
@ -494,6 +509,10 @@ class PEUnary : public PExpr {
|
||||||
unsigned flags) const;
|
unsigned flags) const;
|
||||||
virtual verinum* eval_const(Design*des, NetScope*sc) 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:
|
private:
|
||||||
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;
|
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
|
else
|
||||||
return (*cur).second;
|
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 PEvent;
|
||||||
class PExpr;
|
class PExpr;
|
||||||
|
class PFunction;
|
||||||
class AProcess;
|
class AProcess;
|
||||||
class PProcess;
|
class PProcess;
|
||||||
|
class PTask;
|
||||||
class PWire;
|
class PWire;
|
||||||
|
|
||||||
class Design;
|
class Design;
|
||||||
|
|
@ -83,6 +85,9 @@ class LexicalScope {
|
||||||
map<perm_string,param_expr_t>parameters;
|
map<perm_string,param_expr_t>parameters;
|
||||||
map<perm_string,param_expr_t>localparams;
|
map<perm_string,param_expr_t>localparams;
|
||||||
|
|
||||||
|
// Defined types in the scope.
|
||||||
|
map<perm_string,data_type_t*>typedefs;
|
||||||
|
|
||||||
// Named events in the scope.
|
// Named events in the scope.
|
||||||
map<perm_string,PEvent*>events;
|
map<perm_string,PEvent*>events;
|
||||||
|
|
||||||
|
|
@ -105,6 +110,8 @@ class LexicalScope {
|
||||||
LexicalScope* parent_scope() const { return parent_; }
|
LexicalScope* parent_scope() const { return parent_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void dump_typedefs_(ostream&out, unsigned indent) const;
|
||||||
|
|
||||||
void dump_parameters_(ostream&out, unsigned indent) const;
|
void dump_parameters_(ostream&out, unsigned indent) const;
|
||||||
|
|
||||||
void dump_localparams_(ostream&out, unsigned indent) const;
|
void dump_localparams_(ostream&out, unsigned indent) const;
|
||||||
|
|
@ -145,4 +152,21 @@ class PScope : public LexicalScope {
|
||||||
perm_string name_;
|
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
|
#endif
|
||||||
|
|
|
||||||
8
PTask.h
8
PTask.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __PTask_H
|
#ifndef __PTask_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -41,12 +41,14 @@ enum PTaskFuncEnum {
|
||||||
PTF_REALTIME,
|
PTF_REALTIME,
|
||||||
PTF_TIME,
|
PTF_TIME,
|
||||||
PTF_ATOM2,
|
PTF_ATOM2,
|
||||||
PTF_ATOM2_S
|
PTF_ATOM2_S,
|
||||||
|
PTF_STRING,
|
||||||
|
PTF_VOID
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PTaskFuncArg {
|
struct PTaskFuncArg {
|
||||||
PTaskFuncEnum type;
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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)
|
ivl_variable_type_t dt)
|
||||||
: name_(n), type_(t), port_type_(pt), data_type_(dt),
|
: name_(n), type_(t), port_type_(pt), data_type_(dt),
|
||||||
signed_(false), isint_(false),
|
signed_(false), isint_(false),
|
||||||
port_msb_(0), port_lsb_(0), port_set_(false),
|
port_set_(false), net_set_(false), is_scalar_(false),
|
||||||
net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false),
|
error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0),
|
||||||
error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), discipline_(0)
|
discipline_(0)
|
||||||
{
|
{
|
||||||
if (t == NetNet::INTEGER) {
|
if (t == NetNet::INTEGER) {
|
||||||
type_ = NetNet::REG;
|
type_ = NetNet::REG;
|
||||||
|
|
@ -148,8 +148,9 @@ bool PWire::get_scalar() const
|
||||||
return is_scalar_;
|
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) {
|
switch (type) {
|
||||||
case SR_PORT:
|
case SR_PORT:
|
||||||
if (port_set_) {
|
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;
|
<< "'' has already been declared a port." << endl;
|
||||||
error_cnt_ += 1;
|
error_cnt_ += 1;
|
||||||
} else {
|
} else {
|
||||||
port_msb_ = m;
|
|
||||||
port_lsb_ = l;
|
|
||||||
port_set_ = true;
|
port_set_ = true;
|
||||||
is_scalar_ = is_scalar;
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -170,10 +168,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
|
||||||
<< "'' has already been declared." << endl;
|
<< "'' has already been declared." << endl;
|
||||||
error_cnt_ += 1;
|
error_cnt_ += 1;
|
||||||
} else {
|
} else {
|
||||||
net_msb_ = m;
|
|
||||||
net_lsb_ = l;
|
|
||||||
net_set_ = true;
|
net_set_ = true;
|
||||||
is_scalar_ = is_scalar;
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -190,13 +185,58 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
|
||||||
error_cnt_ += 1;
|
error_cnt_ += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
port_msb_ = m;
|
|
||||||
port_lsb_ = l;
|
|
||||||
port_set_ = true;
|
port_set_ = true;
|
||||||
net_msb_ = m;
|
|
||||||
net_lsb_ = l;
|
|
||||||
net_set_ = true;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -217,9 +257,17 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||||
void PWire::set_enumeration(enum_type_t*enum_type)
|
void PWire::set_enumeration(enum_type_t*enum_type)
|
||||||
{
|
{
|
||||||
assert(enum_type_ == 0);
|
assert(enum_type_ == 0);
|
||||||
|
assert(struct_type_ == 0);
|
||||||
enum_type_ = enum_type;
|
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)
|
void PWire::set_discipline(ivl_discipline_t d)
|
||||||
{
|
{
|
||||||
assert(discipline_ == 0);
|
assert(discipline_ == 0);
|
||||||
|
|
|
||||||
21
PWire.h
21
PWire.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __PWire_H
|
#ifndef __PWire_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "LineInfo.h"
|
# include "LineInfo.h"
|
||||||
|
# include <list>
|
||||||
# include <map>
|
# include <map>
|
||||||
# include "svector.h"
|
|
||||||
# include "StringHeap.h"
|
# include "StringHeap.h"
|
||||||
|
|
||||||
#ifdef HAVE_IOSFWD
|
#ifdef HAVE_IOSFWD
|
||||||
|
|
@ -75,11 +75,13 @@ class PWire : public LineInfo {
|
||||||
bool set_data_type(ivl_variable_type_t dt);
|
bool set_data_type(ivl_variable_type_t dt);
|
||||||
ivl_variable_type_t get_data_type() const;
|
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_memory_idx(PExpr*ldx, PExpr*rdx);
|
||||||
|
|
||||||
void set_enumeration(enum_type_t*enum_type);
|
void set_enumeration(enum_type_t*enum_type);
|
||||||
|
void set_struct_type(struct_type_t*type);
|
||||||
|
|
||||||
void set_discipline(ivl_discipline_t);
|
void set_discipline(ivl_discipline_t);
|
||||||
ivl_discipline_t get_discipline(void) const;
|
ivl_discipline_t get_discipline(void) const;
|
||||||
|
|
@ -100,12 +102,14 @@ class PWire : public LineInfo {
|
||||||
bool isint_; // original type of integer
|
bool isint_; // original type of integer
|
||||||
|
|
||||||
// These members hold expressions for the bit width of the
|
// These members hold expressions for the bit width of the
|
||||||
// wire. If they do not exist, the wire is 1 bit wide.
|
// wire. If they do not exist, the wire is 1 bit wide. If they
|
||||||
PExpr*port_msb_;
|
// do exist, they represent the packed dimensions of the
|
||||||
PExpr*port_lsb_;
|
// 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_;
|
bool port_set_;
|
||||||
PExpr*net_msb_;
|
std::list<pform_range_t>net_;
|
||||||
PExpr*net_lsb_;
|
|
||||||
bool net_set_;
|
bool net_set_;
|
||||||
bool is_scalar_;
|
bool is_scalar_;
|
||||||
unsigned error_cnt_;
|
unsigned error_cnt_;
|
||||||
|
|
@ -116,6 +120,7 @@ class PWire : public LineInfo {
|
||||||
PExpr*ridx_;
|
PExpr*ridx_;
|
||||||
|
|
||||||
enum_type_t*enum_type_;
|
enum_type_t*enum_type_;
|
||||||
|
struct_type_t*struct_type_;
|
||||||
|
|
||||||
ivl_discipline_t discipline_;
|
ivl_discipline_t discipline_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -276,9 +276,8 @@ PForever::~PForever()
|
||||||
}
|
}
|
||||||
|
|
||||||
PForStatement::PForStatement(PExpr*n1, PExpr*e1, PExpr*cond,
|
PForStatement::PForStatement(PExpr*n1, PExpr*e1, PExpr*cond,
|
||||||
PExpr*n2, PExpr*e2, Statement*st)
|
Statement*step, Statement*st)
|
||||||
: name1_(n1), expr1_(e1), cond_(cond), name2_(n2), expr2_(e2),
|
: name1_(n1), expr1_(e1), cond_(cond), step_(step), statement_(st)
|
||||||
statement_(st)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
17
Statement.h
17
Statement.h
|
|
@ -196,18 +196,6 @@ class PCallTask : public Statement {
|
||||||
|
|
||||||
const pform_name_t& path() const;
|
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 void dump(ostream&out, unsigned ind) const;
|
||||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||||
|
|
||||||
|
|
@ -403,7 +391,7 @@ class PForStatement : public Statement {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PForStatement(PExpr*n1, PExpr*e1, PExpr*cond,
|
PForStatement(PExpr*n1, PExpr*e1, PExpr*cond,
|
||||||
PExpr*n2, PExpr*e2, Statement*st);
|
Statement*step, Statement*body);
|
||||||
~PForStatement();
|
~PForStatement();
|
||||||
|
|
||||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||||
|
|
@ -417,8 +405,7 @@ class PForStatement : public Statement {
|
||||||
|
|
||||||
PExpr*cond_;
|
PExpr*cond_;
|
||||||
|
|
||||||
PExpr* name2_;
|
Statement*step_;
|
||||||
PExpr* expr2_;
|
|
||||||
|
|
||||||
Statement*statement_;
|
Statement*statement_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,6 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
||||||
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
SHARED = @shared@
|
|
||||||
|
|
||||||
O = cadpli.o
|
O = cadpli.o
|
||||||
|
|
||||||
all: dep cadpli.vpl $(ALL32)
|
all: dep cadpli.vpl $(ALL32)
|
||||||
|
|
@ -80,7 +78,7 @@ ifeq (@MINGW32@,yes)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
cadpli.vpl: $O ../vvp/libvpi.a ../libveriuser/libveriuser.o
|
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
|
install: all installdirs $(vpidir)/cadpli.vpl
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
// These are correct and are used to find the base (zero) pin.
|
// These are correct and are used to find the base (zero) pin.
|
||||||
thisSubtraction:netlist.h:4168
|
thisSubtraction:netlist.h:4169
|
||||||
thisSubtraction:netlist.h:4177
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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);
|
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. */
|
/* Dump a net. This can be a wire or register. */
|
||||||
void NetNet::dump_net(ostream&o, unsigned ind) const
|
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:
|
case NetNet::PINOUT:
|
||||||
o << " inout";
|
o << " inout";
|
||||||
break;
|
break;
|
||||||
|
case NetNet::PREF:
|
||||||
|
o <<" ref";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ivl_discipline_t dis = get_discipline())
|
if (ivl_discipline_t dis = get_discipline())
|
||||||
o << " discipline=" << dis->name();
|
o << " discipline=" << dis->name();
|
||||||
|
|
||||||
|
o << " packed dims: " << packed_dims_;
|
||||||
|
|
||||||
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
|
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
|
||||||
if (scope())
|
if (scope())
|
||||||
o << " scope=" << scope_path(scope());
|
o << " scope=" << scope_path(scope());
|
||||||
|
|
@ -1045,8 +1059,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
|
||||||
if (result_sig_) {
|
if (result_sig_) {
|
||||||
o << setw(ind+2) << "" << "Return signal: ";
|
o << setw(ind+2) << "" << "Return signal: ";
|
||||||
if (result_sig_->get_signed()) o << "+";
|
if (result_sig_->get_signed()) o << "+";
|
||||||
o << result_sig_->name() << "[" << result_sig_->msb() << ":"
|
o << result_sig_->name() << result_sig_->packed_dims() << endl;
|
||||||
<< result_sig_->lsb() << "]" << endl;
|
|
||||||
}
|
}
|
||||||
o << setw(ind+2) << "" << "Arguments: ";
|
o << setw(ind+2) << "" << "Arguments: ";
|
||||||
if (port_count() == 0) o << "<none>";
|
if (port_count() == 0) o << "<none>";
|
||||||
|
|
@ -1068,8 +1081,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (port(idx)->get_signed()) o << "+";
|
if (port(idx)->get_signed()) o << "+";
|
||||||
o << port(idx)->name() << "[" << port(idx)->msb() << ":"
|
o << port(idx)->name() << port(idx)->packed_dims() << endl;
|
||||||
<< port(idx)->lsb() << "]" << endl;
|
|
||||||
}
|
}
|
||||||
if (statement_)
|
if (statement_)
|
||||||
statement_->dump(o, ind+2);
|
statement_->dump(o, ind+2);
|
||||||
|
|
@ -1509,7 +1521,7 @@ void NetESignal::dump(ostream&o) const
|
||||||
o << "+";
|
o << "+";
|
||||||
o << name();
|
o << name();
|
||||||
if (word_) o << "[word=" << *word_ << "]";
|
if (word_) o << "[word=" << *word_ << "]";
|
||||||
o << "[" << msi()<<":"<<lsi() << "]";
|
o << sig()->packed_dims();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetETernary::dump(ostream&o) const
|
void NetETernary::dump(ostream&o) const
|
||||||
|
|
|
||||||
|
|
@ -79,11 +79,13 @@ dep:
|
||||||
iverilog@EXEEXT@: $O
|
iverilog@EXEEXT@: $O
|
||||||
$(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@ @EXTRALIBS@
|
$(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@ @EXTRALIBS@
|
||||||
|
|
||||||
cflexor.c: cflexor.lex
|
cflexor.c: $(srcdir)/cflexor.lex
|
||||||
$(LEX) -s -ocflexor.c $(srcdir)/cflexor.lex
|
$(LEX) -s -t $< > $@
|
||||||
|
|
||||||
cfparse.h cfparse.c: cfparse.y
|
# Build this in two steps to avoid parallel build issues (see pr3462585)
|
||||||
$(YACC) --verbose -t -d -o cfparse.c --name-prefix=cf $(srcdir)/cfparse.y
|
cfparse.c: $(srcdir)/cfparse.y
|
||||||
|
$(YACC) --verbose -t -p cf -d -o $@ $<
|
||||||
|
cfparse.h: cfparse.c
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
$(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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
# include "netenum.h"
|
# include "netenum.h"
|
||||||
# include "discipline.h"
|
# include "discipline.h"
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
|
# include "netstruct.h"
|
||||||
# include "util.h"
|
# include "util.h"
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
|
|
@ -1418,6 +1419,50 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
|
||||||
return sys_expr;
|
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,
|
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||||
unsigned expr_wid, unsigned flags) const
|
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? If so then check to see if this is an
|
||||||
// enumeration method call.
|
// enumeration method call.
|
||||||
if (net != 0) {
|
if (net != 0) {
|
||||||
netenum_t*netenum = net->enumeration();
|
if (netenum_t*netenum = net->enumeration()) {
|
||||||
if (netenum) {
|
|
||||||
// We may need the net expression for the
|
// We may need the net expression for the
|
||||||
// enumeration variable so get it.
|
// enumeration variable so get it.
|
||||||
NetESignal*expr = new NetESignal(net);
|
NetESignal*expr = new NetESignal(net);
|
||||||
|
|
@ -1472,6 +1516,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||||
expr_wid, tmp,
|
expr_wid, tmp,
|
||||||
parms_.size());
|
parms_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1823,6 +1868,17 @@ NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
|
||||||
return tmp;
|
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
|
* Given that the msb_ and lsb_ are part select expressions, this
|
||||||
* function calculates their values. Note that this method does *not*
|
* 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;
|
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
|
// If there is a part/bit select expression, then process it
|
||||||
// here. This constrains the results no matter what kind the
|
// 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_;
|
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
|
// Not a net, and not a parameter? Give up on the type, but
|
||||||
// set the width to 0.
|
// set the width to 0.
|
||||||
expr_type_ = IVL_VT_NO_TYPE;
|
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? If so then check to see if this is an
|
||||||
// enumeration method call.
|
// enumeration method call.
|
||||||
if (net != 0) {
|
if (net != 0) {
|
||||||
netenum_t*netenum = net->enumeration();
|
// If this net is actually an enum, the method may
|
||||||
if (netenum) {
|
// be an enumeration method.
|
||||||
|
if (netenum_t*netenum = net->enumeration()) {
|
||||||
// We may need the net expression for the
|
// We may need the net expression for the
|
||||||
// enumeration variable so get it.
|
// enumeration variable so get it.
|
||||||
NetESignal*expr = new NetESignal(net);
|
NetESignal*expr = new NetESignal(net);
|
||||||
|
|
@ -2303,6 +2392,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||||
use_path, method_name,
|
use_path, method_name,
|
||||||
expr, expr_wid, NULL, 0);
|
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,
|
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb,
|
const NetExpr*par_lsb,
|
||||||
bool need_const) const
|
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);
|
base = normalize_variable_base(base, par_msv, par_lsv, wid, true);
|
||||||
|
|
||||||
NetExpr*tmp = par->dup_expr();
|
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 = new NetESelect(tmp, base, wid, IVL_SEL_IDX_UP);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
return tmp;
|
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,
|
NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
|
||||||
const NetExpr*par,
|
const NetExpr*par,
|
||||||
NetScope*,
|
NetScope*found_in,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb,
|
const NetExpr*par_lsb,
|
||||||
bool need_const) const
|
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);
|
base = normalize_variable_base(base, par_msv, par_lsv, wid, false);
|
||||||
|
|
||||||
NetExpr*tmp = par->dup_expr();
|
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 = new NetESelect(tmp, base, wid, IVL_SEL_IDX_DOWN);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
return tmp;
|
return tmp;
|
||||||
|
|
@ -2748,8 +2859,14 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
||||||
// rewritten in the above format, as I get to it.
|
// rewritten in the above format, as I get to it.
|
||||||
|
|
||||||
NetExpr*tmp = par->dup_expr();
|
NetExpr*tmp = par->dup_expr();
|
||||||
if (!tmp)
|
if (!tmp) return 0;
|
||||||
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) {
|
if (use_sel == index_component_t::SEL_BIT) {
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
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));
|
NetEConst*re2 = new NetEConst(verinum(rb, 1));
|
||||||
|
re2->set_line(*this);
|
||||||
delete tmp;
|
delete tmp;
|
||||||
delete mtmp;
|
delete mtmp;
|
||||||
tmp = re2;
|
tmp = re2;
|
||||||
|
|
@ -2911,7 +3029,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp->set_line(*this);
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3041,6 +3158,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||||
NetESignal*net, NetScope*,
|
NetESignal*net, NetScope*,
|
||||||
unsigned expr_wid) const
|
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;
|
long msv, lsv;
|
||||||
bool parts_defined_flag;
|
bool parts_defined_flag;
|
||||||
bool flag = calculate_parts_(des, scope, msv, lsv, 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);
|
tmp->set_line(*this);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
long sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv);
|
||||||
long sb_lsb = net->sig()->sb_to_idx(lsv);
|
long sb_msb = net->sig()->sb_to_idx(prefix_indices, msv);
|
||||||
long sb_msb = net->sig()->sb_to_idx(msv);
|
|
||||||
|
|
||||||
if (sb_msb < sb_lsb) {
|
if (sb_msb < sb_lsb) {
|
||||||
cerr << get_fileline() << ": error: part select " << net->name();
|
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*,
|
NetESignal*net, NetScope*,
|
||||||
bool need_const) const
|
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);
|
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
|
||||||
|
|
||||||
unsigned long wid = 0;
|
unsigned long wid = 0;
|
||||||
|
|
@ -3160,27 +3284,32 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||||
NetExpr*ex;
|
NetExpr*ex;
|
||||||
if (base_c->value().is_defined()) {
|
if (base_c->value().is_defined()) {
|
||||||
long lsv = base_c->value().as_long();
|
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
|
// If the part select covers exactly the entire
|
||||||
// vector, then do not bother with it. Return the
|
// vector, then do not bother with it. Return the
|
||||||
// signal itself.
|
// signal itself.
|
||||||
if (net->sig()->sb_to_idx(lsv) == 0 &&
|
if (rel_base == 0 && wid == net->vector_width()) {
|
||||||
wid == net->vector_width()) {
|
|
||||||
delete base;
|
delete base;
|
||||||
net->cast_signed(false);
|
net->cast_signed(false);
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
long offset = 0;
|
|
||||||
if (net->msi() < net->lsi()) {
|
|
||||||
offset = -wid + 1;
|
|
||||||
}
|
|
||||||
// Otherwise, make a part select that covers the right
|
// Otherwise, make a part select that covers the right
|
||||||
// range.
|
// range.
|
||||||
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
|
ex = new NetEConst(verinum(rel_base + offset));
|
||||||
offset));
|
|
||||||
if (warn_ob_select) {
|
if (warn_ob_select) {
|
||||||
long rel_base = net->sig()->sb_to_idx(lsv) + offset;
|
|
||||||
if (rel_base < 0) {
|
if (rel_base < 0) {
|
||||||
cerr << get_fileline() << ": warning: "
|
cerr << get_fileline() << ": warning: "
|
||||||
<< net->name();
|
<< net->name();
|
||||||
|
|
@ -3216,7 +3345,12 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||||
return ss;
|
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);
|
NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
@ -3236,6 +3370,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
||||||
NetESignal*net, NetScope*,
|
NetESignal*net, NetScope*,
|
||||||
bool need_const) const
|
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);
|
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
|
||||||
|
|
||||||
unsigned long wid = 0;
|
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
|
// If the part select covers exactly the entire
|
||||||
// vector, then do not bother with it. Return the
|
// vector, then do not bother with it. Return the
|
||||||
// signal itself.
|
// 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()) {
|
wid == net->vector_width()) {
|
||||||
delete base;
|
delete base;
|
||||||
net->cast_signed(false);
|
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
|
// Otherwise, make a part select that covers the right
|
||||||
// range.
|
// range.
|
||||||
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
|
ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset));
|
||||||
offset));
|
|
||||||
if (warn_ob_select) {
|
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) {
|
if (rel_base < 0) {
|
||||||
cerr << get_fileline() << ": warning: "
|
cerr << get_fileline() << ": warning: "
|
||||||
<< net->name();
|
<< net->name();
|
||||||
|
|
@ -3321,6 +3458,10 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
NetESignal*net, NetScope*,
|
NetESignal*net, NetScope*,
|
||||||
bool need_const) const
|
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();
|
const name_component_t&name_tail = path_.back();
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
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.msb != 0);
|
||||||
ivl_assert(*this, index_tail.lsb == 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
|
// If the bit select is constant, then treat it similar
|
||||||
// to the part select, so that I save the effort of
|
// to the part select, so that I save the effort of
|
||||||
// making a mux part in the netlist.
|
// 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
|
// Special case: The bit select expression is constant
|
||||||
// x/z. The result of the expression is 1'bx.
|
// 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);
|
NetEConst*tmp = make_const_x(1);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
delete ex;
|
delete mux;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
long msv = msc->value().as_long();
|
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) {
|
if (idx >= (long)net->vector_width() || idx < 0) {
|
||||||
/* The bit select is out of range of the
|
/* 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 ";
|
else cerr << "vector ";
|
||||||
cerr << net->name();
|
cerr << net->name();
|
||||||
if (net->word_index()) cerr << "[]";
|
if (net->word_index()) cerr << "[]";
|
||||||
cerr << "[" << net->sig()->msb() << ":"
|
cerr << net->sig()->packed_dims() << "." << endl;
|
||||||
<< net->sig()->lsb() << "]." << endl;
|
|
||||||
cerr << get_fileline() << ": : "
|
cerr << get_fileline() << ": : "
|
||||||
<< "Replacing select with a constant 1'bx."
|
<< "Replacing select with a constant 1'bx."
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
@ -3385,7 +3548,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
NetEConst*tmp = make_const_x(1);
|
NetEConst*tmp = make_const_x(1);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
|
|
||||||
delete ex;
|
delete mux;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3405,15 +3568,35 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
return res;
|
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
|
// Non-constant bit select? punt and make a subsignal
|
||||||
// device to mux the bit in the net. This is a fairly
|
// device to mux the bit in the net. This is a fairly
|
||||||
// complicated task because we need to generate
|
// complicated task because we need to generate
|
||||||
// expressions to convert calculated bit select
|
// expressions to convert calculated bit select
|
||||||
// values to canonical values that are used internally.
|
// values to canonical values that are used internally.
|
||||||
ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(),
|
mux = normalize_variable_bit_base(prefix_indices, mux, net->sig());
|
||||||
1, true);
|
|
||||||
|
|
||||||
NetESelect*ss = new NetESelect(net, ex, 1);
|
NetESelect*ss = new NetESelect(net, mux, 1);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
@ -3446,6 +3629,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
|
||||||
return 0;
|
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
|
// If this is a part select of a signal, then make a new
|
||||||
// temporary signal that is connected to just the
|
// temporary signal that is connected to just the
|
||||||
// selected bits. The lsb_ and msb_ expressions are from
|
// 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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
# include "PExpr.h"
|
# include "PExpr.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
|
# include "netstruct.h"
|
||||||
# include "compiler.h"
|
# include "compiler.h"
|
||||||
# include <cstdlib>
|
# include <cstdlib>
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
|
@ -152,8 +153,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
NetNet* reg = 0;
|
NetNet* reg = 0;
|
||||||
const NetExpr*par = 0;
|
const NetExpr*par = 0;
|
||||||
NetEvent* eve = 0;
|
NetEvent* eve = 0;
|
||||||
|
perm_string method_name;
|
||||||
|
|
||||||
symbol_search(this, des, scope, path_, reg, par, eve);
|
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) {
|
if (reg == 0) {
|
||||||
cerr << get_fileline() << ": error: Could not find variable ``"
|
cerr << get_fileline() << ": error: Could not find variable ``"
|
||||||
<< path_ << "'' in ``" << scope_path(scope) <<
|
<< path_ << "'' in ``" << scope_path(scope) <<
|
||||||
|
|
@ -164,16 +183,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
}
|
}
|
||||||
|
|
||||||
ivl_assert(*this, reg);
|
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();
|
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;
|
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||||
if (!name_tail.index.empty())
|
if (!name_tail.index.empty())
|
||||||
use_sel = name_tail.index.back().sel;
|
use_sel = name_tail.index.back().sel;
|
||||||
|
|
||||||
// This is the special case that the l-value is an entire
|
// Special case: The l-value is an entire memory, or array
|
||||||
// memory. This is, in fact, an error.
|
// slice. This is, in fact, an error in l-values. Detect the
|
||||||
if (reg->array_dimensions() > 0 && name_tail.index.empty()) {
|
// 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 "
|
cerr << get_fileline() << ": error: Cannot assign to array "
|
||||||
<< path_ << ". Did you forget a word index?" << endl;
|
<< path_ << ". Did you forget a word index?" << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
@ -181,7 +210,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the signal referenced by the identifier, and make sure
|
/* 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. */
|
unless this is the l-value of a force. */
|
||||||
if ((reg->type() != NetNet::REG) && !is_force) {
|
if ((reg->type() != NetNet::REG) && !is_force) {
|
||||||
cerr << get_fileline() << ": error: " << path_ <<
|
cerr << get_fileline() << ": error: " << path_ <<
|
||||||
|
|
@ -193,6 +222,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
return 0;
|
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)
|
if (reg->array_dimensions() > 0)
|
||||||
return elaborate_lval_net_word_(des, scope, reg);
|
return elaborate_lval_net_word_(des, scope, reg);
|
||||||
|
|
||||||
|
|
@ -322,7 +357,13 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetAssign_*lv) const
|
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();
|
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();
|
const index_component_t&index_tail = name_tail.index.back();
|
||||||
ivl_assert(*this, index_tail.msb != 0);
|
ivl_assert(*this, index_tail.msb != 0);
|
||||||
ivl_assert(*this, index_tail.lsb == 0);
|
ivl_assert(*this, index_tail.lsb == 0);
|
||||||
|
|
@ -340,20 +381,43 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
mux = 0;
|
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);
|
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
|
// Constant bit mux that happens to select the only bit
|
||||||
// of the l-value. Don't bother with any select at all.
|
// of the l-value. Don't bother with any select at all.
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Constant bit select that does something useful.
|
// 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()) {
|
if (loff < 0 || loff >= (long)reg->vector_width()) {
|
||||||
cerr << get_fileline() << ": error: bit select "
|
cerr << get_fileline() << ": error: bit select "
|
||||||
|
|
@ -373,6 +437,10 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetAssign_*lv) const
|
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
|
// The range expressions of a part select must be
|
||||||
// constant. The calculate_parts_ function calculates the
|
// constant. The calculate_parts_ function calculates the
|
||||||
// values into msb and lsb.
|
// values into msb and lsb.
|
||||||
|
|
@ -385,41 +453,50 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
ivl_assert(*this, parts_defined_flag);
|
ivl_assert(*this, parts_defined_flag);
|
||||||
|
|
||||||
NetNet*reg = lv->sig();
|
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. */
|
// Part selects cannot select slices. So there must be enough
|
||||||
|
// prefix_indices to get all the way to the final dimension.
|
||||||
} else {
|
if (prefix_indices.size()+1 < packed.size()) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot select a range "
|
||||||
/* Get the canonical offsets into the vector. */
|
<< "of slices from a packed array." << endl;
|
||||||
long loff = reg->sb_to_idx(lsb);
|
des->errors += 1;
|
||||||
long moff = reg->sb_to_idx(msb);
|
return false;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,6 +505,10 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
||||||
NetAssign_*lv,
|
NetAssign_*lv,
|
||||||
index_component_t::ctype_t use_sel) const
|
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();;
|
const name_component_t&name_tail = path_.back();;
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
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()) {
|
if (base_c->value().is_defined()) {
|
||||||
long lsv = base_c->value().as_long();
|
long lsv = base_c->value().as_long();
|
||||||
long offset = 0;
|
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) ||
|
use_sel == index_component_t::SEL_IDX_UP) ||
|
||||||
((reg->msb() > reg->lsb()) &&
|
((rng.msb > rng.lsb) &&
|
||||||
use_sel == index_component_t::SEL_IDX_DO)) {
|
use_sel == index_component_t::SEL_IDX_DO)) {
|
||||||
offset = -wid + 1;
|
offset = -wid + 1;
|
||||||
}
|
}
|
||||||
delete base;
|
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 we cover the entire lvalue just skip the select. */
|
||||||
if (rel_base == 0 && wid == reg->vector_width()) return true;
|
if (rel_base == 0 && wid == reg->vector_width()) return true;
|
||||||
base = new NetEConst(verinum(rel_base));
|
base = new NetEConst(verinum(rel_base));
|
||||||
|
|
@ -511,15 +598,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size());
|
||||||
/* Correct the mux for the range of the vector. */
|
/* Correct the mux for the range of the vector. */
|
||||||
if (use_sel == index_component_t::SEL_IDX_UP) {
|
if (use_sel == index_component_t::SEL_IDX_UP) {
|
||||||
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
|
base = normalize_variable_part_base(prefix_indices, base,
|
||||||
wid, true);
|
reg, wid, true);
|
||||||
sel_type = IVL_SEL_IDX_UP;
|
sel_type = IVL_SEL_IDX_UP;
|
||||||
} else {
|
} else {
|
||||||
// This is assumed to be a SEL_IDX_DO.
|
// This is assumed to be a SEL_IDX_DO.
|
||||||
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
|
base = normalize_variable_part_base(prefix_indices, base,
|
||||||
wid, false);
|
reg, wid, false);
|
||||||
sel_type = IVL_SEL_IDX_DOWN;
|
sel_type = IVL_SEL_IDX_DOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -533,6 +621,38 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
||||||
return true;
|
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
|
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
|
||||||
{
|
{
|
||||||
cerr << get_fileline() << ": error: Constant values not allowed "
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
# include "PExpr.h"
|
# include "PExpr.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
|
# include "netstruct.h"
|
||||||
# include "compiler.h"
|
# include "compiler.h"
|
||||||
|
|
||||||
# include <cstdlib>
|
# 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,
|
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
long&midx, long&lidx) const
|
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();
|
const name_component_t&name_tail = path_.back();
|
||||||
// Only treat as part/bit selects any index that is beyond the
|
// Only treat as part/bit selects any index that is beyond the
|
||||||
// word selects for an array. This is not an array, then
|
// 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();
|
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;
|
delete tmp_ex;
|
||||||
|
|
||||||
if (index_tail.sel == index_component_t::SEL_IDX_UP)
|
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
|
else
|
||||||
lidx = sig->sb_to_idx(midx_val-wid+1);
|
lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1);
|
||||||
|
|
||||||
if (midx < lidx) {
|
if (midx < lidx) {
|
||||||
long tmpx = midx;
|
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);
|
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
|
||||||
ivl_assert(*this, part_defined_flag);
|
ivl_assert(*this, part_defined_flag);
|
||||||
|
|
||||||
long lidx_tmp = sig->sb_to_idx(lsb);
|
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
|
||||||
long midx_tmp = sig->sb_to_idx(msb);
|
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
|
||||||
/* Detect reversed indices of a part select. */
|
/* Detect reversed indices of a part select. */
|
||||||
if (lidx_tmp > midx_tmp) {
|
if (lidx_tmp > midx_tmp) {
|
||||||
cerr << get_fileline() << ": error: Part select "
|
cerr << get_fileline() << ": error: Part select "
|
||||||
|
|
@ -369,7 +374,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
}
|
}
|
||||||
assert(mval);
|
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()) {
|
if (midx >= (long)sig->vector_width()) {
|
||||||
cerr << get_fileline() << ": error: Index " << sig->name()
|
cerr << get_fileline() << ": error: Index " << sig->name()
|
||||||
<< "[" << mval->as_long() << "] is out of range."
|
<< "[" << mval->as_long() << "] is out of range."
|
||||||
|
|
@ -405,6 +410,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
NetNet* sig = 0;
|
NetNet* sig = 0;
|
||||||
const NetExpr*par = 0;
|
const NetExpr*par = 0;
|
||||||
NetEvent* eve = 0;
|
NetEvent* eve = 0;
|
||||||
|
perm_string method_name;
|
||||||
|
|
||||||
symbol_search(this, des, scope, path_, sig, par, eve);
|
symbol_search(this, des, scope, path_, sig, par, eve);
|
||||||
|
|
||||||
|
|
@ -416,6 +422,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
return 0;
|
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) {
|
if (sig == 0) {
|
||||||
cerr << get_fileline() << ": error: Net " << path_
|
cerr << get_fileline() << ": error: Net " << path_
|
||||||
<< " is not defined in this context." << endl;
|
<< " 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);
|
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. */
|
/* Don't allow registers as assign l-values. */
|
||||||
if (sig->type() == NetNet::REG) {
|
if (sig->type() == NetNet::REG) {
|
||||||
cerr << get_fileline() << ": error: reg " << sig->name()
|
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();
|
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()) {
|
if (name_tail.index.empty()) {
|
||||||
cerr << get_fileline() << ": error: array " << sig->name()
|
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;
|
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 (sig->pin_count() > 1) {
|
||||||
if (widx < 0 || widx >= (long) sig->pin_count()) {
|
if (widx < 0 || widx >= (long) sig->pin_count()) {
|
||||||
cerr << get_fileline() << ": warning: ignoring out of "
|
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::PINPUT:
|
||||||
case NetNet::POUTPUT:
|
case NetNet::POUTPUT:
|
||||||
case NetNet::PINOUT:
|
case NetNet::PINOUT:
|
||||||
|
case NetNet::PREF:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* If the name matches, but the signal is not a port,
|
/* 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;
|
sig = tmp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NetNet::PREF:
|
||||||
|
// For the purposes of module ports, treat ref ports
|
||||||
|
// just like inout ports.
|
||||||
case NetNet::PINOUT:
|
case NetNet::PINOUT:
|
||||||
ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(),
|
ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(),
|
||||||
swid, lidx);
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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)
|
enum_type_t*enum_type)
|
||||||
{
|
{
|
||||||
bool rc_flag;
|
bool rc_flag;
|
||||||
assert(enum_type->range->size() == 2);
|
assert(enum_type->range->size() == 1);
|
||||||
NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1);
|
pform_range_t&range = enum_type->range->front();
|
||||||
NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1);
|
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;
|
long msb = 0;
|
||||||
rc_flag = eval_as_long(msb, msb_ex);
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
# include "compiler.h"
|
# include "compiler.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
|
# include "netstruct.h"
|
||||||
# include "util.h"
|
# include "util.h"
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
|
|
@ -84,6 +85,14 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
|
||||||
PWire*cur = (*wt).second;
|
PWire*cur = (*wt).second;
|
||||||
NetNet*sig = cur->elaborate_sig(des, scope);
|
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
|
/* If the signal is an input and is also declared as a
|
||||||
reg, then report an error. */
|
reg, then report an error. */
|
||||||
|
|
@ -467,14 +476,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
case PTF_REG:
|
case PTF_REG:
|
||||||
case PTF_REG_S:
|
case PTF_REG_S:
|
||||||
if (return_type_.range) {
|
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,
|
NetExpr*me = elab_and_eval(des, scope,
|
||||||
return_type_.range->at(0), -1,
|
return_range.first, -1,
|
||||||
true);
|
true);
|
||||||
assert(me);
|
assert(me);
|
||||||
NetExpr*le = elab_and_eval(des, scope,
|
NetExpr*le = elab_and_eval(des, scope,
|
||||||
return_type_.range->at(1), -1,
|
return_range.second, -1,
|
||||||
true);
|
true);
|
||||||
assert(le);
|
assert(le);
|
||||||
|
|
||||||
|
|
@ -493,7 +503,9 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
des->errors += 1;
|
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);
|
ret_sig->set_scalar(false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -539,17 +551,18 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
|
|
||||||
case PTF_ATOM2:
|
case PTF_ATOM2:
|
||||||
case PTF_ATOM2_S:
|
case PTF_ATOM2_S:
|
||||||
ivl_assert(*this, return_type_.range != 0);
|
|
||||||
long use_wid;
|
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,
|
NetExpr*me = elab_and_eval(des, scope,
|
||||||
(*return_type_.range)[0], -1,
|
return_range.first, -1,
|
||||||
true);
|
true);
|
||||||
assert(me);
|
ivl_assert(*this, me);
|
||||||
NetExpr*le = elab_and_eval(des, scope,
|
NetExpr*le = elab_and_eval(des, scope,
|
||||||
(*return_type_.range)[1], -1,
|
return_range.second, -1,
|
||||||
true);
|
true);
|
||||||
assert(le);
|
ivl_assert(*this, le);
|
||||||
|
|
||||||
long mnum = 0, lnum = 0;
|
long mnum = 0, lnum = 0;
|
||||||
if ( ! get_const_argument(me, mnum) ) {
|
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);
|
ret_sig->data_type(IVL_VT_BOOL);
|
||||||
break;
|
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:
|
default:
|
||||||
if (ports_) {
|
if (ports_) {
|
||||||
cerr << get_fileline() << ": internal error: I don't know "
|
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);
|
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,
|
* Elaborate a source wire. The "wire" is the declaration of wires,
|
||||||
* registers, ports and memories. The parser has already merged the
|
* 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;
|
unsigned wid = 1;
|
||||||
long lsb = 0, msb = 0;
|
list<NetNet::range_t>packed_dimensions;
|
||||||
|
|
||||||
des->errors += error_cnt_;
|
des->errors += error_cnt_;
|
||||||
|
|
||||||
|
|
@ -841,135 +971,74 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port_set_ || net_set_) {
|
if (port_set_ || net_set_) {
|
||||||
long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0;
|
bool bad_range = false;
|
||||||
bool bad_lsb = false, bad_msb = false;
|
list<NetNet::range_t> plist, nlist;
|
||||||
/* If they exist get the port definition MSB and LSB */
|
/* If they exist get the port definition MSB and LSB */
|
||||||
if (port_set_ && port_msb_ != 0) {
|
if (port_set_ && !port_.empty()) {
|
||||||
NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true);
|
bad_range |= evaluate_ranges(des, scope, plist, port_);
|
||||||
|
nlist = plist;
|
||||||
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;
|
|
||||||
/* An implicit port can have a range so note that here. */
|
/* An implicit port can have a range so note that here. */
|
||||||
is_implicit_scalar = false;
|
is_implicit_scalar = false;
|
||||||
}
|
}
|
||||||
if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0);
|
assert(port_set_ || port_.empty());
|
||||||
if (port_msb_ == 0) assert(port_lsb_ == 0);
|
|
||||||
if (port_lsb_ == 0) assert(port_msb_ == 0);
|
|
||||||
|
|
||||||
/* If they exist get the net/etc. definition MSB and LSB */
|
/* If they exist get the net/etc. definition MSB and LSB */
|
||||||
if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) {
|
if (net_set_ && !net_.empty() && !bad_range) {
|
||||||
NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true);
|
nlist.clear();
|
||||||
|
bad_range |= evaluate_ranges(des, scope, nlist, net_);
|
||||||
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_) assert(net_msb_ == 0 && net_lsb_ == 0);
|
assert(net_set_ || net_.empty());
|
||||||
if (net_msb_ == 0) assert(net_lsb_ == 0);
|
|
||||||
if (net_lsb_ == 0) assert(net_msb_ == 0);
|
/* If we find errors here, then give up on this signal. */
|
||||||
|
if (bad_range)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* We have a port size error */
|
/* 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 */
|
/* Scalar port with a vector net/etc. definition */
|
||||||
if (port_msb_ == 0) {
|
if (port_.empty()) {
|
||||||
if (!gn_io_range_error_flag) {
|
if (!gn_io_range_error_flag) {
|
||||||
cerr << get_fileline()
|
cerr << get_fileline()
|
||||||
<< ": warning: Scalar port ``" << name_
|
<< ": warning: Scalar port ``" << name_
|
||||||
<< "'' has a vectored net declaration ["
|
<< "'' has a vectored net declaration "
|
||||||
<< nmsb << ":" << nlsb << "]." << endl;
|
<< nlist << "." << endl;
|
||||||
} else {
|
} else {
|
||||||
cerr << get_fileline()
|
cerr << get_fileline()
|
||||||
<< ": error: Scalar port ``" << name_
|
<< ": error: Scalar port ``" << name_
|
||||||
<< "'' has a vectored net declaration ["
|
<< "'' has a vectored net declaration "
|
||||||
<< nmsb << ":" << nlsb << "]." << endl;
|
<< nlist << "." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vectored port with a scalar net/etc. definition */
|
/* Vectored port with a scalar net/etc. definition */
|
||||||
if (net_msb_ == 0) {
|
if (net_.empty()) {
|
||||||
cerr << port_msb_->get_fileline()
|
cerr << port_.front().first->get_fileline()
|
||||||
<< ": error: Vectored port ``"
|
<< ": error: Vectored port ``"
|
||||||
<< name_ << "'' [" << pmsb << ":" << plsb
|
<< name_ << "'' " << plist
|
||||||
<< "] has a scalar net declaration at "
|
<< " has a scalar net declaration at "
|
||||||
<< get_fileline() << "." << endl;
|
<< get_fileline() << "." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Both vectored, but they have different ranges. */
|
/* Both vectored, but they have different ranges. */
|
||||||
if (port_msb_ != 0 && net_msb_ != 0) {
|
if (!port_.empty() && !net_.empty()) {
|
||||||
cerr << port_msb_->get_fileline()
|
cerr << port_.front().first->get_fileline()
|
||||||
<< ": error: Vectored port ``"
|
<< ": error: Vectored port ``"
|
||||||
<< name_ << "'' [" << pmsb << ":" << plsb
|
<< name_ << "'' " << plist
|
||||||
<< "] has a net declaration [" << nmsb << ":"
|
<< " has a net declaration " << nlist
|
||||||
<< nlsb << "] at " << net_msb_->get_fileline()
|
<< " at " << net_.front().first->get_fileline()
|
||||||
<< " that does not match." << endl;
|
<< " that does not match." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to recover from errors. */
|
packed_dimensions = nlist;
|
||||||
if (bad_lsb) nlsb = 0;
|
wid = NetNet::vector_width(packed_dimensions);
|
||||||
if (bad_msb) nmsb = nlsb;
|
|
||||||
|
|
||||||
lsb = nlsb;
|
|
||||||
msb = nmsb;
|
|
||||||
if (nmsb > nlsb)
|
|
||||||
wid = nmsb - nlsb + 1;
|
|
||||||
else
|
|
||||||
wid = nlsb - nmsb + 1;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1021,13 +1090,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
array_dimensions = 1;
|
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 ";
|
cerr << get_fileline() << ": error: real ";
|
||||||
if (wtype == NetNet::REG) cerr << "variable";
|
if (wtype == NetNet::REG) cerr << "variable";
|
||||||
else cerr << "net";
|
else cerr << "net";
|
||||||
cerr << " '" << name_
|
cerr << " '" << name_
|
||||||
<< "' cannot be declared as a vector, found a range ["
|
<< "' cannot be declared as a vector, found a range "
|
||||||
<< msb << ":" << lsb << "]." << endl;
|
<< packed_dimensions << "." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
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;
|
NetNet*sig = 0;
|
||||||
if (!get_scalar()) {
|
|
||||||
cerr << " ["<<msb<<":"<<lsb<<"]";
|
// 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) {
|
sig = new NetNet(scope, name_, wtype, use_type);
|
||||||
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
|
|
||||||
|
} 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
|
// If this is an enumeration, then set the enumeration set for
|
||||||
// the new signal. This turns it into an enumeration.
|
// the new signal. This turns it into an enumeration.
|
||||||
if (enum_type_) {
|
if (enum_type_) {
|
||||||
|
ivl_assert(*this, struct_type_ == 0);
|
||||||
ivl_assert(*this, ! enum_type_->names->empty());
|
ivl_assert(*this, ! enum_type_->names->empty());
|
||||||
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
|
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
|
||||||
netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);
|
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;
|
<< "tran device." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
} else {
|
} else {
|
||||||
gate = new NetTran(scope, inst_name, IVL_SW_TRAN);
|
gate = new NetTran(scope, inst_name, IVL_SW_TRAN,
|
||||||
|
instance_width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -534,7 +535,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
|
||||||
<< "rtran device." << endl;
|
<< "rtran device." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
} else {
|
} else {
|
||||||
gate = new NetTran(scope, inst_name, IVL_SW_RTRAN);
|
gate = new NetTran(scope, inst_name, IVL_SW_RTRAN,
|
||||||
|
instance_width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -544,7 +546,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
|
||||||
<< "tranif0 device." << endl;
|
<< "tranif0 device." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
} else {
|
} else {
|
||||||
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0);
|
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0,
|
||||||
|
instance_width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -554,7 +557,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
|
||||||
<< "rtranif0 device." << endl;
|
<< "rtranif0 device." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
} else {
|
} else {
|
||||||
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0);
|
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0,
|
||||||
|
instance_width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -564,7 +568,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
|
||||||
<< "tranif1 device." << endl;
|
<< "tranif1 device." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
} else {
|
} else {
|
||||||
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1);
|
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1,
|
||||||
|
instance_width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -574,7 +579,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
|
||||||
<< "rtranif1 device." << endl;
|
<< "rtranif1 device." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
} else {
|
} else {
|
||||||
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1);
|
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1,
|
||||||
|
instance_width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1063,6 +1069,10 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||||
ivl_assert(*this, 0);
|
ivl_assert(*this, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NetNet::PREF:
|
||||||
|
ivl_assert(*this, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ivl_assert(*this, 0);
|
ivl_assert(*this, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -1500,6 +1510,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Port type must be OUTPUT here. */
|
/* Port type must be OUTPUT here. */
|
||||||
|
ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT);
|
||||||
|
|
||||||
/* Output from module. Elaborate the port
|
/* Output from module. Elaborate the port
|
||||||
expression as the l-value of a continuous
|
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! */
|
/* This may not be correct! */
|
||||||
as_signed = prts[0]->get_signed() && sig->get_signed();
|
as_signed = prts[0]->get_signed() && sig->get_signed();
|
||||||
break;
|
break;
|
||||||
|
case NetNet::PREF:
|
||||||
|
ivl_assert(*this, 0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ivl_assert(*this, 0);
|
ivl_assert(*this, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -1780,6 +1794,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NetNet::PREF:
|
||||||
|
cerr << get_fileline() << ": sorry: "
|
||||||
|
<< "Reference ports not supported yet." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case NetNet::PIMPLICIT:
|
case NetNet::PIMPLICIT:
|
||||||
cerr << get_fileline() << ": internal error: "
|
cerr << get_fileline() << ": internal error: "
|
||||||
<< "Unexpected IMPLICIT port" << endl;
|
<< "Unexpected IMPLICIT port" << endl;
|
||||||
|
|
@ -2805,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned parm_count = nparms();
|
unsigned parm_count = parms_.size();
|
||||||
|
|
||||||
/* Catch the special case that the system task has no
|
/* Catch the special case that the system task has no
|
||||||
parameters. The "()" string will be parsed as a single
|
parameters. The "()" string will be parsed as a single
|
||||||
empty parameter, when we really mean no parameters at all. */
|
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;
|
parm_count = 0;
|
||||||
|
|
||||||
svector<NetExpr*>eparms (parm_count);
|
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_);
|
perm_string name = peek_tail_name(path_);
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||||
PExpr*ex = parm(idx);
|
PExpr*ex = parms_[idx];
|
||||||
if (ex != 0) {
|
if (ex != 0) {
|
||||||
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
|
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2910,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
}
|
}
|
||||||
assert(def);
|
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 ``"
|
cerr << get_fileline() << ": error: Port count mismatch in call to ``"
|
||||||
<< path_ << "''. Got " << nparms()
|
<< path_ << "''. Got " << parm_count
|
||||||
<< " ports, expecting " << def->port_count() << " ports." << endl;
|
<< " ports, expecting " << def->port_count() << " ports." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
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
|
/* Handle non-automatic tasks with no parameters specially. There is
|
||||||
no need to make a sequential block to hold the generated code. */
|
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 = new NetUTask(task);
|
||||||
cur->set_line(*this);
|
cur->set_line(*this);
|
||||||
return cur;
|
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
|
expression the r-value. We know by definition that the port
|
||||||
is a reg type, so this elaboration is pretty obvious. */
|
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);
|
NetNet*port = def->port(idx);
|
||||||
assert(port->port_type() != NetNet::NOT_A_PORT);
|
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);
|
unsigned wid = count_lval_width(lv);
|
||||||
ivl_variable_type_t lv_type = lv->expr_type();
|
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)) {
|
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
|
||||||
cerr << evt->get_fileline() << ": error: An event '"
|
cerr << evt->get_fileline() << ": error: An event '"
|
||||||
<< evt->event()->name() << "' can not be a user "
|
<< 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
|
expression that can be a target to a procedural
|
||||||
assignment, including a memory word. */
|
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);
|
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_);
|
const PEIdent*id1 = dynamic_cast<const PEIdent*>(name1_);
|
||||||
assert(id1);
|
assert(id1);
|
||||||
const PEIdent*id2 = dynamic_cast<const PEIdent*>(name2_);
|
|
||||||
assert(id2);
|
|
||||||
|
|
||||||
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
||||||
top->set_line(*this);
|
top->set_line(*this);
|
||||||
|
|
@ -3820,32 +3865,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
||||||
body->append(tmp);
|
body->append(tmp);
|
||||||
|
|
||||||
|
|
||||||
/* Elaborate the increment assignment statement at the end of
|
/* Now elaborate the for_step statement. I really should do
|
||||||
the for loop. This is also a very specific assignment
|
some error checking here to make sure the step statement
|
||||||
statement. Put this into the "body" block. */
|
really does step the variable. */
|
||||||
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_);
|
|
||||||
|
|
||||||
if (debug_elaborate) {
|
if (debug_elaborate) {
|
||||||
cerr << get_fileline() << ": debug: FOR increment assign: "
|
cerr << get_fileline() << ": debug: Elaborate for_step statement "
|
||||||
<< sig->name() << " = " << *etmp << endl;
|
<< sig->name() << " = " << *etmp << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetAssign*step = new NetAssign(lv, etmp);
|
NetProc*step = step_->elaborate(des, scope);
|
||||||
step->set_line(*this);
|
|
||||||
|
|
||||||
body->append(step);
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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_name
|
||||||
ivl_signal_nex
|
ivl_signal_nex
|
||||||
ivl_signal_npath
|
ivl_signal_npath
|
||||||
|
ivl_signal_packed_dimensions
|
||||||
|
ivl_signal_packed_lsb
|
||||||
|
ivl_signal_packed_msb
|
||||||
ivl_signal_path
|
ivl_signal_path
|
||||||
ivl_signal_port
|
ivl_signal_port
|
||||||
ivl_signal_scope
|
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
|
* If the signal has been declared with a domain (Verilog-AMS) then
|
||||||
* this function will return a non-nil ivl_discipline_t.
|
* this function will return a non-nil ivl_discipline_t.
|
||||||
*
|
*
|
||||||
* ivl_signal_msb
|
* ivl_signal_msb (deprecated)
|
||||||
* ivl_signal_lsb
|
* ivl_signal_lsb (deprecated)
|
||||||
|
* ivl_signal_packed_dimensions
|
||||||
|
* ivl_signal_packed_msb
|
||||||
|
* ivl_signal_packed_lsb
|
||||||
* ivl_signal_width
|
* ivl_signal_width
|
||||||
* These functions return the left and right indices, respectively,
|
* These functions return the msb and lsb packed indices. The
|
||||||
* of the signal. If the signal is a scalar, both return 0. However,
|
* packed dimensions are declared differently from array
|
||||||
* it doesn't mean that the signal is a scalar if both return 0, one
|
* dimensions, like so:
|
||||||
* can have a vector with 0 as both indices.
|
* 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
|
* ivl_signal_port
|
||||||
* If the signal is a port to a module, this function returns the
|
* 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_array_addr_swapped(ivl_signal_t net);
|
||||||
extern unsigned ivl_signal_dimensions(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 ivl_discipline_t ivl_signal_discipline(ivl_signal_t net);
|
||||||
extern int ivl_signal_msb(ivl_signal_t net);
|
extern unsigned ivl_signal_packed_dimensions(ivl_signal_t net);
|
||||||
extern int ivl_signal_lsb(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 unsigned ivl_signal_width(ivl_signal_t net);
|
||||||
extern ivl_signal_port_t ivl_signal_port(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);
|
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:
|
* is the compressed operator used it statements like this:
|
||||||
* foo += <expr>
|
* foo += <expr>
|
||||||
* The ivl_stmt_opcode() returns null (0) if this is not a compressed
|
* The ivl_stmt_opcode() returns null (0) if this is not a compressed
|
||||||
* assignment statment.
|
* assignment statement.
|
||||||
*
|
*
|
||||||
* - IVL_ST_CASSIGN
|
* - IVL_ST_CASSIGN
|
||||||
* This reflects a procedural continuous assignment to an l-value. The
|
* This reflects a procedural continuous assignment to an l-value. The
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ Makefile: $(srcdir)/Makefile.in ../config.status
|
||||||
ivlpp@EXEEXT@: $O
|
ivlpp@EXEEXT@: $O
|
||||||
$(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@
|
$(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@
|
||||||
|
|
||||||
lexor.c: lexor.lex
|
lexor.c: $(srcdir)/lexor.lex
|
||||||
$(LEX) -olexor.c $(srcdir)/lexor.lex
|
$(LEX) -t $< > $@
|
||||||
|
|
||||||
install: all installdirs $(libdir)/ivl$(suffix)/ivlpp@EXEEXT@
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
*/
|
*/
|
||||||
extern YYLTYPE yylloc;
|
extern YYLTYPE yylloc;
|
||||||
|
|
||||||
static char* strdupnew(char const *str)
|
char* strdupnew(char const *str)
|
||||||
{
|
{
|
||||||
return str ? strcpy(new char [strlen(str)+1], str) : 0;
|
return str ? strcpy(new char [strlen(str)+1], str) : 0;
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +191,7 @@ TU [munpf]
|
||||||
">>>=" { return K_RSS_EQ; }
|
">>>=" { return K_RSS_EQ; }
|
||||||
"++" { return K_INCR; }
|
"++" { return K_INCR; }
|
||||||
"--" {return K_DECR; }
|
"--" {return K_DECR; }
|
||||||
|
"'{" { return K_LP; }
|
||||||
|
|
||||||
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
|
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
|
||||||
and ")", but since I know that this is really ( * ), replace it
|
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);
|
perm_string tmp = lex_strings.make(yylval.text);
|
||||||
map<perm_string,ivl_discipline_t>::iterator cur = disciplines.find(tmp);
|
map<perm_string,ivl_discipline_t>::iterator cur = disciplines.find(tmp);
|
||||||
if (cur != disciplines.end()) {
|
if (cur != disciplines.end()) {
|
||||||
|
delete[]yylval.text;
|
||||||
yylval.discipline = (*cur).second;
|
yylval.discipline = (*cur).second;
|
||||||
rc = DISCIPLINE_IDENTIFIER;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,8 +377,11 @@ TU [munpf]
|
||||||
<< "Using SystemVerilog 'N bit vector. Use at least "
|
<< "Using SystemVerilog 'N bit vector. Use at least "
|
||||||
<< "-g2005-sv to remove this warning." << endl;
|
<< "-g2005-sv to remove this warning." << endl;
|
||||||
}
|
}
|
||||||
|
generation_t generation_save = generation_flag;
|
||||||
|
generation_flag = GN_VER2005_SV;
|
||||||
yylval.number = make_unsized_binary(yytext);
|
yylval.number = make_unsized_binary(yytext);
|
||||||
return BASED_NUMBER; }
|
generation_flag = generation_save;
|
||||||
|
return UNBASED_NUMBER; }
|
||||||
|
|
||||||
[0-9][0-9_]* {
|
[0-9][0-9_]* {
|
||||||
yylval.number = make_unsized_dec(yytext);
|
yylval.number = make_unsized_dec(yytext);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __LineInfo_H
|
#ifndef __LineInfo_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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
|
// Get a fully formatted file/lineno
|
||||||
string get_fileline() const;
|
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);
|
void set_line(const LineInfo&that);
|
||||||
|
|
||||||
// Access parts of LineInfo data
|
// Access parts of LineInfo data
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ endif
|
||||||
|
|
||||||
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
||||||
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
|
||||||
|
|
||||||
A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \
|
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 \
|
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);
|
cur->second->evaluate_parameters(des);
|
||||||
|
|
||||||
if (debug_scopes)
|
if (debug_scopes)
|
||||||
cerr << ":0" << ": debug: "
|
cerr << "debug: "
|
||||||
<< "Evaluate parameters in " << scope_path(this) << endl;
|
<< "Evaluating parameters in " << scope_path(this) << endl;
|
||||||
|
|
||||||
for (param_ref_t cur = parameters.begin()
|
for (param_ref_t cur = parameters.begin()
|
||||||
; cur != parameters.end() ; ++ cur) {
|
; cur != parameters.end() ; ++ cur) {
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ bool Nexus::assign_lval() const
|
||||||
if (net == 0)
|
if (net == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (net->peek_lref())
|
if (net->peek_lref() > 0)
|
||||||
return true;
|
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)
|
NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt,
|
||||||
: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt)
|
unsigned width)
|
||||||
|
: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt), wid_(width)
|
||||||
{
|
{
|
||||||
pin(0).set_dir(Link::PASSIVE);
|
pin(0).set_dir(Link::PASSIVE);
|
||||||
pin(1).set_dir(Link::PASSIVE);
|
pin(1).set_dir(Link::PASSIVE);
|
||||||
if (pin_count() == 3) {
|
if (pin_count() == 3) {
|
||||||
pin(2).set_dir(Link::INPUT); // Enable
|
pin(2).set_dir(Link::INPUT); // Enable
|
||||||
}
|
}
|
||||||
wid_ = 0;
|
|
||||||
part_ = 0;
|
part_ = 0;
|
||||||
off_ = 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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
# include "compiler.h"
|
# include "compiler.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
|
# include "netstruct.h"
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -450,12 +451,15 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
|
||||||
: NetObj(s, n, 1),
|
: NetObj(s, n, 1),
|
||||||
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
|
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
|
||||||
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
|
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
|
||||||
enumeration_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0),
|
enumeration_(0), struct_type_(0), discipline_(0),
|
||||||
s0_(0), e0_(0), eref_count_(0), lref_count_(0)
|
dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0)
|
||||||
{
|
{
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(npins>0);
|
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;
|
Link::DIR dir = Link::PASSIVE;
|
||||||
|
|
||||||
switch (t) {
|
switch (t) {
|
||||||
|
|
@ -492,15 +496,15 @@ void NetNet::initialize_dir_(Link::DIR dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
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),
|
: NetObj(s, n, 1), type_(t),
|
||||||
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
|
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
|
||||||
isint_(false), is_scalar_(false), local_flag_(false),
|
isint_(false), is_scalar_(false), local_flag_(false),
|
||||||
enumeration_(0), discipline_(0),
|
enumeration_(0), struct_type_(0), discipline_(0),
|
||||||
msb_(ms), lsb_(ls),
|
|
||||||
dimensions_(0), s0_(0), e0_(0),
|
dimensions_(0), s0_(0), e0_(0),
|
||||||
eref_count_(0), lref_count_(0)
|
eref_count_(0), lref_count_(0)
|
||||||
{
|
{
|
||||||
|
packed_dims_ = packed;
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
Link::DIR dir = Link::PASSIVE;
|
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,
|
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)),
|
: NetObj(s, n, calculate_count(array_s, array_e)),
|
||||||
type_(t), port_type_(NOT_A_PORT),
|
type_(t), port_type_(NOT_A_PORT),
|
||||||
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
|
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
|
||||||
is_scalar_(false), local_flag_(false), enumeration_(0), discipline_(0),
|
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0),
|
||||||
msb_(ms), lsb_(ls),
|
discipline_(0),
|
||||||
dimensions_(1), s0_(array_s), e0_(array_e),
|
dimensions_(1), s0_(array_s), e0_(array_e),
|
||||||
eref_count_(0), lref_count_(0)
|
eref_count_(0), lref_count_(0)
|
||||||
{
|
{
|
||||||
|
packed_dims_ = packed;
|
||||||
ivl_assert(*this, s);
|
ivl_assert(*this, s);
|
||||||
if (pin_count() == 0) {
|
if (pin_count() == 0) {
|
||||||
cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl;
|
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);
|
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()
|
NetNet::~NetNet()
|
||||||
{
|
{
|
||||||
if (eref_count_ > 0) {
|
if (eref_count_ > 0) {
|
||||||
|
|
@ -692,10 +743,16 @@ netenum_t*NetNet::enumeration(void) const
|
||||||
|
|
||||||
void NetNet::set_enumeration(netenum_t*es)
|
void NetNet::set_enumeration(netenum_t*es)
|
||||||
{
|
{
|
||||||
|
ivl_assert(*this, struct_type_ == 0);
|
||||||
ivl_assert(*this, enumeration_ == 0);
|
ivl_assert(*this, enumeration_ == 0);
|
||||||
enumeration_ = es;
|
enumeration_ = es;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netstruct_t*NetNet::struct_type(void) const
|
||||||
|
{
|
||||||
|
return struct_type_;
|
||||||
|
}
|
||||||
|
|
||||||
ivl_discipline_t NetNet::get_discipline() const
|
ivl_discipline_t NetNet::get_discipline() const
|
||||||
{
|
{
|
||||||
return discipline_;
|
return discipline_;
|
||||||
|
|
@ -707,40 +764,121 @@ void NetNet::set_discipline(ivl_discipline_t dis)
|
||||||
discipline_ = 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_;
|
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
|
||||||
}
|
assert(packed_dims_.size() == 1);
|
||||||
|
const range_t&rng = packed_dims_.back();
|
||||||
unsigned long NetNet::vector_width() const
|
if (rng.msb >= rng.lsb)
|
||||||
{
|
return (sb <= rng.msb) && (sb >= rng.lsb);
|
||||||
if (msb_ > lsb_)
|
|
||||||
return msb_ - lsb_ + 1;
|
|
||||||
else
|
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_)
|
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
|
||||||
return (sb <= msb_) && (sb >= lsb_);
|
|
||||||
|
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
|
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_)
|
ivl_assert(*this, indices.size() < packed_dims_.size());
|
||||||
return sb - lsb_;
|
|
||||||
|
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
|
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
|
unsigned NetNet::array_dimensions() const
|
||||||
{
|
{
|
||||||
return dimensions_;
|
return dimensions_;
|
||||||
|
|
@ -802,6 +940,26 @@ unsigned NetNet::peek_eref() const
|
||||||
return eref_count_;
|
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()
|
void NetNet::incr_lref()
|
||||||
{
|
{
|
||||||
lref_count_ += 1;
|
lref_count_ += 1;
|
||||||
|
|
@ -2296,14 +2454,23 @@ NetNet* NetESignal::sig()
|
||||||
return net_;
|
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
|
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
|
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
|
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 NetECast::expr_type() const
|
||||||
{
|
{
|
||||||
ivl_variable_type_t ret;
|
ivl_variable_type_t ret = IVL_VT_NO_TYPE;
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case 'v':
|
case 'v':
|
||||||
ret = IVL_VT_LOGIC;
|
ret = IVL_VT_LOGIC;
|
||||||
|
|
|
||||||
89
netlist.h
89
netlist.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __netlist_H
|
#ifndef __netlist_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -75,6 +75,7 @@ class NetEvWait;
|
||||||
class PExpr;
|
class PExpr;
|
||||||
class PFunction;
|
class PFunction;
|
||||||
class netenum_t;
|
class netenum_t;
|
||||||
|
class netstruct_t;
|
||||||
|
|
||||||
struct target;
|
struct target;
|
||||||
struct functor_t;
|
struct functor_t;
|
||||||
|
|
@ -549,7 +550,7 @@ class NetDelaySrc : public NetObj {
|
||||||
*
|
*
|
||||||
* NetNet objects are located by searching NetScope objects.
|
* 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
|
* anything and they are not a data sink, per se. The pins follow the
|
||||||
* values on the nexus.
|
* values on the nexus.
|
||||||
*/
|
*/
|
||||||
|
|
@ -560,8 +561,24 @@ class NetNet : public NetObj {
|
||||||
SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG,
|
SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG,
|
||||||
UNRESOLVED_WIRE };
|
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
|
// 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
|
// ls=0. Only one pin is created, the width is of the vector
|
||||||
// that passed through.
|
// that passed through.
|
||||||
|
|
@ -572,9 +589,12 @@ class NetNet : public NetObj {
|
||||||
// dimensions. If s0==e0, then this is not an array after
|
// dimensions. If s0==e0, then this is not an array after
|
||||||
// all.
|
// all.
|
||||||
explicit NetNet(NetScope*s, perm_string n, Type t,
|
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,
|
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();
|
virtual ~NetNet();
|
||||||
|
|
||||||
|
|
@ -603,27 +623,49 @@ class NetNet : public NetObj {
|
||||||
void set_enumeration(netenum_t*enum_set);
|
void set_enumeration(netenum_t*enum_set);
|
||||||
netenum_t*enumeration(void) const;
|
netenum_t*enumeration(void) const;
|
||||||
|
|
||||||
|
netstruct_t*struct_type(void) const;
|
||||||
|
|
||||||
/* Attach a discipline to the net. */
|
/* Attach a discipline to the net. */
|
||||||
ivl_discipline_t get_discipline() const;
|
ivl_discipline_t get_discipline() const;
|
||||||
void set_discipline(ivl_discipline_t dis);
|
void set_discipline(ivl_discipline_t dis);
|
||||||
|
|
||||||
/* These methods return the msb and lsb indices for the most
|
/* This method returns a reference to the packed dimensions
|
||||||
significant and least significant bits. These are signed
|
for the vector. These are arranged as a list where the
|
||||||
longs, and may be different from pin numbers. For example,
|
first range in the list (front) is the left-most range in
|
||||||
reg [1:8] has 8 bits, msb==1 and lsb==8. */
|
the verilog declaration. */
|
||||||
long msb() const;
|
const std::list<range_t>& packed_dims() const { return packed_dims_; }
|
||||||
long lsb() const;
|
|
||||||
unsigned long vector_width() const;
|
/* 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
|
/* This method converts a signed index (the type that might be
|
||||||
found in the Verilog source) to a pin number. It accounts
|
found in the Verilog source) to canonical. It accounts
|
||||||
for variation in the definition of the reg/wire/whatever. */
|
for variation in the definition of the
|
||||||
long sb_to_idx(long sb) const;
|
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
|
/* 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
|
signal. If it is, the above sb_to_idx can be used to get
|
||||||
the pin# from the index. */
|
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
|
/* This method returns 0 for scalars and vectors, and greater
|
||||||
for arrays. The value is the number of array
|
for arrays. The value is the number of array
|
||||||
|
|
@ -654,6 +696,7 @@ class NetNet : public NetObj {
|
||||||
void incr_lref();
|
void incr_lref();
|
||||||
void decr_lref();
|
void decr_lref();
|
||||||
unsigned peek_lref() const { return lref_count_; }
|
unsigned peek_lref() const { return lref_count_; }
|
||||||
|
bool test_part_lref(unsigned msb, unsigned lsb);
|
||||||
|
|
||||||
unsigned get_refs() const;
|
unsigned get_refs() const;
|
||||||
|
|
||||||
|
|
@ -676,18 +719,25 @@ class NetNet : public NetObj {
|
||||||
bool is_scalar_ : 1;
|
bool is_scalar_ : 1;
|
||||||
bool local_flag_: 1;
|
bool local_flag_: 1;
|
||||||
netenum_t*enumeration_;
|
netenum_t*enumeration_;
|
||||||
|
netstruct_t*struct_type_;
|
||||||
ivl_discipline_t discipline_;
|
ivl_discipline_t discipline_;
|
||||||
|
|
||||||
long msb_, lsb_;
|
std::list<range_t> packed_dims_;
|
||||||
const unsigned dimensions_;
|
const unsigned dimensions_;
|
||||||
long s0_, e0_;
|
long s0_, e0_;
|
||||||
|
|
||||||
unsigned eref_count_;
|
unsigned eref_count_;
|
||||||
unsigned lref_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_;
|
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
|
* This object type is used to contain a logical scope within a
|
||||||
* design. The scope doesn't represent any executable hardware, but is
|
* design. The scope doesn't represent any executable hardware, but is
|
||||||
|
|
@ -1613,7 +1663,8 @@ class NetTran : public NetNode, public IslandBranch {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Tran devices other than TRAN_VP
|
// 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
|
// Create a TRAN_VP
|
||||||
NetTran(NetScope*scope, perm_string n, unsigned wid,
|
NetTran(NetScope*scope, perm_string n, unsigned wid,
|
||||||
unsigned part, unsigned off);
|
unsigned part, unsigned off);
|
||||||
|
|
@ -2315,6 +2366,8 @@ class NetAssign_ {
|
||||||
ivl_select_type_t select_type() const;
|
ivl_select_type_t select_type() const;
|
||||||
|
|
||||||
void set_word(NetExpr*);
|
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,
|
void set_part(NetExpr* loff, unsigned wid,
|
||||||
ivl_select_type_t = IVL_SEL_OTHER);
|
ivl_select_type_t = IVL_SEL_OTHER);
|
||||||
|
|
||||||
|
|
|
||||||
184
netmisc.cc
184
netmisc.cc
|
|
@ -27,55 +27,6 @@
|
||||||
# include "compiler.h"
|
# include "compiler.h"
|
||||||
# include "ivl_assert.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)
|
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;
|
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
|
* This routine is used to calculate the number of bits needed to
|
||||||
* contain the given number.
|
* contain the given number.
|
||||||
|
|
@ -273,10 +239,13 @@ static unsigned num_bits(long arg)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine generates the normalization expression needed for a variable
|
* 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,
|
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;
|
long offset = lsb;
|
||||||
|
|
||||||
|
|
@ -309,13 +278,13 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
|
||||||
base = tmp;
|
base = tmp;
|
||||||
}
|
}
|
||||||
/* Normalize the expression. */
|
/* Normalize the expression. */
|
||||||
base = make_sub_expr(offset, base);
|
base = make_sub_expr(offset+soff, base);
|
||||||
} else {
|
} else {
|
||||||
/* Correct the offset if needed. */
|
/* Correct the offset if needed. */
|
||||||
if (!is_up) offset += wid - 1;
|
if (!is_up) offset += wid - 1;
|
||||||
/* If the offset is zero then just return the base (index)
|
/* If the offset is zero then just return the base (index)
|
||||||
* expression. */
|
* expression. */
|
||||||
if (offset == 0) return base;
|
if ((soff-offset) == 0) return base;
|
||||||
/* Calculate the space needed for the offset. */
|
/* Calculate the space needed for the offset. */
|
||||||
unsigned min_wid = num_bits(-offset);
|
unsigned min_wid = num_bits(-offset);
|
||||||
/* We need enough space for the larger of the offset or the
|
/* 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;
|
base = tmp;
|
||||||
}
|
}
|
||||||
/* Normalize the expression. */
|
/* Normalize the expression. */
|
||||||
base = make_add_expr(base, -offset);
|
base = make_add_expr(base, soff-offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base;
|
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
|
* This routine generates the normalization expression needed for a variable
|
||||||
* array word select.
|
* array word select.
|
||||||
|
|
@ -892,3 +932,39 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig)
|
||||||
delete ps_obj;
|
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.
|
* the provided vector/array information.
|
||||||
*/
|
*/
|
||||||
extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
|
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,
|
extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
|
||||||
unsigned count);
|
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 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
|
#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 "config.h"
|
||||||
|
|
||||||
# include "parse_misc.h"
|
# include "parse_misc.h"
|
||||||
|
# include <cstdarg>
|
||||||
|
# include <cstdio>
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
|
||||||
extern const char*vl_file;
|
extern const char*vl_file;
|
||||||
|
|
@ -42,10 +44,16 @@ void VLerror(const char*msg)
|
||||||
cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl;
|
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;
|
error_count += 1;
|
||||||
cerr << loc << ": " << msg << endl;
|
|
||||||
based_size = 0; /* Clear the base information if we have an error. */
|
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 int VLlex();
|
||||||
extern void VLerror(const char*msg);
|
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
|
#define yywarn VLwarn
|
||||||
extern void VLwarn(const YYLTYPE&loc, const char*msg);
|
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_timeunit_decl;
|
||||||
extern bool have_timeprec_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
|
* Export these functions because we have to generate PENumber class
|
||||||
* in pform.cc for user defparam definition from command file.
|
* 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_octal(const char*txt);
|
||||||
extern verinum*make_unsized_hex(const char*txt);
|
extern verinum*make_unsized_hex(const char*txt);
|
||||||
|
|
||||||
|
extern char* strdupnew(char const *str);
|
||||||
|
|
||||||
#endif
|
#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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
# include "pform.h"
|
# include "pform.h"
|
||||||
# include "parse_misc.h"
|
# include "parse_misc.h"
|
||||||
# include "parse_api.h"
|
# include "parse_api.h"
|
||||||
|
# include "PClass.h"
|
||||||
# include "PEvent.h"
|
# include "PEvent.h"
|
||||||
# include "PUdp.h"
|
# include "PUdp.h"
|
||||||
# include "PGenerate.h"
|
# include "PGenerate.h"
|
||||||
|
|
@ -267,12 +268,30 @@ void pform_pop_scope()
|
||||||
lexical_scope = lexical_scope->parent_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)
|
PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
|
||||||
{
|
{
|
||||||
perm_string task_name = lex_strings.make(name);
|
perm_string task_name = lex_strings.make(name);
|
||||||
|
|
||||||
PTask*task = new PTask(task_name, lexical_scope, is_auto);
|
PTask*task = new PTask(task_name, lexical_scope, is_auto);
|
||||||
FILE_NAME(task, loc);
|
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) {
|
if (pform_cur_generate) {
|
||||||
// Check if the task is already in the dictionary.
|
// Check if the task is already in the dictionary.
|
||||||
if (pform_cur_generate->tasks.find(task->pscope_name()) !=
|
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;
|
pform_cur_generate->tasks[task->pscope_name()] = task;
|
||||||
} else {
|
} else {
|
||||||
// Check if the task is already in the dictionary.
|
// Check if the task is already in the dictionary.
|
||||||
if (pform_cur_module->tasks.find(task->pscope_name()) !=
|
if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) {
|
||||||
pform_cur_module->tasks.end()) {
|
|
||||||
cerr << task->get_fileline() << ": error: duplicate "
|
cerr << task->get_fileline() << ": error: duplicate "
|
||||||
"definition for task '" << name << "' in '"
|
"definition for task '" << name << "' in '"
|
||||||
<< pform_cur_module->mod_name() << "'." << endl;
|
<< scopex->pscope_name() << "'." << endl;
|
||||||
error_count += 1;
|
error_count += 1;
|
||||||
}
|
}
|
||||||
pform_cur_module->tasks[task->pscope_name()] = task;
|
scopex->tasks[task->pscope_name()] = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
lexical_scope = task;
|
lexical_scope = task;
|
||||||
|
|
||||||
return 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);
|
PFunction*func = new PFunction(func_name, lexical_scope, is_auto);
|
||||||
FILE_NAME(func, loc);
|
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) {
|
if (pform_cur_generate) {
|
||||||
// Check if the function is already in the dictionary.
|
// Check if the function is already in the dictionary.
|
||||||
if (pform_cur_generate->funcs.find(func->pscope_name()) !=
|
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;
|
pform_cur_generate->funcs[func->pscope_name()] = func;
|
||||||
} else {
|
} else {
|
||||||
// Check if the function is already in the dictionary.
|
// Check if the function is already in the dictionary.
|
||||||
if (pform_cur_module->funcs.find(func->pscope_name()) !=
|
if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) {
|
||||||
pform_cur_module->funcs.end()) {
|
|
||||||
cerr << func->get_fileline() << ": error: duplicate "
|
cerr << func->get_fileline() << ": error: duplicate "
|
||||||
"definition for function '" << name << "' in '"
|
"definition for function '" << name << "' in '"
|
||||||
<< pform_cur_module->mod_name() << "'." << endl;
|
<< scopex->pscope_name() << "'." << endl;
|
||||||
error_count += 1;
|
error_count += 1;
|
||||||
}
|
}
|
||||||
pform_cur_module->funcs[func->pscope_name()] = func;
|
scopex->funcs[func->pscope_name()] = func;
|
||||||
}
|
}
|
||||||
lexical_scope = 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);
|
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);
|
PWire*cur = pform_get_wire_in_scope(name);
|
||||||
if (cur == 0) {
|
if (cur == 0) {
|
||||||
|
|
@ -401,6 +428,33 @@ static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_typ
|
||||||
return cur;
|
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)
|
static void pform_put_behavior_in_scope(PProcess*pp)
|
||||||
{
|
{
|
||||||
lexical_scope->behaviors.push_back(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.
|
* and the name that I receive only has the tail component.
|
||||||
*/
|
*/
|
||||||
static void pform_set_net_range(perm_string name,
|
static void pform_set_net_range(perm_string name,
|
||||||
const list<PExpr*>*range,
|
const list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
ivl_variable_type_t dt,
|
ivl_variable_type_t dt,
|
||||||
PWSRType rt)
|
PWSRType rt)
|
||||||
|
|
@ -1478,11 +1532,10 @@ static void pform_set_net_range(perm_string name,
|
||||||
if (range == 0) {
|
if (range == 0) {
|
||||||
/* This is the special case that we really mean a
|
/* This is the special case that we really mean a
|
||||||
scalar. Set a fake range. */
|
scalar. Set a fake range. */
|
||||||
cur->set_range(0, 0, rt, true);
|
cur->set_range_scalar(rt);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
assert(range->size() == 2);
|
cur->set_range(*range, rt);
|
||||||
cur->set_range(range->front(), range->back(), rt, false);
|
|
||||||
}
|
}
|
||||||
cur->set_signed(signed_flag);
|
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,
|
void pform_set_net_range(list<perm_string>*names,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
ivl_variable_type_t dt,
|
ivl_variable_type_t dt)
|
||||||
PWSRType rt)
|
|
||||||
{
|
{
|
||||||
assert((range == 0) || (range->size() == 2));
|
|
||||||
|
|
||||||
for (list<perm_string>::iterator cur = names->begin()
|
for (list<perm_string>::iterator cur = names->begin()
|
||||||
; cur != names->end() ; ++ cur ) {
|
; cur != names->end() ; ++ cur ) {
|
||||||
perm_string txt = *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;
|
delete names;
|
||||||
|
|
@ -1565,8 +1615,8 @@ static void pform_makegate(PGBuiltin::Type type,
|
||||||
|
|
||||||
perm_string dev_name = lex_strings.make(info.name);
|
perm_string dev_name = lex_strings.make(info.name);
|
||||||
PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay);
|
PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay);
|
||||||
if (info.range[0])
|
if (info.range.first)
|
||||||
cur->set_range(info.range[0], info.range[1]);
|
cur->set_range(info.range.first, info.range.second);
|
||||||
|
|
||||||
// The pform_makegates() that calls me will take care of
|
// The pform_makegates() that calls me will take care of
|
||||||
// deleting the attr pointer, so tell the
|
// deleting the attr pointer, so tell the
|
||||||
|
|
@ -1705,7 +1755,7 @@ void pform_make_modgates(perm_string type,
|
||||||
if (cur.parms_by_name) {
|
if (cur.parms_by_name) {
|
||||||
pform_make_modgate(type, cur_name, overrides,
|
pform_make_modgate(type, cur_name, overrides,
|
||||||
cur.parms_by_name,
|
cur.parms_by_name,
|
||||||
cur.range[0], cur.range[1],
|
cur.range.first, cur.range.second,
|
||||||
cur.file, cur.lineno);
|
cur.file, cur.lineno);
|
||||||
|
|
||||||
} else if (cur.parms) {
|
} else if (cur.parms) {
|
||||||
|
|
@ -1719,14 +1769,14 @@ void pform_make_modgates(perm_string type,
|
||||||
}
|
}
|
||||||
pform_make_modgate(type, cur_name, overrides,
|
pform_make_modgate(type, cur_name, overrides,
|
||||||
cur.parms,
|
cur.parms,
|
||||||
cur.range[0], cur.range[1],
|
cur.range.first, cur.range.second,
|
||||||
cur.file, cur.lineno);
|
cur.file, cur.lineno);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
list<PExpr*>*wires = new list<PExpr*>;
|
list<PExpr*>*wires = new list<PExpr*>;
|
||||||
pform_make_modgate(type, cur_name, overrides,
|
pform_make_modgate(type, cur_name, overrides,
|
||||||
wires,
|
wires,
|
||||||
cur.range[0], cur.range[1],
|
cur.range.first, cur.range.second,
|
||||||
cur.file, cur.lineno);
|
cur.file, cur.lineno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1799,8 +1849,8 @@ void pform_make_pgassign_list(list<PExpr*>*alist,
|
||||||
void pform_make_reginit(const struct vlltype&li,
|
void pform_make_reginit(const struct vlltype&li,
|
||||||
perm_string name, PExpr*expr)
|
perm_string name, PExpr*expr)
|
||||||
{
|
{
|
||||||
if (! pform_at_module_level()) {
|
if (! pform_at_module_level() && !gn_system_verilog()) {
|
||||||
VLerror(li, "variable declaration assignments are only "
|
VLerror(li, "error: variable declaration assignments are only "
|
||||||
"allowed at the module level.");
|
"allowed at the module level.");
|
||||||
delete expr;
|
delete expr;
|
||||||
return;
|
return;
|
||||||
|
|
@ -1839,7 +1889,7 @@ void pform_module_define_port(const struct vlltype&li,
|
||||||
NetNet::Type type,
|
NetNet::Type type,
|
||||||
ivl_variable_type_t data_type,
|
ivl_variable_type_t data_type,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
list<named_pexpr_t>*attr)
|
list<named_pexpr_t>*attr)
|
||||||
{
|
{
|
||||||
PWire*cur = pform_get_wire_in_scope(name);
|
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);
|
cur->set_signed(signed_flag);
|
||||||
|
|
||||||
if (range == 0) {
|
if (range == 0) {
|
||||||
cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT :
|
cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
|
||||||
SR_BOTH,
|
|
||||||
true);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
assert(range->size() == 2);
|
cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
|
||||||
assert(range->front());
|
|
||||||
assert(range->back());
|
|
||||||
cur->set_range(range->front(), range->back(),
|
|
||||||
(type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pform_bind_attributes(cur->attributes, attr);
|
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.
|
* 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
|
* this is the basic form of pform_makewire. This takes a single simple
|
||||||
* name, port type, net type, data type, and attributes, and creates
|
* 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,
|
ivl_variable_type_t dt,
|
||||||
list<named_pexpr_t>*attr)
|
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) {
|
if (! cur) {
|
||||||
new_wire_flag = true;
|
|
||||||
cur = new PWire(name, type, pt, dt);
|
cur = new PWire(name, type, pt, dt);
|
||||||
FILE_NAME(cur, li.text, li.first_line);
|
FILE_NAME(cur, li.text, li.first_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != NetNet::IMPLICIT)
|
|
||||||
FILE_NAME(cur, li.text, li.first_line);
|
|
||||||
|
|
||||||
bool flag;
|
bool flag;
|
||||||
switch (dt) {
|
switch (dt) {
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
|
|
@ -1947,7 +2000,7 @@ void pform_makewire(const vlltype&li, perm_string name,
|
||||||
<< " to " << dt << "." << endl;
|
<< " to " << dt << "." << endl;
|
||||||
}
|
}
|
||||||
ivl_assert(*cur, flag);
|
ivl_assert(*cur, flag);
|
||||||
cur->set_range(0, 0, SR_NET, true);
|
cur->set_range_scalar(SR_NET);
|
||||||
cur->set_signed(true);
|
cur->set_signed(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -1960,9 +2013,6 @@ void pform_makewire(const vlltype&li, perm_string name,
|
||||||
cur->attributes[attr_cur->name] = attr_cur->parm;
|
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.
|
* pform_makewire above.
|
||||||
*/
|
*/
|
||||||
void pform_makewire(const vlltype&li,
|
void pform_makewire(const vlltype&li,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<perm_string>*names,
|
list<perm_string>*names,
|
||||||
NetNet::Type type,
|
NetNet::Type type,
|
||||||
|
|
@ -1998,7 +2048,7 @@ void pform_makewire(const vlltype&li,
|
||||||
* This form makes nets with delays and continuous assignments.
|
* This form makes nets with delays and continuous assignments.
|
||||||
*/
|
*/
|
||||||
void pform_makewire(const vlltype&li,
|
void pform_makewire(const vlltype&li,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*delay,
|
list<PExpr*>*delay,
|
||||||
str_pair_t str,
|
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
|
* 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
|
* 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
|
* constraints as those of tasks, so this works fine. Functions have
|
||||||
* no output or inout ports.
|
* 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,
|
ivl_variable_type_t vtype,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
list<perm_string>*names,
|
list<perm_string>*names,
|
||||||
const char* file,
|
|
||||||
unsigned lineno,
|
|
||||||
bool isint)
|
bool isint)
|
||||||
{
|
{
|
||||||
|
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
|
||||||
assert(names);
|
assert(names);
|
||||||
svector<PWire*>*res = new svector<PWire*>(0);
|
svector<PWire*>*res = new svector<PWire*>(0);
|
||||||
for (list<perm_string>::iterator cur = names->begin()
|
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);
|
curw->set_port_type(pt);
|
||||||
} else {
|
} else {
|
||||||
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
|
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);
|
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 there is a range involved, it needs to be set. */
|
||||||
if (range) {
|
if (range) {
|
||||||
assert(range->size() == 2);
|
curw->set_range(*range, SR_PORT);
|
||||||
curw->set_range(range->front(), range->back(), SR_PORT, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
svector<PWire*>*tmp = new svector<PWire*>(*res, curw);
|
svector<PWire*>*tmp = new svector<PWire*>(*res, curw);
|
||||||
|
|
@ -2152,6 +2168,71 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||||
return res;
|
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)
|
void pform_set_attrib(perm_string name, perm_string key, char*value)
|
||||||
{
|
{
|
||||||
if (PWire*cur = lexical_scope->wires_find(name)) {
|
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,
|
void pform_set_parameter(const struct vlltype&loc,
|
||||||
perm_string name, ivl_variable_type_t type,
|
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::range_t*value_range)
|
||||||
{
|
{
|
||||||
LexicalScope*scope = lexical_scope;
|
LexicalScope*scope = lexical_scope;
|
||||||
|
|
@ -2255,11 +2336,12 @@ void pform_set_parameter(const struct vlltype&loc,
|
||||||
|
|
||||||
parm.type = type;
|
parm.type = type;
|
||||||
if (range) {
|
if (range) {
|
||||||
assert(range->size() == 2);
|
assert(range->size() == 1);
|
||||||
assert(range->front());
|
pform_range_t&rng = range->front();
|
||||||
assert(range->back());
|
assert(rng.first);
|
||||||
parm.msb = range->front();
|
assert(rng.second);
|
||||||
parm.lsb = range->back();
|
parm.msb = rng.first;
|
||||||
|
parm.lsb = rng.second;
|
||||||
} else {
|
} else {
|
||||||
parm.msb = 0;
|
parm.msb = 0;
|
||||||
parm.lsb = 0;
|
parm.lsb = 0;
|
||||||
|
|
@ -2273,7 +2355,7 @@ void pform_set_parameter(const struct vlltype&loc,
|
||||||
|
|
||||||
void pform_set_localparam(const struct vlltype&loc,
|
void pform_set_localparam(const struct vlltype&loc,
|
||||||
perm_string name, ivl_variable_type_t type,
|
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;
|
LexicalScope*scope = lexical_scope;
|
||||||
|
|
||||||
|
|
@ -2303,11 +2385,12 @@ void pform_set_localparam(const struct vlltype&loc,
|
||||||
|
|
||||||
parm.type = type;
|
parm.type = type;
|
||||||
if (range) {
|
if (range) {
|
||||||
assert(range->size() == 2);
|
assert(range->size() == 1);
|
||||||
assert(range->front());
|
pform_range_t&rng = range->front();
|
||||||
assert(range->back());
|
assert(rng.first);
|
||||||
parm.msb = range->front();
|
assert(rng.second);
|
||||||
parm.lsb = range->back();
|
parm.msb = rng.first;
|
||||||
|
parm.lsb = rng.second;
|
||||||
} else {
|
} else {
|
||||||
parm.msb = 0;
|
parm.msb = 0;
|
||||||
parm.lsb = 0;
|
parm.lsb = 0;
|
||||||
|
|
@ -2404,12 +2487,48 @@ extern void pform_module_specify_path(PSpecPath*obj)
|
||||||
pform_cur_module->specify_paths.push_back(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,
|
void pform_set_port_type(const struct vlltype&li,
|
||||||
list<perm_string>*names,
|
list<perm_string>*names,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
NetNet::PortType pt)
|
NetNet::PortType pt)
|
||||||
{
|
{
|
||||||
|
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
|
||||||
|
|
||||||
for (list<perm_string>::iterator cur = names->begin()
|
for (list<perm_string>::iterator cur = names->begin()
|
||||||
; cur != names->end() ; ++ cur ) {
|
; cur != names->end() ; ++ cur ) {
|
||||||
perm_string txt = *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);
|
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
|
||||||
assert(cur);
|
assert(cur);
|
||||||
|
|
||||||
cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)),
|
pform_range_t rng;
|
||||||
new PENumber(new verinum((uint64_t)0, integer_width)),
|
rng.first = new PENumber(new verinum(integer_width-1, integer_width));
|
||||||
SR_NET, false);
|
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);
|
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);
|
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
|
||||||
assert(cur);
|
assert(cur);
|
||||||
|
|
||||||
cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)),
|
pform_range_t rng;
|
||||||
new PENumber(new verinum((uint64_t)0, integer_width)),
|
rng.first = new PENumber(new verinum(TIME_WIDTH-1, integer_width));
|
||||||
SR_NET, false);
|
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)
|
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);
|
assert(cur);
|
||||||
|
|
||||||
cur->set_signed(signed_flag);
|
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)),
|
pform_range_t rng;
|
||||||
SR_NET, false);
|
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)
|
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;
|
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,
|
static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
|
||||||
perm_string name)
|
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);
|
cur->set_signed(enum_type->signed_flag);
|
||||||
|
|
||||||
assert(enum_type->range.get() != 0);
|
assert(enum_type->range.get() != 0);
|
||||||
assert(enum_type->range->size() == 2);
|
assert(enum_type->range->size() == 1);
|
||||||
cur->set_range(enum_type->range->front(), enum_type->range->back(), SR_NET, false);
|
cur->set_range(*enum_type->range, SR_NET);
|
||||||
cur->set_enumeration(enum_type);
|
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->base_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL);
|
||||||
|
|
||||||
assert(enum_type->range.get() != 0);
|
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.
|
// Add the file and line information to the enumeration type.
|
||||||
FILE_NAME(&(enum_type->li), li);
|
FILE_NAME(&(enum_type->li), li);
|
||||||
|
|
|
||||||
78
pform.h
78
pform.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __pform_H
|
#ifndef __pform_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -58,6 +58,7 @@
|
||||||
class PGate;
|
class PGate;
|
||||||
class PExpr;
|
class PExpr;
|
||||||
class PSpecPath;
|
class PSpecPath;
|
||||||
|
class PClass;
|
||||||
struct vlltype;
|
struct vlltype;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -101,22 +102,23 @@ struct net_decl_assign_t {
|
||||||
|
|
||||||
/* The lgate is gate instantiation information. */
|
/* The lgate is gate instantiation information. */
|
||||||
struct lgate {
|
struct lgate {
|
||||||
lgate(int =0)
|
inline lgate(int =0)
|
||||||
: parms(0), parms_by_name(0), file(NULL), lineno(0)
|
: parms(0), parms_by_name(0), file(NULL), lineno(0)
|
||||||
{ range[0] = 0;
|
{ }
|
||||||
range[1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string name;
|
string name;
|
||||||
list<PExpr*>*parms;
|
list<PExpr*>*parms;
|
||||||
list<named_pexpr_t>*parms_by_name;
|
list<named_pexpr_t>*parms_by_name;
|
||||||
|
|
||||||
PExpr*range[2];
|
pform_range_t range;
|
||||||
|
|
||||||
const char* file;
|
const char* file;
|
||||||
unsigned lineno;
|
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
|
/* Use this function to transform the parted form of the attribute
|
||||||
list to the attribute map that is used later. */
|
list to the attribute map that is used later. */
|
||||||
extern void pform_bind_attributes(map<perm_string,PExpr*>&attributes,
|
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_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
|
* The parser uses startmodule and endmodule together to build up a
|
||||||
* module as it parses it. The startmodule tells the pform code that 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,
|
NetNet::Type type,
|
||||||
ivl_variable_type_t data_type,
|
ivl_variable_type_t data_type,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
list<named_pexpr_t>*attr);
|
list<named_pexpr_t>*attr);
|
||||||
|
|
||||||
extern Module::port_t* pform_module_port_reference(perm_string name,
|
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,
|
extern void pform_endmodule(const char*, bool inside_celldefine,
|
||||||
Module::UCDriveType uc_drive_def);
|
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,
|
extern void pform_make_udp(perm_string name, list<perm_string>*parms,
|
||||||
svector<PWire*>*decl, list<string>*table,
|
svector<PWire*>*decl, list<string>*table,
|
||||||
Statement*init,
|
Statement*init,
|
||||||
|
|
@ -184,6 +192,7 @@ extern void pform_make_udp(perm_string name,
|
||||||
*/
|
*/
|
||||||
extern void pform_pop_scope();
|
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,
|
extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name,
|
||||||
bool is_auto);
|
bool is_auto);
|
||||||
extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name,
|
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 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
|
* The makewire functions announce to the pform code new wires. These
|
||||||
* go into a module that is currently opened.
|
* 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 */
|
/* This form handles simple declarations */
|
||||||
extern void pform_makewire(const struct vlltype&li,
|
extern void pform_makewire(const struct vlltype&li,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<perm_string>*names,
|
list<perm_string>*names,
|
||||||
NetNet::Type type,
|
NetNet::Type type,
|
||||||
|
|
@ -243,9 +254,15 @@ extern void pform_makewire(const struct vlltype&li,
|
||||||
list<named_pexpr_t>*attr,
|
list<named_pexpr_t>*attr,
|
||||||
PWSRType rt = SR_NET);
|
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. */
|
/* This form handles assignment declarations. */
|
||||||
extern void pform_makewire(const struct vlltype&li,
|
extern void pform_makewire(const struct vlltype&li,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*delay,
|
list<PExpr*>*delay,
|
||||||
str_pair_t str,
|
str_pair_t str,
|
||||||
|
|
@ -253,6 +270,13 @@ extern void pform_makewire(const struct vlltype&li,
|
||||||
NetNet::Type type,
|
NetNet::Type type,
|
||||||
ivl_variable_type_t);
|
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,
|
extern void pform_make_reginit(const struct vlltype&li,
|
||||||
perm_string name, PExpr*expr);
|
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. */
|
it. The second form takes a single name. */
|
||||||
extern void pform_set_port_type(const struct vlltype&li,
|
extern void pform_set_port_type(const struct vlltype&li,
|
||||||
list<perm_string>*names,
|
list<perm_string>*names,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
NetNet::PortType);
|
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,
|
extern void pform_set_net_range(list<perm_string>*names,
|
||||||
list<PExpr*>*,
|
list<pform_range_t>*,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
ivl_variable_type_t,
|
ivl_variable_type_t);
|
||||||
PWSRType rt = SR_NET);
|
|
||||||
extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r);
|
extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r);
|
||||||
extern void pform_set_reg_integer(list<perm_string>*names);
|
extern void pform_set_reg_integer(list<perm_string>*names);
|
||||||
extern void pform_set_reg_time(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_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_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
|
/* pform_set_attrib and pform_set_type_attrib exist to support the
|
||||||
$attribute syntax, which can only set string values to
|
$attribute syntax, which can only set string values to
|
||||||
attributes. The functions keep the value strings that are
|
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,
|
perm_string name,
|
||||||
ivl_variable_type_t type,
|
ivl_variable_type_t type,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
PExpr*expr, LexicalScope::range_t*value_range);
|
PExpr*expr, LexicalScope::range_t*value_range);
|
||||||
extern void pform_set_localparam(const struct vlltype&loc,
|
extern void pform_set_localparam(const struct vlltype&loc,
|
||||||
perm_string name,
|
perm_string name,
|
||||||
ivl_variable_type_t type,
|
ivl_variable_type_t type,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
PExpr*expr);
|
PExpr*expr);
|
||||||
extern void pform_set_defparam(const pform_name_t&name, 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
|
/* Given a port type and a list of names, make a list of wires that
|
||||||
can be used as task port information. */
|
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,
|
ivl_variable_type_t vtype,
|
||||||
bool signed_flag,
|
bool signed_flag,
|
||||||
list<PExpr*>*range,
|
list<pform_range_t>*range,
|
||||||
list<perm_string>*names,
|
list<perm_string>*names,
|
||||||
const char* file,
|
|
||||||
unsigned lineno,
|
|
||||||
bool isint = false);
|
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
|
* 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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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;
|
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,
|
static void dump_attributes_map(ostream&out,
|
||||||
const map<perm_string,PExpr*>&attributes,
|
const map<perm_string,PExpr*>&attributes,
|
||||||
int ind)
|
int ind)
|
||||||
|
|
@ -331,6 +336,9 @@ void PWire::dump(ostream&out, unsigned ind) const
|
||||||
case NetNet::PINOUT:
|
case NetNet::PINOUT:
|
||||||
out << " inout";
|
out << " inout";
|
||||||
break;
|
break;
|
||||||
|
case NetNet::PREF:
|
||||||
|
out << " ref";
|
||||||
|
break;
|
||||||
case NetNet::NOT_A_PORT:
|
case NetNet::NOT_A_PORT:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -346,17 +354,23 @@ void PWire::dump(ostream&out, unsigned ind) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port_set_) {
|
if (port_set_) {
|
||||||
if (port_msb_ == 0) {
|
if (port_.empty()) {
|
||||||
out << " port<scalar>";
|
out << " port<scalar>";
|
||||||
} else {
|
} 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_set_) {
|
||||||
if (net_msb_ == 0) {
|
if (net_.empty()) {
|
||||||
out << " net<scalar>";
|
out << " net<scalar>";
|
||||||
} else {
|
} 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 (delay_) out << "#" << *delay_ << " ";
|
||||||
if (count_) out << "repeat(" << *count_ << ") ";
|
if (count_) out << "repeat(" << *count_ << ") ";
|
||||||
if (event_) out << *event_ << " ";
|
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
|
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
|
void PForStatement::dump(ostream&out, unsigned ind) const
|
||||||
{
|
{
|
||||||
out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_
|
out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_
|
||||||
<< "; " << *cond_ << "; " << *name2_ << " = " << *expr2_ <<
|
<< "; " << *cond_ << "; <for_step>)" << endl;
|
||||||
")" << endl;
|
step_->dump(out, ind+6);
|
||||||
statement_->dump(out, ind+3);
|
statement_->dump(out, ind+3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -798,7 +815,13 @@ void PFunction::dump(ostream&out, unsigned ind) const
|
||||||
out << "int unsigned ";
|
out << "int unsigned ";
|
||||||
break;
|
break;
|
||||||
case PTF_ATOM2_S:
|
case PTF_ATOM2_S:
|
||||||
cout << "int signed ";
|
out << "int signed ";
|
||||||
|
break;
|
||||||
|
case PTF_STRING:
|
||||||
|
out << "string ";
|
||||||
|
break;
|
||||||
|
case PTF_VOID:
|
||||||
|
out << "void ";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -849,6 +872,10 @@ void PTask::dump(ostream&out, unsigned ind) const
|
||||||
out << pscope_name() << ";" << endl;
|
out << pscope_name() << ";" << endl;
|
||||||
if (ports_)
|
if (ports_)
|
||||||
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
|
||||||
|
if ((*ports_)[idx] == 0) {
|
||||||
|
out << setw(ind) << "" << "ERROR PORT" << endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
out << setw(ind) << "";
|
out << setw(ind) << "";
|
||||||
switch ((*ports_)[idx]->get_port_type()) {
|
switch ((*ports_)[idx]->get_port_type()) {
|
||||||
case NetNet::PINPUT:
|
case NetNet::PINPUT:
|
||||||
|
|
@ -860,6 +887,12 @@ void PTask::dump(ostream&out, unsigned ind) const
|
||||||
case NetNet::PINOUT:
|
case NetNet::PINOUT:
|
||||||
out << "inout ";
|
out << "inout ";
|
||||||
break;
|
break;
|
||||||
|
case NetNet::PIMPLICIT:
|
||||||
|
out << "PIMPLICIT";
|
||||||
|
break;
|
||||||
|
case NetNet::NOT_A_PORT:
|
||||||
|
out << "NOT_A_PORT";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
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
|
void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const
|
||||||
{
|
{
|
||||||
typedef map<perm_string,param_expr_t>::const_iterator parm_iter_t;
|
typedef map<perm_string,param_expr_t>::const_iterator parm_iter_t;
|
||||||
|
|
@ -1189,6 +1231,8 @@ void Module::dump(ostream&out) const
|
||||||
out << ")" << endl;
|
out << ")" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dump_typedefs_(out, 4);
|
||||||
|
|
||||||
dump_parameters_(out, 4);
|
dump_parameters_(out, 4);
|
||||||
|
|
||||||
dump_localparams_(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"
|
# include "pform_types.h"
|
||||||
|
|
||||||
|
data_type_t::~data_type_t()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __pform_types_H
|
#ifndef __pform_types_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
class PExpr;
|
class PExpr;
|
||||||
typedef named<verinum> named_number_t;
|
typedef named<verinum> named_number_t;
|
||||||
typedef named<PExpr*> named_pexpr_t;
|
typedef named<PExpr*> named_pexpr_t;
|
||||||
|
typedef std::pair<PExpr*,PExpr*> pform_range_t;
|
||||||
|
|
||||||
struct index_component_t {
|
struct index_component_t {
|
||||||
enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO };
|
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;
|
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
|
* The enum_type_t holds the parsed declaration to represent an
|
||||||
* enumeration. Since this is in the pform, it represents the type
|
* enumeration. Since this is in the pform, it represents the type
|
||||||
* before elaboration to the range, for example, man not be complete
|
* before elaboration to the range, for example, man not be complete
|
||||||
* until it is elaborated in a scope.
|
* 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;
|
ivl_variable_type_t base_type;
|
||||||
bool signed_flag;
|
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;
|
std::auto_ptr< list<named_pexpr_t> > names;
|
||||||
LineInfo li;
|
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
|
* The pform_name_t is the general form for a hierarchical
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ debug:elaborate
|
||||||
debug:elab_pexpr
|
debug:elab_pexpr
|
||||||
debug:scopes
|
debug:scopes
|
||||||
debug:synth2
|
debug:synth2
|
||||||
|
debug:optimizer
|
||||||
out:a.out
|
out:a.out
|
||||||
ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp
|
ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp
|
||||||
sys_func:scripts/devel-stub.sft
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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:
|
public:
|
||||||
synth_f() { top_ = NULL; }
|
synth_f() { top_ = NULL; }
|
||||||
void process(class Design*, class NetProcTop*);
|
void process(Design*, NetProcTop*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void proc_always_(class Design*);
|
void proc_always_(Design*);
|
||||||
void proc_initial_(class Design*);
|
void proc_initial_(Design*);
|
||||||
void proc_final_(class Design*);
|
void proc_final_(Design*);
|
||||||
|
|
||||||
NetProcTop*top_;
|
NetProcTop*top_;
|
||||||
};
|
};
|
||||||
|
|
@ -129,7 +129,7 @@ class synth_f : public functor_t {
|
||||||
* Look at a process, and divide the problem into always and initial
|
* Look at a process, and divide the problem into always and initial
|
||||||
* threads.
|
* threads.
|
||||||
*/
|
*/
|
||||||
void synth_f::process(class Design*des, class NetProcTop*top)
|
void synth_f::process(Design*des, NetProcTop*top)
|
||||||
{
|
{
|
||||||
top_ = top;
|
top_ = top;
|
||||||
switch (top->type()) {
|
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());
|
do_expr expr_pat(des, top_->scope());
|
||||||
top_->statement()->match_proc(&expr_pat);
|
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());
|
do_expr expr_pat(des, top_->scope());
|
||||||
top_->statement()->match_proc(&expr_pat);
|
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());
|
do_expr expr_pat(des, top_->scope());
|
||||||
top_->statement()->match_proc(&expr_pat);
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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 {
|
class synth2_f : public functor_t {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void process(class Design*, class NetProcTop*);
|
void process(Design*, NetProcTop*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
@ -910,7 +910,7 @@ class synth2_f : public functor_t {
|
||||||
* Look at a process. If it is asynchronous, then synthesize it as an
|
* Look at a process. If it is asynchronous, then synthesize it as an
|
||||||
* asynchronous process and delete the process itself for its gates.
|
* 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)
|
if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0)
|
||||||
return;
|
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)
|
extern "C" int ivl_signal_msb(ivl_signal_t net)
|
||||||
{
|
{
|
||||||
assert(net->lsb_dist == 1 || net->lsb_dist == -1);
|
if (net->packed_dims.size() == 0)
|
||||||
return net->lsb_index + net->lsb_dist * (net->width_ - 1);
|
return 0;
|
||||||
|
|
||||||
|
assert(net->packed_dims.size() == 1);
|
||||||
|
return net->packed_dims[0].msb;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int ivl_signal_lsb(ivl_signal_t net)
|
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)
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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;
|
struct ivl_switch_s*obj = new struct ivl_switch_s;
|
||||||
obj->type = net->type();
|
obj->type = net->type();
|
||||||
obj->width = 0;
|
obj->width = net->vector_width();
|
||||||
obj->part = 0;
|
obj->part = 0;
|
||||||
obj->offset = 0;
|
obj->offset = 0;
|
||||||
obj->name = net->name();
|
obj->name = net->name();
|
||||||
|
|
@ -996,7 +996,6 @@ bool dll_target::tran(const NetTran*net)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->type == IVL_SW_TRAN_VP) {
|
if (obj->type == IVL_SW_TRAN_VP) {
|
||||||
obj->width = net->vector_width();
|
|
||||||
obj->part = net->part_width();
|
obj->part = net->part_width();
|
||||||
obj->offset= net->part_offset();
|
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
|
/* Save the primitive properties of the signal in the
|
||||||
ivl_signal_t object. */
|
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->width_ = net->vector_width();
|
||||||
obj->signed_= net->get_signed()? 1 : 0;
|
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->isint_ = false;
|
||||||
obj->local_ = net->local_flag()? 1 : 0;
|
obj->local_ = net->local_flag()? 1 : 0;
|
||||||
obj->forced_net_ = (net->type() != NetNet::REG) &&
|
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_words = net->array_count();
|
||||||
obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0;
|
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: "
|
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
|
||||||
"t-dll creating nexus array " << obj->array_words << " long" << endl;
|
"t-dll creating nexus array " << obj->array_words << " long" << endl;
|
||||||
if (obj->array_words > 1 && net->pins_are_virtual()) {
|
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_dimensions_ : 1;
|
||||||
unsigned array_addr_swapped : 1;
|
unsigned array_addr_swapped : 1;
|
||||||
|
|
||||||
/* These encode the run-time index for the least significant
|
/* These encode the declared packed dimensions for the
|
||||||
bit, and the distance to the second bit. */
|
signal, in case they are needed by the run-time */
|
||||||
signed lsb_index;
|
std::vector<NetNet::range_t> packed_dims;
|
||||||
signed lsb_dist;
|
|
||||||
|
|
||||||
perm_string name_;
|
perm_string name_;
|
||||||
ivl_scope_t scope_;
|
ivl_scope_t scope_;
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ cppcheck: $(O:.o=.c)
|
||||||
cppcheck --enable=all -f $(INCLUDE_PATH) $^
|
cppcheck --enable=all -f $(INCLUDE_PATH) $^
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in ../config.status
|
Makefile: $(srcdir)/Makefile.in ../config.status
|
||||||
cd ..; ./config.status --file=tgt-fpga$@
|
cd ..; ./config.status --file=tgt-fpga/$@
|
||||||
|
|
||||||
dep:
|
dep:
|
||||||
mkdir dep
|
mkdir dep
|
||||||
|
|
@ -83,7 +83,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
fpga.tgt: $O $(TGTDEPLIBS)
|
fpga.tgt: $O $(TGTDEPLIBS)
|
||||||
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
|
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
|
||||||
|
|
||||||
iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man
|
iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man
|
||||||
man -t $(srcdir)/iverilog-fpga.man > iverilog-fpga.ps
|
man -t $(srcdir)/iverilog-fpga.man > iverilog-fpga.ps
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
null.tgt: $O $(TGTDEPLIBS)
|
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
|
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
|
endif
|
||||||
|
|
||||||
pal.tgt: $O $(TGTDEPLIBS)
|
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
|
install: all installdirs $(libdir)/ivl/pal.tgt
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,9 @@ clean:
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile config.log
|
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) $^
|
cppcheck --enable=all -f $(INCLUDE_PATH) $^
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in ../config.status
|
Makefile: $(srcdir)/Makefile.in ../config.status
|
||||||
|
|
@ -68,9 +69,10 @@ Makefile: $(srcdir)/Makefile.in ../config.status
|
||||||
dep:
|
dep:
|
||||||
mkdir dep
|
mkdir dep
|
||||||
|
|
||||||
%.o: %.c
|
stamp-pcb_config-h: $(srcdir)/pcb_config.h.in ../config.status
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
@rm -f $@
|
||||||
mv $*.d dep
|
cd ..; ./config.status --header=tgt-pcb/pcb_config.h
|
||||||
|
pcb_config.h: stamp-pcb_config-h
|
||||||
|
|
||||||
%.o: %.cc
|
%.o: %.cc
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
||||||
|
|
@ -92,7 +94,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pcb.tgt: $O $(TGTDEPLIBS)
|
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
|
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_base.h"
|
||||||
# include "version_tag.h"
|
# include "version_tag.h"
|
||||||
# include "pcb_config.h"
|
# include "pcb_config.h"
|
||||||
# include <string.h>
|
# include <cassert>
|
||||||
|
# include <cstdio>
|
||||||
|
# include <cstring>
|
||||||
# include "pcb_priv.h"
|
# include "pcb_priv.h"
|
||||||
# include "ivl_target.h"
|
# include "ivl_target.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
# include <set>
|
# include <set>
|
||||||
# include <list>
|
# include <list>
|
||||||
# include <map>
|
# include <map>
|
||||||
# include <ivl_target.h>
|
# include "ivl_target.h"
|
||||||
|
|
||||||
extern int scan_scope(ivl_scope_t scope);
|
extern int scan_scope(ivl_scope_t scope);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
# include <map>
|
# include <map>
|
||||||
# include <string>
|
# include <string>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
# include <cstdio>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
@ -85,7 +86,7 @@ int scan_scope(ivl_scope_t scope)
|
||||||
return 0;
|
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);
|
int rc = scan_scope(scope);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# include "pcb_priv.h"
|
# include "pcb_priv.h"
|
||||||
|
# include <cassert>
|
||||||
# include <cstdio>
|
# include <cstdio>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
# include "pcb_config.h"
|
# include "pcb_config.h"
|
||||||
# include "pcb_priv.h"
|
# include "pcb_priv.h"
|
||||||
|
# include <cassert>
|
||||||
|
# include <cstdio>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
stub.tgt: $O $(TGTDEPLIBS)
|
stub.tgt: $O $(TGTDEPLIBS)
|
||||||
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
|
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
|
||||||
|
|
||||||
install: all installdirs $(libdir)/ivl$(suffix)/stub.tgt \
|
install: all installdirs $(libdir)/ivl$(suffix)/stub.tgt \
|
||||||
$(libdir)/ivl$(suffix)/stub.conf $(libdir)/ivl$(suffix)/stub-s.conf
|
$(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) {
|
for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) {
|
||||||
|
|
||||||
ivl_nexus_t nex = ivl_signal_nex(net, idx);
|
ivl_nexus_t nex = ivl_signal_nex(net, idx);
|
||||||
|
unsigned dim;
|
||||||
|
|
||||||
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] "
|
fprintf(out, " %s %s %s%s", type, sign, port, data_type);
|
||||||
"<width=%u%s> <discipline=%s> ",
|
for (dim = 0 ; dim < ivl_signal_packed_dimensions(net) ; dim += 1) {
|
||||||
type, sign, port, data_type,
|
fprintf(out, "[%d:%d]", ivl_signal_packed_msb(net,dim),
|
||||||
ivl_signal_msb(net), ivl_signal_lsb(net),
|
ivl_signal_packed_lsb(net,dim));
|
||||||
|
}
|
||||||
|
fprintf(out, " %s[word=%u, adr=%d] <width=%u%s> <discipline=%s> ",
|
||||||
ivl_signal_basename(net),
|
ivl_signal_basename(net),
|
||||||
idx, ivl_signal_array_base(net)+idx,
|
idx, ivl_signal_array_base(net)+idx,
|
||||||
ivl_signal_width(net),
|
ivl_signal_width(net),
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
verilog.tgt: $O $(TGTDEPLIBS)
|
verilog.tgt: $O $(TGTDEPLIBS)
|
||||||
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
|
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
|
||||||
|
|
||||||
install: all installdirs $(libdir)/ivl/verilog.tgt \
|
install: all installdirs $(libdir)/ivl/verilog.tgt \
|
||||||
$(includedir)/vpi_user.h
|
$(includedir)/vpi_user.h
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
vhdl.tgt: $O $(TGTDEPLIBS)
|
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
|
stamp-vhdl_config-h: $(srcdir)/vhdl_config.h.in ../config.status
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Generate code to convert between VHDL types.
|
* 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
|
* 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
|
* 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
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Helper functions for VHDL syntax elements.
|
* 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
|
* 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
|
* 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 '-';
|
return '-';
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
vlog95.tgt: $O $(TGTDEPLIBS)
|
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
|
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) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
if (first) first = 0;
|
if (first) first = 0;
|
||||||
else fprintf(vlog_out, " or ");
|
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. */
|
/* Check for positive edge events. */
|
||||||
|
|
@ -46,7 +46,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
if (first) first = 0;
|
if (first) first = 0;
|
||||||
else fprintf(vlog_out, " or ");
|
else fprintf(vlog_out, " or ");
|
||||||
fprintf(vlog_out, "posedge ");
|
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. */
|
/* Check for negative edge events. */
|
||||||
|
|
@ -56,7 +56,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
if (first) first = 0;
|
if (first) first = 0;
|
||||||
else fprintf(vlog_out, " or ");
|
else fprintf(vlog_out, " or ");
|
||||||
fprintf(vlog_out, "negedge ");
|
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. */
|
/* 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)
|
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
{
|
{
|
||||||
char *oper = "<invalid>";
|
char *oper = "<invalid>";
|
||||||
switch(ivl_expr_opcode(expr)) {
|
switch (ivl_expr_opcode(expr)) {
|
||||||
case '+': oper = "+"; break;
|
case '+': oper = "+"; break;
|
||||||
case '-': oper = "-"; break;
|
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, "(");
|
fprintf(vlog_out, "(");
|
||||||
switch(ivl_expr_opcode(expr)) {
|
switch (ivl_expr_opcode(expr)) {
|
||||||
case '%':
|
case '%':
|
||||||
if (ivl_expr_value(expr) == IVL_VT_REAL) {
|
if (ivl_expr_value(expr) == IVL_VT_REAL) {
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Real modulus operator "
|
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 {
|
} else {
|
||||||
// HERE: Should this sign extend if the expression is signed?
|
// HERE: Should this sign extend if the expression is signed?
|
||||||
emit_expr(scope, sig_expr, wid);
|
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. */
|
/* A cast is a noop. */
|
||||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||||
break;
|
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:
|
default:
|
||||||
fprintf(vlog_out, "<unknown>");
|
fprintf(vlog_out, "<unknown>");
|
||||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
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_file(expr),
|
||||||
ivl_expr_lineno(expr),
|
ivl_expr_lineno(expr),
|
||||||
ivl_expr_opcode(expr));
|
ivl_expr_opcode(expr));
|
||||||
|
vlog_errors += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
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:
|
case IVL_EX_ARRAY:
|
||||||
emit_expr_array(scope, expr, wid);
|
emit_expr_array(scope, expr, wid);
|
||||||
break;
|
break;
|
||||||
|
|
@ -535,6 +588,14 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
case IVL_EX_DELAY:
|
case IVL_EX_DELAY:
|
||||||
emit_expr_delay(scope, expr, wid);
|
emit_expr_delay(scope, expr, wid);
|
||||||
break;
|
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:
|
case IVL_EX_EVENT:
|
||||||
emit_expr_event(scope, expr, wid);
|
emit_expr_event(scope, expr, wid);
|
||||||
break;
|
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
|
* 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
|
* 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);
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||||
if (ivl_signal_local(sig)) {
|
if (ivl_signal_local(sig)) {
|
||||||
assert(! is_stmt);
|
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;
|
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_driver = 0;
|
||||||
unsigned is_array = 0;
|
unsigned is_array = 0;
|
||||||
int64_t array_idx = 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) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||||
ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr);
|
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. */
|
/* Skip any NULL bytes. */
|
||||||
if (val == 0) continue;
|
if (val == 0) continue;
|
||||||
/* Print some values that must be escapped. */
|
/* Print some values that can be escaped. */
|
||||||
if (val == '"') fprintf(vlog_out, "\\\"");
|
if (val == '"') fprintf(vlog_out, "\\\"");
|
||||||
else 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. */
|
/* Print the printable characters. */
|
||||||
else if (isprint((int)val)) fprintf(vlog_out, "%c", val);
|
else if (isprint((int)val)) fprintf(vlog_out, "%c", val);
|
||||||
/* Print the non-printable characters as an octal escape. */
|
/* 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;
|
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 @*?
|
// 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;
|
ivl_scope_t mod_scope;
|
||||||
/* First look in the local scope for the nexus name. */
|
/* 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;
|
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 there is no signals driving this then look for a constant. */
|
||||||
if (find_const_nexus(scope, nex)) return;
|
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?
|
// HERE: Need to check arr[var]? Can this be rebuilt?
|
||||||
// Then look for down scopes and then any scope. For all this warn if
|
// 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
|
// 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
|
/* It is possible that the nexus does not have a name. For this
|
||||||
* case do not print an actual name. */
|
* case do not print an actual name. */
|
||||||
fprintf(vlog_out, "/* Empty */");
|
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;
|
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. */
|
/* We looked at all the digits, so this is a normal id. */
|
||||||
return 0;
|
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
|
* 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
|
* 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. */
|
/* 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)) {
|
if (is_signed && (msb == '1') && (trim_wid < 32U)) {
|
||||||
value |= ~(((int32_t)1 << trim_wid) - (int32_t)1);
|
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);
|
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
|
* Routine to print a string value as a string after removing any leading
|
||||||
* escaped NULL bytes.
|
* 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)
|
void emit_string(const char* string)
|
||||||
{
|
{
|
||||||
char *buffer = strdup(string);
|
char *buffer = strdup(string);
|
||||||
char *cptr = buffer;
|
char *bptr = buffer;
|
||||||
|
char *cptr;
|
||||||
fprintf(vlog_out, "\"");
|
fprintf(vlog_out, "\"");
|
||||||
/* Prune any leading escaped NULL bytes. */
|
/* Prune any leading escaped NULL bytes. */
|
||||||
while ((cptr[0] == '\\') && (cptr[1] == '0') &&
|
while ((bptr[0] == '\\') && (bptr[1] == '0') &&
|
||||||
(cptr[2] == '0') && (cptr[3] == '0')) cptr += 4;
|
(bptr[2] == '0') && (bptr[3] == '0')) bptr += 4;
|
||||||
if (*cptr) fprintf(vlog_out, "%s", cptr);
|
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);
|
free(buffer);
|
||||||
fprintf(vlog_out, "\"");
|
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));
|
ivl_signal_lineno(sig), ivl_signal_basename(sig));
|
||||||
vlog_errors += 1;
|
vlog_errors += 1;
|
||||||
} else {
|
} else {
|
||||||
switch(ivl_signal_type(sig)) {
|
switch (ivl_signal_type(sig)) {
|
||||||
case IVL_SIT_TRI:
|
case IVL_SIT_TRI:
|
||||||
case IVL_SIT_UWIRE:
|
case IVL_SIT_UWIRE:
|
||||||
// HERE: Need to add support for supply nets. Probably supply strength
|
// 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;
|
if (count == 0) return;
|
||||||
|
|
||||||
fprintf(vlog_out, "(");
|
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) {
|
for (idx = 1; idx < count; idx += 1) {
|
||||||
fprintf(vlog_out, ", ");
|
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, ")");
|
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);
|
assert(nex);
|
||||||
unsigned idx, count = ivl_nexus_ptrs(nex);
|
unsigned idx, count = ivl_nexus_ptrs(nex);
|
||||||
ivl_signal_t sig = 0;
|
ivl_signal_t sig = 0;
|
||||||
|
*word = 0;
|
||||||
for (idx = 0; idx < count; idx += 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||||
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
|
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;
|
if (ivl_signal_scope(t_sig) != scope) continue;
|
||||||
assert(! sig);
|
assert(! sig);
|
||||||
sig = t_sig;
|
sig = t_sig;
|
||||||
|
*word = ivl_nexus_ptr_pin(nex_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sig;
|
return sig;
|
||||||
|
|
@ -475,7 +478,12 @@ static void emit_port(ivl_signal_t port)
|
||||||
}
|
}
|
||||||
emit_sig_type(port);
|
emit_sig_type(port);
|
||||||
fprintf(vlog_out, " ");
|
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, ";");
|
fprintf(vlog_out, ";");
|
||||||
emit_sig_file_line(port);
|
emit_sig_file_line(port);
|
||||||
fprintf(vlog_out, "\n");
|
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)
|
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) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
|
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);
|
if (port) emit_port(port);
|
||||||
else {
|
else {
|
||||||
fprintf(vlog_out, "<missing>");
|
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)
|
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_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. */
|
/* For an input port we need to emit the driving expression. */
|
||||||
if (ivl_signal_port(port) == IVL_SIP_INPUT) {
|
if (ivl_signal_port(port) == IVL_SIP_INPUT) {
|
||||||
emit_nexus_port_driver_as_ca(ivl_scope_parent(scope),
|
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. */
|
/* For an output we need to emit the signal the output is driving. */
|
||||||
} else {
|
} 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");
|
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
|
* 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
|
* 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_BEGIN:
|
||||||
case IVL_SCT_FORK:
|
case IVL_SCT_FORK:
|
||||||
assert(indent != 0);
|
assert(indent != 0);
|
||||||
|
emit_named_block_scope(scope);
|
||||||
return 0; /* A named begin/fork is handled in line. */
|
return 0; /* A named begin/fork is handled in line. */
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Unsupported scope type "
|
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;
|
char *case_type;
|
||||||
unsigned idx, default_case, count = ivl_stmt_case_count(stmt);
|
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_CASE:
|
||||||
case IVL_ST_CASER:
|
case IVL_ST_CASER:
|
||||||
case_type = "case";
|
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)
|
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:
|
case IVL_ST_NOOP:
|
||||||
/* If this is a statement termination then just finish the
|
/* If this is a statement termination then just finish the
|
||||||
* statement, otherwise print an empty begin/end pair. */
|
* 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)
|
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(), ' ');
|
fprintf(vlog_out, "\n%*c", get_indent(), ' ');
|
||||||
switch (ivl_process_type(proc)) {
|
switch (ivl_process_type(proc)) {
|
||||||
case IVL_PR_INITIAL:
|
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_file(proc),
|
||||||
ivl_process_lineno(proc));
|
ivl_process_lineno(proc));
|
||||||
}
|
}
|
||||||
stmt = ivl_process_stmt(proc);
|
|
||||||
if (ivl_statement_type(stmt) == IVL_ST_NOOP) {
|
if (ivl_statement_type(stmt) == IVL_ST_NOOP) {
|
||||||
fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' ');
|
fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' ');
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun)
|
static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun)
|
||||||
{
|
{
|
||||||
const char *value = 0;
|
const char *value = 0;
|
||||||
switch(entry) {
|
switch (entry) {
|
||||||
case '0':
|
case '0':
|
||||||
value = " 0 ";
|
value = " 0 ";
|
||||||
break;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
static const char*version_string =
|
static const char*version_string =
|
||||||
"Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n"
|
"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"
|
" 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"
|
" 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"
|
" 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);
|
fclose(vlog_out);
|
||||||
|
|
||||||
|
/* A do nothing call to prevent warnings about this routine not
|
||||||
|
* being used. */
|
||||||
|
dump_nexus_information(0, 0);
|
||||||
|
|
||||||
return vlog_errors;
|
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_variables(ivl_scope_t scope);
|
||||||
extern void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_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_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_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);
|
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_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_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);
|
extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig);
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
vvp.tgt: $O $(TGTDEPLIBS)
|
vvp.tgt: $O $(TGTDEPLIBS)
|
||||||
$(CC) @shared@ -o $@ $O $(TGTLDFLAGS)
|
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
|
||||||
|
|
||||||
vvp.conf: $(srcdir)/vvp.conf.in Makefile
|
vvp.conf: $(srcdir)/vvp.conf.in Makefile
|
||||||
echo 'flag:VVP_EXECUTABLE=$(bindir)/vvp$(suffix)' | cat $(srcdir)/vvp.conf.in - > vvp.conf
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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 fall_exp = ivl_switch_delay(sw, 1);
|
||||||
ivl_expr_t decay_exp= ivl_switch_delay(sw, 2);
|
ivl_expr_t decay_exp= ivl_switch_delay(sw, 2);
|
||||||
|
|
||||||
/* We do not support tran delays. */
|
|
||||||
if ((rise_exp || fall_exp || decay_exp) &&
|
if ((rise_exp || fall_exp || decay_exp) &&
|
||||||
(!number_is_immediate(rise_exp, 64, 0) ||
|
(!number_is_immediate(rise_exp, 64, 0) ||
|
||||||
number_is_unknown(rise_exp) ||
|
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. */
|
processing doesn't have to deal with it. */
|
||||||
const char*raw = draw_net_input(enable);
|
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 "
|
fprintf(vvp_out, "%s/d .delay 1 "
|
||||||
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n",
|
"(%" 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(fall_exp),
|
||||||
get_number_immediate64(decay_exp), raw);
|
get_number_immediate64(decay_exp), raw);
|
||||||
|
|
||||||
fprintf(vvp_out, "p%p .import I%p, %s/d;\n", enable, island, raw);
|
fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e);
|
||||||
snprintf(str_e_buf, sizeof str_e_buf, "p%p", enable);
|
|
||||||
str_e = str_e_buf;
|
|
||||||
|
|
||||||
} else if (enable) {
|
} else if (enable) {
|
||||||
str_e = draw_island_net_input(island, 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: {
|
case IVL_EX_SELECT: {
|
||||||
ivl_expr_t vexpr = ivl_expr_oper1(expr);
|
ivl_expr_t vexpr = ivl_expr_oper1(expr);
|
||||||
ivl_expr_t bexpr;
|
ivl_expr_t bexpr;
|
||||||
|
ivl_expr_t wexpr;
|
||||||
|
|
||||||
assert(vexpr);
|
assert(vexpr);
|
||||||
|
|
||||||
|
|
@ -179,20 +180,38 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||||
|
|
||||||
/* The signal is part of an array. */
|
/* The signal is part of an array. */
|
||||||
/* Add &APV<> code here when it is finished. */
|
/* Add &APV<> code here when it is finished. */
|
||||||
if (ivl_expr_oper1(vexpr)) return 0;
|
|
||||||
|
|
||||||
bexpr = ivl_expr_oper2(expr);
|
bexpr = ivl_expr_oper2(expr);
|
||||||
|
|
||||||
/* This is a pad operation. */
|
/* This is a pad operation. */
|
||||||
if (!bexpr) return 0;
|
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. */
|
/* 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));
|
assert(! number_is_unknown(bexpr));
|
||||||
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
|
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
|
||||||
ivl_expr_signal(vexpr),
|
ivl_expr_signal(vexpr),
|
||||||
get_number_immediate(bexpr),
|
get_number_immediate(bexpr),
|
||||||
ivl_expr_width(expr));
|
ivl_expr_width(expr));
|
||||||
|
|
||||||
/* This is an indexed bit/part select. */
|
/* This is an indexed bit/part select. */
|
||||||
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL ||
|
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL ||
|
||||||
ivl_expr_type(bexpr) == IVL_EX_SELECT) {
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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)
|
static struct vector_info increment(ivl_expr_t e, unsigned wid, bool pre)
|
||||||
{
|
{
|
||||||
ivl_signal_t s;
|
ivl_signal_t s = 0;
|
||||||
unsigned w;
|
unsigned w = 0;
|
||||||
struct vector_info r;
|
struct vector_info r;
|
||||||
struct vector_info rc;
|
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)
|
static struct vector_info decrement(ivl_expr_t e, unsigned wid, bool pre)
|
||||||
{
|
{
|
||||||
ivl_signal_t s;
|
ivl_signal_t s = 0;
|
||||||
unsigned w;
|
unsigned w = 0;
|
||||||
struct vector_info r;
|
struct vector_info r;
|
||||||
struct vector_info rc;
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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",
|
fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
|
||||||
ivl_expr_opcode(expr));
|
ivl_expr_opcode(expr));
|
||||||
assert(0);
|
assert(0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int draw_eval_real(ivl_expr_t expr)
|
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)
|
static void draw_reg_in_scope(ivl_signal_t sig)
|
||||||
{
|
{
|
||||||
int msb = ivl_signal_msb(sig);
|
int msb;
|
||||||
int lsb = ivl_signal_lsb(sig);
|
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" :
|
const char*datatype_flag = ivl_signal_integer(sig) ? "/i" :
|
||||||
ivl_signal_signed(sig)? "/s" : "";
|
ivl_signal_signed(sig)? "/s" : "";
|
||||||
|
|
|
||||||
|
|
@ -110,9 +110,11 @@ parse.o: parse.cc
|
||||||
lexor.cc: $(srcdir)/lexor.lex
|
lexor.cc: $(srcdir)/lexor.lex
|
||||||
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
|
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
|
||||||
|
|
||||||
parse.cc parse.h: $(srcdir)/parse.y
|
# Build this in two steps to avoid parallel build issues (see pr3462585)
|
||||||
$(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y
|
parse.cc: $(srcdir)/parse.y
|
||||||
mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h
|
$(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
|
lexor_keyword.o: lexor_keyword.cc parse.h
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,24 +124,28 @@ endif
|
||||||
system.vpi: $O $(OPP) ../vvp/libvpi.a
|
system.vpi: $O $(OPP) ../vvp/libvpi.a
|
||||||
$(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
$(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
sys_readmem_lex.c: sys_readmem_lex.lex
|
sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex
|
||||||
$(LEX) -t $(srcdir)/sys_readmem_lex.lex > sys_readmem_lex.c
|
$(LEX) -t $< > $@
|
||||||
|
|
||||||
sdf_lexor.o: sdf_lexor.c sdf_parse.h
|
sdf_lexor.o: sdf_lexor.c sdf_parse.h
|
||||||
|
|
||||||
sdf_lexor.c: sdf_lexor.lex
|
sdf_lexor.c: $(srcdir)/sdf_lexor.lex
|
||||||
$(LEX) -t $(srcdir)/sdf_lexor.lex > sdf_lexor.c
|
$(LEX) -t $< > $@
|
||||||
|
|
||||||
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
|
# Build this in two steps to avoid parallel build issues (see pr3462585)
|
||||||
$(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y
|
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.o: table_mod_lexor.c table_mod_parse.h
|
||||||
|
|
||||||
table_mod_lexor.c: $(srcdir)/table_mod_lexor.lex
|
table_mod_lexor.c: $(srcdir)/table_mod_lexor.lex
|
||||||
$(LEX) -t $< > $@
|
$(LEX) -t $< > $@
|
||||||
|
|
||||||
table_mod_parse.c table_mod_parse.h: $(srcdir)/table_mod_parse.y
|
# Build this in two steps to avoid parallel build issues (see pr3462585)
|
||||||
$(YACC) --verbose -d -p tblmod -o table_mod_parse.c $<
|
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
|
v2005_math.vpi: $M ../vvp/libvpi.a
|
||||||
$(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
$(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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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,
|
static void get_time(char *rtn, const char *value, int prec,
|
||||||
PLI_INT32 time_units)
|
PLI_INT32 time_units)
|
||||||
{
|
{
|
||||||
int head, tail;
|
|
||||||
int shift = time_units - timeformat_info.units;
|
int shift = time_units - timeformat_info.units;
|
||||||
|
|
||||||
/* Strip any leading zeros, but leave a single zero. */
|
/* 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. */
|
/* We need to scale the number down. */
|
||||||
} else {
|
} 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. */
|
/* We have digits to the left of the decimal point. */
|
||||||
if (head > 0) {
|
if (head > 0) {
|
||||||
strncpy(rtn, value, head);
|
strncpy(rtn, value, head);
|
||||||
|
|
@ -222,18 +223,18 @@ static void get_time(char *rtn, const char *value, int prec,
|
||||||
strcpy(rtn, "0");
|
strcpy(rtn, "0");
|
||||||
if (prec > 0) strcat(rtn, ".");
|
if (prec > 0) strcat(rtn, ".");
|
||||||
/* Add leading zeros as needed. */
|
/* Add leading zeros as needed. */
|
||||||
head = -shift - 1;
|
head = -head;
|
||||||
if (head > prec) head = prec;
|
if (head > prec) head = prec;
|
||||||
while (head > 0) {
|
while (head > 0) {
|
||||||
strcat(rtn, "0");
|
strcat(rtn, "0");
|
||||||
head -= 1;
|
head -= 1;
|
||||||
}
|
}
|
||||||
/* Add digits from the value if they fit. */
|
/* Add digits from the value if they fit. */
|
||||||
tail = prec + shift + 1;
|
tail = prec + len + shift;
|
||||||
if (tail > 0) {
|
if (tail > 0) {
|
||||||
strncat(rtn, value, tail);
|
strncat(rtn, value, tail);
|
||||||
/* Add trailing zeros to fill out the precision. */
|
/* Add trailing zeros to fill out the precision. */
|
||||||
tail = prec + shift + 1 - strlen(value);
|
tail = prec + shift + 1 - len;
|
||||||
while (tail > 0) {
|
while (tail > 0) {
|
||||||
strcat(rtn, "0");
|
strcat(rtn, "0");
|
||||||
tail -= 1;
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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);
|
vpi_free_object(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
words = (width+31)/32;
|
assert(width > 0);
|
||||||
|
words = (width - 1)/32 + 1;
|
||||||
vector = calloc(words, sizeof(s_vpi_vecval));
|
vector = calloc(words, sizeof(s_vpi_vecval));
|
||||||
bpe = (width+7)/8;
|
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
|
* 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
|
* 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
|
/* Check that the first count arguments are numeric. Currently
|
||||||
* only three are needed/supported. */
|
* only three are needed/supported. */
|
||||||
for (idx = 0; idx < count; idx += 1) {
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
char *loc;
|
char *loc = NULL;
|
||||||
vpiHandle arg = vpi_scan(argv);
|
vpiHandle arg = vpi_scan(argv);
|
||||||
|
|
||||||
/* Get the name for this argument. */
|
/* 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_register_cb(&cb);
|
||||||
vpi_put_userdata(sys, mon);
|
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);
|
arg = vpi_scan(argv);
|
||||||
if (arg != 0) {
|
if (arg != 0) {
|
||||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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.sizetf = 0;
|
||||||
tf_data.user_data = "$vpi_tree";
|
tf_data.user_data = "$vpi_tree";
|
||||||
res = vpi_register_systf(&tf_data);
|
res = vpi_register_systf(&tf_data);
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*vlog_startup_routines[])() = {
|
void (*vlog_startup_routines[])() = {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __vpi_user_H
|
#ifndef __vpi_user_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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"
|
# include "_pli_types.h"
|
||||||
|
|
||||||
#define ICARUS_VPI_CONST
|
#define ICARUS_VPI_CONST
|
||||||
|
#ifdef __cplusplus
|
||||||
|
typedef class __vpiHandle *vpiHandle;
|
||||||
|
#else
|
||||||
typedef struct __vpiHandle *vpiHandle;
|
typedef struct __vpiHandle *vpiHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This structure is created by the VPI application to provide hooks
|
* 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)
|
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
|
||||||
else
|
else
|
||||||
libvpi.a: libvpi.c
|
libvpi.a: libvpi.c
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
|
||||||
rm -f libvpi.a
|
rm -f libvpi.a
|
||||||
$(AR) cqv libvpi.a libvpi.o
|
$(AR) cqv libvpi.a libvpi.o
|
||||||
$(RANLIB) libvpi.a
|
$(RANLIB) libvpi.a
|
||||||
|
|
@ -157,11 +157,11 @@ parse.o: parse.cc
|
||||||
|
|
||||||
tables.o: tables.cc
|
tables.o: tables.cc
|
||||||
|
|
||||||
|
# Build this in two steps to avoid parallel build issues (see pr3462585)
|
||||||
parse.cc: $(srcdir)/parse.y
|
parse.cc: $(srcdir)/parse.y
|
||||||
$(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y
|
$(YACC) --verbose -t -d -o $@ $<
|
||||||
|
|
||||||
parse.h: parse.cc
|
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
|
lexor.cc: $(srcdir)/lexor.lex
|
||||||
$(LEX) -s -olexor.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"
|
#include "vpi_user.h"
|
||||||
|
|
||||||
typedef struct __vpiArray* vvp_array_t;
|
typedef struct __vpiArray* vvp_array_t;
|
||||||
|
class value_callback;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function tries to find the array (by label) in the global
|
* 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 */
|
/* VPI hooks */
|
||||||
|
|
||||||
extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word);
|
extern value_callback* vpip_array_word_change(p_cb_data data);
|
||||||
extern void vpip_array_change(struct __vpiCallback*cb, vpiHandle word);
|
extern value_callback* vpip_array_change(p_cb_data data);
|
||||||
|
|
||||||
/* Compile hooks */
|
/* Compile hooks */
|
||||||
extern void compile_varw_real(char*label, vvp_array_t array,
|
extern void compile_varw_real(char*label, vvp_array_t array,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __codes_H
|
#ifndef __codes_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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_net_t *net;
|
||||||
vvp_code_t cptr;
|
vvp_code_t cptr;
|
||||||
vvp_array_t array;
|
vvp_array_t array;
|
||||||
struct __vpiHandle*handle;
|
class __vpiHandle*handle;
|
||||||
struct __vpiScope*scope;
|
struct __vpiScope*scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue