Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl

This commit is contained in:
Nick Gasson 2008-11-12 22:15:57 +00:00
commit f1a2e71aab
81 changed files with 1310 additions and 484 deletions

View File

@ -21,10 +21,6 @@
# include "AStatement.h"
AStatement::~AStatement()
{
}
AContrib::AContrib(PExpr*lv, PExpr*rv)
: lval_(lv), rval_(rv)
{

View File

@ -20,37 +20,30 @@
*/
# include <map>
# include "ivl_target.h"
# include "StringHeap.h"
# include "LineInfo.h"
# include "Statement.h"
# include "PExpr.h"
class PExpr;
class AStatement : public LineInfo {
public:
AStatement() { }
virtual ~AStatement() =0;
virtual void dump(ostream&out, unsigned ind) const;
private: // not implemented
AStatement(const AStatement&);
AStatement& operator= (const AStatement&);
};
class NetAnalog;
class NetScope;
class Design;
/*
* A contribution statement is like an assignment: there is an l-value
* expression and an r-value expression. The l-value is a branch probe
* expression.
*/
class AContrib : public AStatement {
class AContrib : public Statement {
public:
AContrib(PExpr*lval, PExpr*rval);
~AContrib();
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
private:
PExpr*lval_;
@ -65,21 +58,24 @@ class AContrib : public AStatement {
class AProcess : public LineInfo {
public:
enum Type { PR_INITIAL, PR_ALWAYS };
AProcess(Type t, AStatement*st)
AProcess(ivl_process_type_t t, Statement*st)
: type_(t), statement_(st) { }
~AProcess();
bool elaborate(Design*des, NetScope*scope) const;
ivl_process_type_t type() const { return type_; }
Statement*statement() { return statement_; }
map<perm_string,PExpr*> attributes;
// Dump the analog process
void dump(ostream&out, unsigned ind) const;
private:
Type type_;
AStatement*statement_;
ivl_process_type_t type_;
Statement*statement_;
private: // not implemented
AProcess(const AProcess&);

View File

@ -116,11 +116,12 @@ distclean: clean
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o elab_expr.o \
O = main.o async.o design_dump.o discipline.o dup_expr.o \
elaborate.o elab_expr.o elaborate_analog.o \
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \
elab_sig.o emit.o eval.o eval_attrib.o \
elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
load_module.o netlist.o netmisc.o net_assign.o \
load_module.o netlist.o netmisc.o net_analog.o net_assign.o \
net_design.o net_event.o net_expr.o net_func.o \
net_link.o net_modulo.o net_nex_input.o net_nex_output.o \
net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \

View File

@ -43,7 +43,7 @@ void Module::add_gate(PGate*gate)
unsigned Module::port_count() const
{
return ports.count();
return ports.size();
}
/*
@ -51,10 +51,10 @@ unsigned Module::port_count() const
* module. If the port is internally unconnected, return an empty
* array.
*/
const svector<PEIdent*>& Module::get_port(unsigned idx) const
const vector<PEIdent*>& Module::get_port(unsigned idx) const
{
assert(idx < ports.count());
static svector<PEIdent*> zero;
assert(idx < ports.size());
static const vector<PEIdent*> zero;
if (ports[idx])
return ports[idx]->expr;
@ -65,7 +65,7 @@ const svector<PEIdent*>& Module::get_port(unsigned idx) const
unsigned Module::find_port(const char*name) const
{
assert(name != 0);
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < ports.size() ; idx += 1) {
if (ports[idx] == 0) {
/* It is possible to have undeclared ports. These
are ports that are skipped in the declaration,
@ -79,7 +79,7 @@ unsigned Module::find_port(const char*name) const
return idx;
}
return ports.count();
return ports.size();
}

View File

@ -22,8 +22,8 @@
# include <list>
# include <map>
# include <vector>
# include <utility>
# include "svector.h"
# include "StringHeap.h"
# include "HName.h"
# include "named.h"
@ -59,7 +59,7 @@ class Module : public PScope, public LineInfo {
public:
struct port_t {
perm_string name;
svector<PEIdent*> expr;
vector<PEIdent*> expr;
};
public:
@ -98,7 +98,7 @@ class Module : public PScope, public LineInfo {
/* This is an array of port descriptors, which is in turn a
named array of PEident pointers. */
svector<port_t*> ports;
vector<port_t*> ports;
map<perm_string,PExpr*> attributes;
@ -126,7 +126,7 @@ class Module : public PScope, public LineInfo {
void add_gate(PGate*gate);
unsigned port_count() const;
const svector<PEIdent*>& get_port(unsigned idx) const;
const vector<PEIdent*>& get_port(unsigned idx) const;
unsigned find_port(const char*name) const;
PGate* get_gate(perm_string name);

View File

@ -24,6 +24,7 @@
# include "compiler.h"
# include "PExpr.h"
# include "Module.h"
# include "netmisc.h"
# include <typeinfo>
PExpr::PExpr()
@ -35,6 +36,11 @@ PExpr::~PExpr()
{
}
bool PExpr::has_aa_term(Design*, NetScope*) const
{
return false;
}
bool PExpr::is_the_same(const PExpr*that) const
{
return typeid(this) == typeid(that);
@ -64,6 +70,12 @@ PEBinary::~PEBinary()
{
}
bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
{
assert(left_ && right_);
return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope);
}
PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r)
{
@ -130,6 +142,15 @@ PECallFunction::~PECallFunction()
{
}
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
flag = parms_[idx]->has_aa_term(des, scope) || flag;
}
return flag;
}
PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
: parms_(p), repeat_(r)
{
@ -140,6 +161,18 @@ PEConcat::~PEConcat()
delete repeat_;
}
bool PEConcat::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
flag = parms_[idx]->has_aa_term(des, scope) || flag;
}
if (repeat_)
flag = repeat_->has_aa_term(des, scope) || flag;
return flag;
}
PEEvent::PEEvent(PEEvent::edge_t t, PExpr*e)
: type_(t), expr_(e)
{
@ -154,6 +187,12 @@ PEEvent::edge_t PEEvent::type() const
return type_;
}
bool PEEvent::has_aa_term(Design*des, NetScope*scope) const
{
assert(expr_);
return expr_->has_aa_term(des, scope);
}
PExpr* PEEvent::expr() const
{
return expr_;
@ -188,6 +227,22 @@ PEIdent::~PEIdent()
{
}
bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
{
NetNet* net = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
const NetExpr*ex1, *ex2;
scope = symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2);
if (scope)
return scope->is_auto();
else
return false;
}
PENumber::PENumber(verinum*vp)
: value_(vp)
{
@ -237,6 +292,14 @@ PETernary::~PETernary()
{
}
bool PETernary::has_aa_term(Design*des, NetScope*scope) const
{
assert(expr_ && tru_ && fal_);
return expr_->has_aa_term(des, scope)
|| tru_->has_aa_term(des, scope)
|| fal_->has_aa_term(des, scope);
}
PEUnary::PEUnary(char op, PExpr*ex)
: op_(op), expr_(ex)
{
@ -245,3 +308,9 @@ PEUnary::PEUnary(char op, PExpr*ex)
PEUnary::~PEUnary()
{
}
bool PEUnary::has_aa_term(Design*des, NetScope*scope) const
{
assert(expr_);
return expr_->has_aa_term(des, scope);
}

20
PExpr.h
View File

@ -46,6 +46,10 @@ class PExpr : public LineInfo {
virtual void dump(ostream&) const;
// This method tests whether the expression contains any
// references to automatically allocated variables.
virtual bool has_aa_term(Design*des, NetScope*scope) const;
// This method tests the width that the expression wants to
// be. It is used by elaboration of assignments to figure out
// the width of the expression.
@ -156,6 +160,8 @@ class PEConcat : public PExpr {
virtual verinum* eval_const(Design*des, NetScope*sc) const;
virtual void dump(ostream&) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
@ -200,6 +206,8 @@ class PEEvent : public PExpr {
virtual void dump(ostream&) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
private:
edge_t type_;
PExpr *expr_;
@ -247,6 +255,9 @@ class PEIdent : public PExpr {
void append_name(perm_string);
virtual void dump(ostream&) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
@ -420,6 +431,8 @@ class PEUnary : public PExpr {
virtual void dump(ostream&out) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
@ -448,6 +461,8 @@ class PEBinary : public PExpr {
virtual void dump(ostream&out) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
@ -541,6 +556,9 @@ class PETernary : public PExpr {
~PETernary();
virtual void dump(ostream&out) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
@ -579,6 +597,8 @@ class PECallFunction : public PExpr {
virtual void dump(ostream &) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool sys_task_arg) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;

View File

@ -198,13 +198,13 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
}
}
void PWire::set_discipline(discipline_t*d)
void PWire::set_discipline(ivl_discipline_t d)
{
assert(discipline_ == 0);
discipline_ = d;
}
discipline_t* PWire::get_discipline(void) const
ivl_discipline_t PWire::get_discipline(void) const
{
return discipline_;
}

10
PWire.h
View File

@ -18,9 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PWire.h,v 1.21 2007/05/24 04:07:11 steve Exp $"
#endif
# include "netlist.h"
# include "LineInfo.h"
@ -36,7 +33,6 @@ class ostream;
class PExpr;
class Design;
class discipline_t;
/*
* The different type of PWire::set_range() calls.
@ -82,8 +78,8 @@ class PWire : public LineInfo {
void set_memory_idx(PExpr*ldx, PExpr*rdx);
void set_discipline(discipline_t*);
discipline_t* get_discipline(void) const;
void set_discipline(ivl_discipline_t);
ivl_discipline_t get_discipline(void) const;
map<perm_string,PExpr*> attributes;
@ -115,7 +111,7 @@ class PWire : public LineInfo {
PExpr*lidx_;
PExpr*ridx_;
discipline_t*discipline_;
ivl_discipline_t discipline_;
private: // not implemented
PWire(const PWire&);

View File

@ -228,6 +228,15 @@ void PEventStatement::set_statement(Statement*st)
statement_ = st;
}
bool PEventStatement::has_aa_term(Design*des, NetScope*scope)
{
bool flag = false;
for (unsigned idx = 0 ; idx < expr_.count() ; idx += 1) {
flag = expr_[idx]->has_aa_term(des, scope) || flag;
}
return flag;
}
PForce::PForce(PExpr*l, PExpr*r)
: lval_(l), expr_(r)
{

View File

@ -20,6 +20,7 @@
*/
# include <string>
# include "ivl_target.h"
# include "svector.h"
# include "StringHeap.h"
# include "PDelays.h"
@ -46,16 +47,14 @@ class NetScope;
class PProcess : public LineInfo {
public:
enum Type { PR_INITIAL, PR_ALWAYS };
PProcess(Type t, Statement*st)
PProcess(ivl_process_type_t t, Statement*st)
: type_(t), statement_(st) { }
virtual ~PProcess();
bool elaborate(Design*des, NetScope*scope) const;
Type type() const { return type_; }
ivl_process_type_t type() const { return type_; }
Statement*statement() { return statement_; }
map<perm_string,PExpr*> attributes;
@ -63,7 +62,7 @@ class PProcess : public LineInfo {
virtual void dump(ostream&out, unsigned ind) const;
private:
Type type_;
ivl_process_type_t type_;
Statement*statement_;
};
@ -348,6 +347,8 @@ class PEventStatement : public Statement {
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const;
bool has_aa_term(Design*des, NetScope*scope);
// This method is used to elaborate, but attach a previously
// elaborated statement to the event.
NetProc* elaborate_st(Design*des, NetScope*scope, NetProc*st) const;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: async.cc,v 1.7 2004/01/18 23:26:54 steve Exp $"
#endif
# include "config.h"
@ -87,34 +84,8 @@ bool NetProc::is_asynchronous()
bool NetProcTop::is_asynchronous()
{
if (type_ == NetProcTop::KINITIAL)
if (type_ == IVL_PR_INITIAL)
return false;
return statement_->is_asynchronous();
}
/*
* $Log: async.cc,v $
* Revision 1.7 2004/01/18 23:26:54 steve
* The is_combinational function really need not recurse.
*
* Revision 1.6 2003/12/20 00:33:39 steve
* More thorough check that NetEvWait is asynchronous.
*
* Revision 1.5 2003/09/04 20:28:05 steve
* Support time0 resolution of combinational threads.
*
* Revision 1.4 2002/08/18 22:07:16 steve
* Detect temporaries in sequential block synthesis.
*
* Revision 1.3 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.2 2002/07/04 00:24:16 steve
* initial statements are not asynchronous.
*
* Revision 1.1 2002/06/30 02:21:31 steve
* Add structure for asynchronous logic synthesis.
*
*/

View File

@ -189,7 +189,7 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
break;
}
if (discipline_t*dis = get_discipline())
if (ivl_discipline_t dis = get_discipline())
o << " discipline=" << dis->name();
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
@ -702,11 +702,11 @@ void NetUDP::dump_node(ostream&o, unsigned ind) const
void NetProcTop::dump(ostream&o, unsigned ind) const
{
switch (type_) {
case NetProcTop::KINITIAL:
case IVL_PR_INITIAL:
o << "initial /* " << get_fileline() << " in "
<< scope_path(scope_) << " */" << endl;
break;
case NetProcTop::KALWAYS:
case IVL_PR_ALWAYS:
o << "always /* " << get_fileline() << " in "
<< scope_path(scope_) << " */" << endl;
break;
@ -720,6 +720,23 @@ void NetProcTop::dump(ostream&o, unsigned ind) const
statement_->dump(o, ind+2);
}
void NetAnalogTop::dump(ostream&o, unsigned ind) const
{
switch (type_) {
case IVL_PR_INITIAL:
o << "analog initial /* " << get_fileline() << " in "
<< scope_path(scope_) << " */" << endl;
break;
case IVL_PR_ALWAYS:
o << "analog /* " << get_fileline() << " in "
<< scope_path(scope_) << " */" << endl;
break;
}
statement_->dump(o, ind+2);
}
void NetAlloc::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "// allocate storage : " << scope_path(scope_) << endl;
@ -868,6 +885,15 @@ void NetCondit::dump(ostream&o, unsigned ind) const
}
}
void NetContribution::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
lval_->dump(o);
o << " <+ ";
rval_->dump(o);
o << ";" << endl;
}
void NetDeassign::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "deassign ";
@ -1491,4 +1517,6 @@ void Design::dump(ostream&o) const
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
idx->dump(o, 0);
for (const NetAnalogTop*idx = aprocs_ ; idx ; idx = idx->next_)
idx->dump(o, 0);
}

View File

@ -10,7 +10,7 @@ participating in the Icarus Verilog development process. That
information will not be repeated here.
What this documentation *will* cover is the gross structure of the
Icarus Verilog core compiler source. This will help orient you to the
Icarus Verilog compiler source. This will help orient you to the
source code itself, so that you can find the global parts where you
can look for even better detail.
@ -40,7 +40,7 @@ on the core itself.
- The loadable code generators (tgt-*/)
This core compiler, after it is finished with parsing and semantic
analysis, uses loadable code generators to emit code for suppoted
analysis, uses loadable code generators to emit code for supported
targets. The tgt-*/ directories contains the source for the target
code generators that are bundled with Icarus Verilog. The tgt-vvp/
directory in particular contains the code generator for the vvp
@ -65,20 +65,20 @@ and the source is in this subdirectory.
The Icarus Verilog support for the deprecated PLI-1 is in this
subdirectory. The vvp runtime does not directly support the
PLI-1. Insead, the libveriuser library emulates it using the builtin
PLI-1. Instead, the libveriuser library emulates it using the builtin
PLI-2 support.
- The Cadence PLI module compatibility module (cadpli/)
It is possible in some specialized situations to load and execute
PLI-1 code writen for Verilog-XL. This directory contains the source
PLI-1 code written for Verilog-XL. This directory contains the source
for the module that provides the Cadence PLI interface.
* The Core Compiler
The "ivl" binary is the core compiler that does the heavy lifting of
compiling the Veriog source (including libraries) and generating the
compiling the Verilog source (including libraries) and generating the
output. This is the most complex component of the Icarus Verilog
compilation system.
@ -86,8 +86,8 @@ The process in the abstract starts with the Verilog lexical analysis
and parsing to generate an internal "pform". The pform is then
translated by elaboration into the "netlist" form. The netlist is
processed by some functors (which include some optimizations and
optional synthesys) then is translated into the ivl_target internal
form. And finallly, the ivl_target form is passed via the ivl_target.h
optional synthesis) then is translated into the ivl_target internal
form. And finally, the ivl_target form is passed via the ivl_target.h
API to the code generators.
- Lexical Analysis
@ -105,9 +105,9 @@ large set of potential keywords.
- Parsing
The parser input file "parse.y" is passed to the "bison" program to
generate the parser. The parser uses the functions in parse*.,
parse*.cc, pform*.h and pform*.cc to generate the pform from the
stream of input tokens. The pfrom is what compiler writers call a
generate the parser. The parser uses the functions in parse*.h,
parse*.cc, pform.h, and pform*.cc to generate the pform from the
stream of input tokens. The pform is what compiler writers call a
"decorated parse tree".
The pform itself is described by the classes in the header files

View File

@ -28,12 +28,12 @@ nature_t::~nature_t()
{
}
discipline_t::discipline_t(perm_string name__, ddomain_t domain__,
ivl_discipline_s::ivl_discipline_s(perm_string name__, ivl_dis_domain_t domain__,
nature_t*pot, nature_t*flow__)
: name_(name__), domain_(domain__), potential_(pot), flow_(flow__)
{
}
discipline_t::~discipline_t()
ivl_discipline_s::~ivl_discipline_s()
{
}

View File

@ -28,10 +28,10 @@
# include "StringHeap.h"
# include <iostream>
# include <map>
# include "ivl_target.h"
# include "LineInfo.h"
typedef enum { DD_NONE, DD_DISCRETE, DD_CONTINUOUS } ddomain_t;
extern std::ostream& operator << (std::ostream&, ddomain_t);
extern std::ostream& operator << (std::ostream&, ivl_dis_domain_t);
class nature_t : public LineInfo {
public:
@ -47,30 +47,30 @@ class nature_t : public LineInfo {
perm_string access_;
};
class discipline_t : public LineInfo {
class ivl_discipline_s : public LineInfo {
public:
explicit discipline_t (perm_string name, ddomain_t dom,
explicit ivl_discipline_s (perm_string name, ivl_dis_domain_t dom,
nature_t*pot, nature_t*flow);
~discipline_t();
~ivl_discipline_s();
perm_string name() const { return name_; }
ddomain_t domain() const { return domain_; }
ivl_dis_domain_t domain() const { return domain_; }
const nature_t*potential() const { return potential_; }
const nature_t*flow() const { return flow_; }
private:
perm_string name_;
ddomain_t domain_;
ivl_dis_domain_t domain_;
nature_t*potential_;
nature_t*flow_;
private: // not implemented
discipline_t(const discipline_t&);
discipline_t& operator = (const discipline_t&);
ivl_discipline_s(const ivl_discipline_s&);
ivl_discipline_s& operator = (const ivl_discipline_s&);
};
extern map<perm_string,nature_t*> natures;
extern map<perm_string,discipline_t*> disciplines;
extern map<perm_string,ivl_discipline_t> disciplines;
// Map access function name to the nature that it accesses.
extern map<perm_string,nature_t*> access_function_nature;

View File

@ -263,6 +263,7 @@ static const char*my_tempfile(const char*str, FILE**fout)
static int t_version_only(void)
{
remove(source_path);
free(source_path);
fflush(0);
snprintf(tmp, sizeof tmp, "%s%civlpp -V", pbase, sep);
@ -275,8 +276,11 @@ static int t_version_only(void)
if ( ! getenv("IVERILOG_ICONFIG")) {
remove(iconfig_path);
free(iconfig_path);
remove(defines_path);
free(defines_path);
remove(compiled_defines_path);
free(compiled_defines_path);
}
return 0;
@ -314,11 +318,15 @@ static int t_preprocess_only(void)
rc = system(cmd);
remove(source_path);
free(source_path);
if ( ! getenv("IVERILOG_ICONFIG")) {
remove(iconfig_path);
free(iconfig_path);
remove(defines_path);
free(defines_path);
remove(compiled_defines_path);
free(compiled_defines_path);
}
if (rc != 0) {
@ -332,6 +340,7 @@ static int t_preprocess_only(void)
return -1;
}
free(cmd);
return 0;
}
@ -410,9 +419,13 @@ static int t_compile()
rc = system(cmd);
if ( ! getenv("IVERILOG_ICONFIG")) {
remove(source_path);
free(source_path);
remove(iconfig_path);
free(iconfig_path);
remove(defines_path);
free(defines_path);
remove(compiled_defines_path);
free(compiled_defines_path);
}
#ifdef __MINGW32__ /* MinGW just returns the exit status, so return it! */
free(cmd);

View File

@ -138,6 +138,14 @@ NetEUFunc* NetEUFunc::dup_expr() const
return tmp;
}
NetEUBits* NetEUBits::dup_expr() const
{
NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr());
assert(tmp);
tmp->set_line(*this);
return tmp;
}
NetEUnary* NetEUnary::dup_expr() const
{
NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr());

View File

@ -404,6 +404,16 @@ NetExpr* PEBinary::elaborate_expr_base_div_(Design*des,
}
}
/* The original elaboration of the left and right expressions
already tried to elaborate to the expr_wid. If the
expressions are not that width by now, then they need to be
padded. The divide expression operands must be the width
of the output. */
if (expr_wid > 0) {
lp = pad_to_width(lp, expr_wid);
rp = pad_to_width(rp, expr_wid);
}
NetEBDiv*tmp = new NetEBDiv(op_, lp, rp);
tmp->set_line(*this);
@ -1231,7 +1241,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
NetNet*sig = scope->find_signal(name);
ivl_assert(*this, sig);
discipline_t*dis = sig->get_discipline();
ivl_discipline_t dis = sig->get_discipline();
ivl_assert(*this, dis);
ivl_assert(*this, nature == dis->potential() || nature == dis->flow());
@ -1349,12 +1359,26 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope,
{
expr_type_ = IVL_VT_LOGIC;
unsigned count_width = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
count_width += parms_[idx]->test_width(des, scope, 0, 0, expr_type__, unsized_flag);
if (repeat_) {
// The repeat expression is self-determined and its own type.
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
bool tmp_flag = false;
repeat_->test_width(des, scope, 0, 0, tmp_type, tmp_flag);
count_width = 0;
if (debug_elaborate)
cerr << get_fileline() << ": debug: CONCAT MISSING TEST_WIDTH!" << endl;
cerr << get_fileline() << ": debug: "
<< "CONCAT MISSING TEST_WIDTH WHEN REPEAT IS PRESENT!"
<< endl;
}
expr_type__ = expr_type_;
unsized_flag = false;
return 0;
return count_width;
}
// Keep track of the concatenation/repeat depth.

View File

@ -40,6 +40,7 @@
# include "PTask.h"
# include "PWire.h"
# include "Statement.h"
# include "AStatement.h"
# include "netlist.h"
# include "util.h"
# include <typeinfo>
@ -1122,8 +1123,9 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
? NetScope::FORK_JOIN
: NetScope::BEGIN_END);
my_scope->set_line(get_file(), get_lineno());
my_scope->is_auto(scope->is_auto());
// Scan the parameters in the module, and create stub parameter
// Scan the parameters in the scope, and create stub parameter
// entries in the scope for the parameter names.
collect_scope_parameters_(my_scope, parameters);

View File

@ -150,7 +150,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
// Scan all the ports of the module, and make sure that each
// is connected to wires that have port declarations.
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < ports.size() ; idx += 1) {
Module::port_t*pp = ports[idx];
if (pp == 0)
continue;
@ -159,7 +159,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
// expression are all identifiers that should reference
// wires within the scope.
map<perm_string,PWire*>::const_iterator wt;
for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) {
for (unsigned cc = 0 ; cc < pp->expr.size() ; cc += 1) {
pform_name_t port_path (pp->expr[cc]->path());
// A concatenated wire of a port really should not
// have any hierarchy.
@ -365,7 +365,7 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
NetScope::scope_vec_t instance = scope->instance_arrays[get_name()];
for (unsigned idx = 0 ; idx < instance.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < instance.size() ; idx += 1) {
// I know a priori that the elaborate_scope created the scope
// already, so just look it up as a child of the current scope.
NetScope*my_scope = instance[idx];
@ -1055,7 +1055,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
sig->set_signed(get_signed());
sig->set_isint(get_isint());
if (discipline_t*dis = get_discipline()) {
if (ivl_discipline_t dis = get_discipline()) {
sig->set_discipline(dis);
}

26
elab_sig_analog.cc Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "AStatement.h"
# include <cstdlib>
# include <iostream>

View File

@ -938,7 +938,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
return tmp;
}
static bool need_bufz_for_input_port(const svector<NetNet*>&prts)
static bool need_bufz_for_input_port(const vector<NetNet*>&prts)
{
if (prts[0]->port_type() != NetNet::PINPUT)
return false;
@ -1051,7 +1051,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// later.
NetScope::scope_vec_t&instance = scope->instance_arrays[get_name()];
for (unsigned inst = 0 ; inst < instance.count() ; inst += 1) {
for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) {
rmod->elaborate(des, instance[inst]);
}
@ -1079,8 +1079,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// input. If so, consider printing a port binding
// warning.
if (warn_portbinding) {
svector<PEIdent*> mport = rmod->get_port(idx);
if (mport.count() == 0)
vector<PEIdent*> mport = rmod->get_port(idx);
if (mport.size() == 0)
continue;
perm_string pname = peek_tail_name(mport[0]->path());
@ -1105,26 +1105,26 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// Inside the module, the port is zero or more signals
// that were already elaborated. List all those signals
// and the NetNet equivalents, for all the instances.
svector<PEIdent*> mport = rmod->get_port(idx);
svector<NetNet*>prts (mport.count() * instance.count());
vector<PEIdent*> mport = rmod->get_port(idx);
vector<NetNet*> prts (mport.size() * instance.size());
if (debug_elaborate) {
cerr << get_fileline() << ": debug: " << get_name()
<< ": Port " << idx << " has " << prts.count()
<< ": Port " << idx << " has " << prts.size()
<< " sub-ports." << endl;
}
// Count the internal vector bits of the port.
unsigned prts_vector_width = 0;
for (unsigned inst = 0 ; inst < instance.count() ; inst += 1) {
for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) {
// Scan the instances from MSB to LSB. The port
// will be assembled in that order as well.
NetScope*inst_scope = instance[instance.count()-inst-1];
NetScope*inst_scope = instance[instance.size()-inst-1];
// Scan the module sub-ports for this instance...
for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) {
unsigned lbase = inst * mport.count();
for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) {
unsigned lbase = inst * mport.size();
PEIdent*pport = mport[ldx];
assert(pport);
prts[lbase + ldx]
@ -1147,10 +1147,10 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// We know by design that each instance has the same
// width port. Therefore, the prts_pin_count must be an
// even multiple of the instance count.
assert(prts_vector_width % instance.count() == 0);
assert(prts_vector_width % instance.size() == 0);
unsigned desired_vector_width = prts_vector_width;
if (instance.count() != 1)
if (instance.size() != 1)
desired_vector_width = 0;
// Elaborate the expression that connects to the
@ -1158,7 +1158,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// that connects to the port.
NetNet*sig;
if ((prts.count() == 0)
if ((prts.size() == 0)
|| (prts[0]->port_type() == NetNet::PINPUT)) {
/* Input to module. elaborate the expression to
@ -1263,7 +1263,7 @@ v NOTE that this also handles the case that the
assert(sig);
#ifndef NDEBUG
if ((prts.count() >= 1)
if ((prts.size() >= 1)
&& (prts[0]->port_type() != NetNet::PINPUT)) {
assert(sig->type() != NetNet::REG);
}
@ -1271,13 +1271,13 @@ v NOTE that this also handles the case that the
/* If we are working with an instance array, then the
signal width must match the port width exactly. */
if ((instance.count() != 1)
if ((instance.size() != 1)
&& (sig->vector_width() != prts_vector_width)
&& (sig->vector_width() != prts_vector_width/instance.count())) {
&& (sig->vector_width() != prts_vector_width/instance.size())) {
cerr << pins[idx]->get_fileline() << ": error: "
<< "Port expression width " << sig->vector_width()
<< " does not match expected width "<< prts_vector_width
<< " or " << (prts_vector_width/instance.count())
<< " or " << (prts_vector_width/instance.size())
<< "." << endl;
des->errors += 1;
continue;
@ -1292,7 +1292,7 @@ v NOTE that this also handles the case that the
// Check that the parts have matching pin counts. If
// not, they are different widths. Note that idx is 0
// based, but users count parameter positions from 1.
if ((instance.count() == 1)
if ((instance.size() == 1)
&& (prts_vector_width != sig->vector_width())) {
const char *tmp3 = rmod->ports[idx]->name.str();
bool as_signed = false;
@ -1363,7 +1363,7 @@ v NOTE that this also handles the case that the
// Connect this many of the port pins. If the expression
// is too small, then reduce the number of connects.
unsigned ccount = prts_vector_width;
if (instance.count() == 1 && sig->vector_width() < ccount)
if (instance.size() == 1 && sig->vector_width() < ccount)
ccount = sig->vector_width();
// The spin_modulus is the width of the signal (not the
@ -1371,7 +1371,7 @@ v NOTE that this also handles the case that the
// signals wide enough for a single instance to be
// connected to all the instances.
unsigned spin_modulus = prts_vector_width;
if (instance.count() != 1)
if (instance.size() != 1)
spin_modulus = sig->vector_width();
// Now scan the concatenation that makes up the port,
@ -1383,7 +1383,7 @@ v NOTE that this also handles the case that the
NetConcat*ctmp;
unsigned spin = 0;
if (prts.count() == 1) {
if (prts.size() == 1) {
// The simplest case, there are no
// parts/concatenations on the inside of the
@ -1391,33 +1391,32 @@ v NOTE that this also handles the case that the
// connected directly.
connect(prts[0]->pin(0), sig->pin(0));
} else if (sig->vector_width()==prts_vector_width/instance.count()
&& prts.count()/instance.count() == 1) {
} else if (sig->vector_width()==prts_vector_width/instance.size()
&& prts.size()/instance.size() == 1) {
if (debug_elaborate){
cerr << get_fileline() << ": debug: " << get_name()
<< ": Replicating " << prts_vector_width
<< " bits across all "
<< prts_vector_width/instance.count()
<< prts_vector_width/instance.size()
<< " sub-ports." << endl;
}
// The signal width is exactly the width of a
// single instance of the port. In this case,
// connect the sig to all the ports identically.
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1)
for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1)
connect(prts[ldx]->pin(0), sig->pin(0));
} else switch (prts[0]->port_type()) {
case NetNet::POUTPUT:
ctmp = new NetConcat(scope, scope->local_symbol(),
prts_vector_width,
prts.count());
prts_vector_width, prts.size());
des->add_node(ctmp);
connect(ctmp->pin(0), sig->pin(0));
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1) {
for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1) {
connect(ctmp->pin(ldx+1),
prts[prts.count()-ldx-1]->pin(0));
prts[prts.size()-ldx-1]->pin(0));
}
break;
@ -1426,13 +1425,13 @@ v NOTE that this also handles the case that the
cerr << get_fileline() << ": debug: " << get_name()
<< ": Dividing " << prts_vector_width
<< " bits across all "
<< prts_vector_width/instance.count()
<< prts_vector_width/instance.size()
<< " input sub-ports of port "
<< idx << "." << endl;
}
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1) {
NetNet*sp = prts[prts.count()-ldx-1];
for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1) {
NetNet*sp = prts[prts.size()-ldx-1];
NetPartSelect*ptmp = new NetPartSelect(sig, spin,
sp->vector_width(),
NetPartSelect::VP);
@ -2013,6 +2012,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
return 0;
}
if (scope->is_auto() && lval()->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using non-blocking "
"assignments." << endl;
des->errors += 1;
return 0;
}
/* Elaborate the l-value. */
NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0;
@ -2043,6 +2050,15 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetEvWait*event = 0;
if (count_ != 0 || event_ != 0) {
if (count_ != 0) {
if (scope->is_auto() && count_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically "
"allocated variables may not be referenced "
"in intra-assignment event controls of "
"non-blocking assignments." << endl;
des->errors += 1;
return 0;
}
assert(event_ != 0);
count = elab_and_eval(des, scope, count_, -1);
if (count == 0) {
@ -2053,6 +2069,15 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
}
}
if (scope->is_auto() && event_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically "
"allocated variables may not be referenced "
"in intra-assignment event controls of "
"non-blocking assignments." << endl;
des->errors += 1;
return 0;
}
NetProc*st = event_->elaborate(des, scope);
if (st == 0) {
cerr << get_fileline() << ": unable to elaborate "
@ -2587,6 +2612,22 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
NetCAssign*dev = 0;
assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"continuous assignments." << endl;
des->errors += 1;
return 0;
}
if (scope->is_auto() && expr_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be referenced in procedural "
"continuous assignments." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
if (lval == 0)
return 0;
@ -2618,6 +2659,14 @@ NetDeassign* PDeassign::elaborate(Design*des, NetScope*scope) const
{
assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"continuous assignments." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
if (lval == 0)
return 0;
@ -2876,6 +2925,16 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
the sub-expression as a net and decide how to handle
the edge. */
if (scope->is_auto()) {
if (! dynamic_cast<PEIdent*>(expr_[idx]->expr())) {
cerr << get_fileline() << ": sorry, complex event "
"expressions are not yet supported in "
"automatic tasks." << endl;
des->errors += 1;
return 0;
}
}
bool save_flag = error_implicit;
error_implicit = true;
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0);
@ -3151,6 +3210,22 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
NetForce*dev = 0;
assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"force statements." << endl;
des->errors += 1;
return 0;
}
if (scope->is_auto() && expr_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be referenced in procedural force "
"statements." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
if (lval == 0)
return 0;
@ -3356,6 +3431,14 @@ NetProc* PRelease::elaborate(Design*des, NetScope*scope) const
{
assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"force statements." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
if (lval == 0)
return 0;
@ -3503,15 +3586,7 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
return false;
}
NetProcTop*top=0;
switch (type()) {
case PProcess::PR_INITIAL:
top = new NetProcTop(scope, NetProcTop::KINITIAL, cur);
break;
case PProcess::PR_ALWAYS:
top = new NetProcTop(scope, NetProcTop::KALWAYS, cur);
break;
}
NetProcTop*top=new NetProcTop(scope, type(), cur);
ivl_assert(*this, top);
// Evaluate the attributes for this process, if there
@ -3536,7 +3611,7 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
gets into its wait statement before non-combinational
code is executed. */
do {
if (top->type() != NetProcTop::KALWAYS)
if (top->type() != IVL_PR_ALWAYS)
break;
NetEvWait*st = dynamic_cast<NetEvWait*>(top->statement());
@ -3959,6 +4034,12 @@ bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const
result_flag &= (*st)->elaborate(des, scope);
}
for (list<AProcess*>::const_iterator st = analog_behaviors.begin()
; st != analog_behaviors.end() ; st ++ ) {
result_flag &= (*st)->elaborate(des, scope);
}
return result_flag;
}
@ -4046,7 +4127,7 @@ bool Design::check_always_delay() const
* a runtime infinite loop will happen. If we possible have some
* delay then print a warning that an infinite loop is possible.
*/
if (pr->type() == NetProcTop::KALWAYS) {
if (pr->type() == IVL_PR_ALWAYS) {
DelayType dly_type = pr->statement()->delay_type();
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {

64
elaborate_analog.cc Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "AStatement.h"
# include "netlist.h"
# include "netmisc.h"
# include "util.h"
# include <typeinfo>
NetProc* AContrib::elaborate(Design*des, NetScope*scope) const
{
NetExpr*lval = elab_and_eval(des, scope, lval_, -1);
NetExpr*rval = elab_and_eval(des, scope, rval_, -1);
NetContribution*st = new NetContribution(lval, rval);
st->set_line(*this);
return st;
}
bool AProcess::elaborate(Design*des, NetScope*scope) const
{
NetProc*statement = statement_->elaborate(des, scope);
if (statement == 0)
return false;
NetAnalogTop*top = new NetAnalogTop(scope, type_, statement);
// Evaluate the attributes for this process, if there
// are any. These attributes are to be attached to the
// NetProcTop object.
struct attrib_list_t*attrib_list = 0;
unsigned attrib_list_n = 0;
attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope);
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
top->attribute(attrib_list[adx].key,
attrib_list[adx].val);
delete[]attrib_list;
top->set_line(*this);
des->add_process(top);
return true;
}

View File

@ -190,6 +190,13 @@ bool NetProcTop::emit(struct target_t*tgt) const
return tgt->process(this);
}
bool NetAnalogTop::emit(struct target_t*tgt) const
{
cerr << get_fileline() << ": sorry: "
<< "I don't know how to emit for analog processes." << endl;
return false;
}
bool NetProc::emit_proc(struct target_t*tgt) const
{
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
@ -456,6 +463,8 @@ int Design::emit(struct target_t*tgt) const
bool proc_rc = true;
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
proc_rc &= idx->emit(tgt);
for (const NetAnalogTop*idx = aprocs_ ; idx ; idx = idx->next_)
proc_rc &= idx->emit(tgt);
rc = tgt->end_design(this);

View File

@ -484,6 +484,7 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope)
lsig->vector_width(),
rsig->vector_width());
div->set_line(*this);
div->set_signed(has_sign());
des->add_node(div);
connect(div->pin_DataA(), lsig->pin(0));

View File

@ -15,6 +15,9 @@ ivl_const_signed
ivl_const_type
ivl_const_width
ivl_discipline_domain
ivl_discipline_name
ivl_event_any
ivl_event_basename
ivl_event_name
@ -172,6 +175,7 @@ ivl_signal_attr_val
ivl_signal_basename
ivl_signal_data_type
ivl_signal_dimensions
ivl_signal_discipline
ivl_signal_file
ivl_signal_integer
ivl_signal_lineno

View File

@ -151,6 +151,7 @@ _BEGIN_DECL
typedef struct ivl_array_s *ivl_array_t;
typedef struct ivl_delaypath_s*ivl_delaypath_t;
typedef struct ivl_design_s *ivl_design_t;
typedef struct ivl_discipline_s*ivl_discipline_t;
typedef struct ivl_event_s *ivl_event_t;
typedef struct ivl_expr_s *ivl_expr_t;
typedef struct ivl_island_s *ivl_island_t;
@ -159,6 +160,7 @@ typedef struct ivl_lval_s *ivl_lval_t;
typedef struct ivl_net_const_s*ivl_net_const_t;
typedef struct ivl_net_logic_s*ivl_net_logic_t;
typedef struct ivl_udp_s *ivl_udp_t;
typedef struct ivl_nature_s *ivl_nature_t;
typedef struct ivl_net_probe_s*ivl_net_probe_t;
typedef struct ivl_nexus_s *ivl_nexus_t;
typedef struct ivl_nexus_ptr_s*ivl_nexus_ptr_t;
@ -176,6 +178,12 @@ typedef struct ivl_statement_s*ivl_statement_t;
* changes and additions to the enumerations.
*/
typedef enum ivl_dis_domain_e {
IVL_DIS_NONE = 0,
IVL_DIS_DISCRETE = 1,
IVL_DIS_CONTINUOUS = 2
} ivl_dis_domain_t;
typedef enum ivl_drive_e {
IVL_DR_HiZ = 0,
IVL_DR_SMALL = 1,
@ -543,6 +551,28 @@ extern double ivl_const_real(ivl_net_const_t net);
/* extern ivl_nexus_t ivl_const_pin(ivl_net_const_t net, unsigned idx); */
/* extern unsigned ivl_const_pins(ivl_net_const_t net); */
/* DISCIPLINES
*
* Disciplines are Verilog-AMS construct. A discipline is a collection
* of attributes that can be attached to a signal.
*
* FUNCTION SUMMARY
*
* ivl_discipline_name
* This is the name of the discipline in the Verilog-AMS source.
*
* ivl_discipline_domain
* This is the domain: continuous or discrete.
*
* SEMANTIC NOTES
*
* The discipline domain will not be IVL_DIS_NONE. The "none" domain
* is a place-holder internally for incomplete parsing, and is also
* available for code generaters to use.
*/
extern const char*ivl_discipline_name(ivl_discipline_t net);
extern ivl_dis_domain_t ivl_discipline_domain(ivl_discipline_t net);
/* EVENTS
*
* Events are a unification of named events and implicit events
@ -1584,6 +1614,10 @@ extern int ivl_scope_time_units(ivl_scope_t net);
* The signal may be an array (of vectors) in which case this
* function returns >0, the number of dimensions of the array.
*
* ivl_signal_discipline
* If the signal has been declared with a domain (Verilog-AMS) then
* this function wil return a non-nil ivl_discipline_t.
*
* ivl_signal_msb
* ivl_signal_lsb
* ivl_signal_width
@ -1651,6 +1685,7 @@ extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word);
extern int ivl_signal_array_base(ivl_signal_t net);
extern unsigned ivl_signal_array_count(ivl_signal_t net);
extern unsigned ivl_signal_dimensions(ivl_signal_t net);
extern ivl_discipline_t ivl_signal_discipline(ivl_signal_t net);
extern int ivl_signal_msb(ivl_signal_t net);
extern int ivl_signal_lsb(ivl_signal_t net);
extern unsigned ivl_signal_width(ivl_signal_t net);

View File

@ -1,7 +1,7 @@
#ifndef __globals_H
#define __globals_H
/*
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -22,9 +22,11 @@
# include <stdio.h>
extern void reset_lexor(FILE*out, char*paths[]);
extern void destroy_lexor();
extern void load_precompiled_defines(FILE*src);
extern void define_macro(const char*name, const char*value, int keyword,
int argc);
extern void free_macros();
extern void dump_precompiled_defines(FILE*out);
/* These variables contain the include directories to be searched when

View File

@ -78,6 +78,9 @@ struct include_stack_t
YY_BUFFER_STATE yybs;
struct include_stack_t* next;
/* A single line comment can be associated with this include. */
char* comment;
};
static void emit_pathline(struct include_stack_t* isp);
@ -295,9 +298,10 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
/* Catch single-line comments that share the line with an include
* directive. And while I'm at it, I might as well preserve the
* comment in the output stream.
* comment in the output stream. This will be printed after the
* file has been included.
*/
<PPINCLUDE>"//"[^\r\n]* { ECHO; }
<PPINCLUDE>"//"[^\r\n]* { standby->comment = strdup(yytext); }
/* These finish the include directive (EOF or EOL) so I revert the
* lexor state and execute the inclusion.
@ -829,6 +833,21 @@ void define_macro(const char* name, const char* value, int keyword, int argc)
}
}
static void free_macro(struct define_t* def)
{
if (def == 0) return;
free_macro(def->left);
free_macro(def->right);
free(def->name);
free(def->value);
free(def);
}
void free_macros()
{
free_macro(def_table);
}
/*
* The do_define function accumulates the defined value in these
* variables. When the define is over, the def_finish() function
@ -1418,6 +1437,7 @@ static void include_filename()
standby->path = strdup(yytext+1);
standby->path[strlen(standby->path)-1] = 0;
standby->lineno = 0;
standby->comment = NULL;
}
static void do_include()
@ -1457,6 +1477,8 @@ static void do_include()
if ((standby->file = fopen(path, "r")))
{
/* Free the original path before we overwrite it. */
free(standby->path);
standby->path = strdup(path);
goto code_that_switches_buffers;
}
@ -1468,6 +1490,9 @@ static void do_include()
code_that_switches_buffers:
/* Clear the current files path from the search list. */
include_dir[0] = 0;
if(depend_file)
fprintf(depend_file, "%s\n", standby->path);
@ -1530,6 +1555,17 @@ static int load_next_input()
/* Delete the current input buffers, and free the cell. */
yy_delete_buffer(YY_CURRENT_BUFFER);
/* If there was a comment for this include print it before we
* return to the previous input stream. This technically belongs
* to the previous stream, but it should not create any problems
* since it is only a comment.
*/
if (isp->comment) {
fprintf(yyout, "%s\n", isp->comment);
free(isp->comment);
isp->comment = NULL;
}
if (isp->file)
{
free(isp->path);
@ -1726,6 +1762,7 @@ void reset_lexor(FILE* out, char* paths[])
isp->ebs = 0;
isp->lineno = 0;
isp->stringify_flag = 0;
isp->comment = NULL;
if (isp->file == 0)
{
@ -1756,6 +1793,7 @@ void reset_lexor(FILE* out, char* paths[])
isp->next = 0;
isp->lineno = 0;
isp->stringify_flag = 0;
isp->comment = NULL;
if (tail)
tail->next = isp;
@ -1765,3 +1803,17 @@ void reset_lexor(FILE* out, char* paths[])
tail = isp;
}
}
/*
* Modern version of flex (>=2.5.9) can clean up the scanner data.
*/
void destroy_lexor()
{
# ifdef FLEX_SCANNER
# if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
yylex_destroy();
# endif
# endif
# endif
}

View File

@ -189,12 +189,14 @@ static int flist_read_names(const char*path)
add_source_file(cp);
}
fclose(fd);
return 0;
}
int main(int argc, char*argv[])
{
int opt, idx;
unsigned lp;
const char*flist_path = 0;
unsigned flag_errors = 0;
char*out_path = 0;
@ -368,6 +370,7 @@ int main(int argc, char*argv[])
start scanning. */
reset_lexor(out, source_list);
if (yylex()) return -1;
destroy_lexor();
if(depend_file) {
fclose(depend_file);
@ -378,5 +381,17 @@ int main(int argc, char*argv[])
fclose(precomp_out);
}
/* Free the source and include directory lists. */
for (lp = 0; lp < source_cnt; lp += 1) {
free(source_list[lp]);
}
free(source_list);
for (lp = 0; lp < include_cnt; lp += 1) {
free(include_dir[lp]);
}
free(include_dir);
free_macros();
return error_count;
}

View File

@ -247,7 +247,7 @@ S [afpnumkKMGT]
value instead. */
if (rc == IDENTIFIER && gn_verilog_ams_flag) {
perm_string tmp = lex_strings.make(yylval.text);
map<perm_string,discipline_t*>::iterator cur = disciplines.find(tmp);
map<perm_string,ivl_discipline_t>::iterator cur = disciplines.find(tmp);
if (cur != disciplines.end()) {
yylval.discipline = (*cur).second;
rc = DISCIPLINE_IDENTIFIER;

View File

@ -705,7 +705,7 @@ int main(int argc, char*argv[])
pform_dump(out, (*cur).second);
}
out << "PFORM DUMP DISCIPLINES:" << endl;
for (map<perm_string,discipline_t*>::iterator cur = disciplines.begin()
for (map<perm_string,ivl_discipline_t>::iterator cur = disciplines.begin()
; cur != disciplines.end() ; cur ++ ) {
pform_dump(out, (*cur).second);
}

37
net_analog.cc Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include <typeinfo>
# include <cstdlib>
# include <climits>
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "ivl_assert.h"
NetContribution::NetContribution(NetExpr*l, NetExpr*r)
: lval_(l), rval_(r)
{
}
NetContribution::~NetContribution()
{
}

View File

@ -36,7 +36,7 @@
# include "ivl_assert.h"
Design:: Design()
: errors(0), nodes_(0), procs_(0), lcounter_(0)
: errors(0), nodes_(0), procs_(0), aprocs_(0), lcounter_(0)
{
procs_idx_ = 0;
des_precision_ = 0;
@ -764,6 +764,11 @@ void Design::add_process(NetProcTop*pro)
procs_ = pro;
}
void Design::add_process(NetAnalogTop*pro)
{
pro->next_ = aprocs_;
aprocs_ = pro;
}
void Design::delete_process(NetProcTop*top)
{
assert(top);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_modulo.cc,v 1.9 2005/09/15 22:54:47 steve Exp $"
#endif
# include "config.h"
@ -69,6 +66,16 @@ Link& NetModulo::pin_Result()
return pin(0);
}
void NetModulo::set_signed(bool flag)
{
signed_flag_ = flag;
}
bool NetModulo::get_signed() const
{
return signed_flag_;
}
const Link& NetModulo::pin_Result() const
{
return pin(0);
@ -93,25 +100,3 @@ const Link& NetModulo::pin_DataB() const
{
return pin(2);
}
/*
* $Log: net_modulo.cc,v $
* Revision 1.9 2005/09/15 22:54:47 steve
* Fix bug configuring NetModulo pins.
*
* Revision 1.8 2005/03/12 06:43:35 steve
* Update support for LPM_MOD.
*
* Revision 1.7 2004/02/18 17:11:56 steve
* Use perm_strings for named langiage items.
*
* Revision 1.6 2003/03/06 00:28:41 steve
* All NetObj objects have lex_string base names.
*
* Revision 1.5 2002/08/12 01:34:59 steve
* conditional ident string using autoconfig.
*
* Revision 1.4 2002/08/11 23:47:04 steve
* Add missing Log and Ident strings.
*
*/

View File

@ -242,7 +242,7 @@ NetNode::~NetNode()
design_->del_node(this);
}
NetBranch::NetBranch(discipline_t*dis)
NetBranch::NetBranch(ivl_discipline_t dis)
: NetPins(2), discipline_(dis)
{
pin(0).set_dir(Link::PASSIVE);
@ -647,12 +647,12 @@ void NetNet::set_isint(bool flag)
isint_ = flag;
}
discipline_t* NetNet::get_discipline() const
ivl_discipline_t NetNet::get_discipline() const
{
return discipline_;
}
void NetNet::set_discipline(discipline_t*dis)
void NetNet::set_discipline(ivl_discipline_t dis)
{
ivl_assert(*this, discipline_ == 0);
discipline_ = dis;
@ -849,7 +849,7 @@ NetProc::~NetProc()
{
}
NetProcTop::NetProcTop(NetScope*s, Type t, NetProc*st)
NetProcTop::NetProcTop(NetScope*s, ivl_process_type_t t, NetProc*st)
: type_(t), statement_(st), scope_(s)
{
}
@ -874,6 +874,16 @@ NetScope* NetProcTop::scope()
return scope_;
}
NetAnalogTop::NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetProc*st)
: type_(t), statement_(st), scope_(scope)
{
next_ = 0;
}
NetAnalogTop::~NetAnalogTop()
{
}
const NetScope* NetProcTop::scope() const
{
return scope_;

View File

@ -69,7 +69,6 @@ class NetEvTrig;
class NetEvWait;
class nature_t;
class discipline_t;
struct target;
struct functor_t;
@ -173,12 +172,12 @@ class IslandBranch {
class NetBranch : public NetPins {
public:
explicit NetBranch(discipline_t*dis);
explicit NetBranch(discipline_t*dis, perm_string name);
explicit NetBranch(ivl_discipline_t dis);
explicit NetBranch(ivl_discipline_t dis, perm_string name);
~NetBranch();
private:
discipline_t*discipline_;
ivl_discipline_t discipline_;
perm_string name_;
};
@ -555,8 +554,8 @@ class NetNet : public NetObj {
void set_isint(bool);
/* Attach a discipline to the net. */
discipline_t* get_discipline() const;
void set_discipline(discipline_t*dis);
ivl_discipline_t get_discipline() const;
void set_discipline(ivl_discipline_t dis);
/* These methods return the msb and lsb indices for the most
significant and least significant bits. These are signed
@ -620,7 +619,7 @@ class NetNet : public NetObj {
ivl_variable_type_t data_type_;
bool signed_;
bool isint_; // original type of integer
discipline_t*discipline_;
ivl_discipline_t discipline_;
long msb_, lsb_;
const unsigned dimensions_;
@ -830,7 +829,7 @@ class NetScope : public Attrib {
/* Module instance arrays are collected here for access during
the multiple elaboration passes. */
typedef svector<NetScope*> scope_vec_t;
typedef vector<NetScope*> scope_vec_t;
map<perm_string, scope_vec_t>instance_arrays;
/* Loop generate uses this as scratch space during
@ -1178,6 +1177,9 @@ class NetModulo : public NetNode {
unsigned width_a() const;
unsigned width_b() const;
void set_signed(bool);
bool get_signed() const;
Link& pin_DataA();
Link& pin_DataB();
Link& pin_Result();
@ -1194,6 +1196,8 @@ class NetModulo : public NetNode {
unsigned width_r_;
unsigned width_a_;
unsigned width_b_;
bool signed_flag_;
};
/*
@ -2430,6 +2434,24 @@ class NetCondit : public NetProc {
NetProc*else_;
};
/*
* This represents the analog contribution statement. The l-val is a
* branch expression, and the r-value is an arbitrary expression that
* may include branches and real values.
*/
class NetContribution : public NetProc {
public:
explicit NetContribution(NetExpr*lval, NetExpr*rval);
~NetContribution();
virtual void dump(ostream&, unsigned ind) const;
private:
NetExpr*lval_;
NetExpr*rval_;
};
/*
* The procedural deassign statement (the opposite of assign) releases
* any assign expressions attached to the bits of the reg. The
@ -3040,12 +3062,10 @@ class NetWhile : public NetProc {
class NetProcTop : public LineInfo, public Attrib {
public:
enum Type { KINITIAL, KALWAYS };
NetProcTop(NetScope*s, Type t, class NetProc*st);
NetProcTop(NetScope*s, ivl_process_type_t t, class NetProc*st);
~NetProcTop();
Type type() const { return type_; }
ivl_process_type_t type() const { return type_; }
NetProc*statement();
const NetProc*statement() const;
@ -3070,7 +3090,7 @@ class NetProcTop : public LineInfo, public Attrib {
bool emit(struct target_t*tgt) const;
private:
const Type type_;
const ivl_process_type_t type_;
NetProc*const statement_;
NetScope*scope_;
@ -3078,6 +3098,32 @@ class NetProcTop : public LineInfo, public Attrib {
NetProcTop*next_;
};
class NetAnalogTop : public LineInfo, public Attrib {
public:
NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetProc*st);
~NetAnalogTop();
ivl_process_type_t type() const { return type_; }
NetProc*statement();
const NetProc*statement() const;
NetScope*scope();
const NetScope*scope() const;
void dump(ostream&, unsigned ind) const;
bool emit(struct target_t*tgt) const;
private:
const ivl_process_type_t type_;
NetProc* statement_;
NetScope*scope_;
friend class Design;
NetAnalogTop*next_;
};
/*
* This class represents a binary operator, with the left and right
* operands and a single character for the operator. The operator
@ -3655,6 +3701,7 @@ class NetEUBits : public NetEUnary {
virtual NetNet* synthesize(Design*, NetScope*scope);
virtual NetEUBits* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual ivl_variable_type_t expr_type() const;
};
@ -3818,6 +3865,7 @@ class Design {
// PROCESSES
void add_process(NetProcTop*);
void add_process(NetAnalogTop*);
void delete_process(NetProcTop*);
bool check_always_delay() const;
@ -3849,6 +3897,8 @@ class Design {
NetProcTop*procs_;
NetProcTop*procs_idx_;
NetAnalogTop*aprocs_;
map<string,const char*> flags_;
int des_precision_;

65
parse.y
View File

@ -108,6 +108,12 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
return copy;
}
template <class T> void append(vector<T>&out, const vector<T>&in)
{
for (size_t idx = 0 ; idx < in.size() ; idx += 1)
out.push_back(in[idx]);
}
/*
* This is a shorthand for making a PECallFunction that takes a single
* arg. This is used by some of the code that detects built-ins.
@ -142,7 +148,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
list<perm_string>*perm_strings;
pform_name_t*pform_name;
discipline_t*discipline;
ivl_discipline_t discipline;
hname_t*hier;
@ -158,7 +164,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
Module::port_t *mport;
LexicalScope::range_t* value_range;
svector<Module::port_t*>*mports;
vector<Module::port_t*>*mports;
named_pexpr_t*named_pexpr;
svector<named_pexpr_t*>*named_pexprs;
@ -180,7 +186,6 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
PEventStatement*event_statement;
Statement*statement;
svector<Statement*>*statement_list;
AStatement*astatement;
PTaskFuncArg function_type;
@ -304,7 +309,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%type <statement> statement statement_or_null
%type <statement_list> statement_list
%type <astatement> analog_statement
%type <statement> analog_statement
%type <letter> spec_polarity
%type <perm_strings> specify_path_identifiers
@ -705,9 +710,9 @@ discipline_items
discipline_item
: K_domain K_discrete ';'
{ pform_discipline_domain(@1, DD_DISCRETE); }
{ pform_discipline_domain(@1, IVL_DIS_DISCRETE); }
| K_domain K_continuous ';'
{ pform_discipline_domain(@1, DD_CONTINUOUS); }
{ pform_discipline_domain(@1, IVL_DIS_CONTINUOUS); }
| K_potential IDENTIFIER ';'
{ pform_discipline_potential(@1, $2); delete[] $2; }
| K_flow IDENTIFIER ';'
@ -1659,30 +1664,28 @@ list_of_identifiers
list_of_ports
: port_opt
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(1);
{ vector<Module::port_t*>*tmp
= new vector<Module::port_t*>(1);
(*tmp)[0] = $1;
$$ = tmp;
}
| list_of_ports ',' port_opt
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, $3);
delete $1;
{ vector<Module::port_t*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
;
list_of_port_declarations
: port_declaration
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(1);
{ vector<Module::port_t*>*tmp
= new vector<Module::port_t*>(1);
(*tmp)[0] = $1;
$$ = tmp;
}
| list_of_port_declarations ',' port_declaration
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, $3);
delete $1;
{ vector<Module::port_t*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
| list_of_port_declarations ',' IDENTIFIER
@ -1690,8 +1693,8 @@ list_of_port_declarations
perm_string name = lex_strings.make($3);
ptmp = pform_module_port_reference(name, @3.text,
@3.first_line);
svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, ptmp);
vector<Module::port_t*>*tmp = $1;
tmp->push_back(ptmp);
/* Get the port declaration details, the port type
and what not, from context data stored by the
@ -1701,7 +1704,6 @@ list_of_port_declarations
port_declaration_context.port_net_type,
port_declaration_context.sign_flag,
port_declaration_context.range, 0);
delete $1;
delete[]$3;
$$ = tmp;
}
@ -2093,16 +2095,16 @@ module_item
/* Always and initial items are behavioral processes. */
| attribute_list_opt K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $3, $1);
{ PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS, $3, $1);
FILE_NAME(tmp, @2);
}
| attribute_list_opt K_initial statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL, $3, $1);
{ PProcess*tmp = pform_make_behavior(IVL_PR_INITIAL, $3, $1);
FILE_NAME(tmp, @2);
}
| attribute_list_opt K_analog analog_statement
{ pform_make_analog_behavior(@2, AProcess::PR_ALWAYS, $3); }
{ pform_make_analog_behavior(@2, IVL_PR_ALWAYS, $3); }
/* The task declaration rule matches the task declaration
header, then pushes the function scope. This causes the
@ -2777,8 +2779,7 @@ port_reference
Module::port_t*ptmp = new Module::port_t;
ptmp->name = perm_string();
ptmp->expr = svector<PEIdent*>(1);
ptmp->expr[0] = wtmp;
ptmp->expr.push_back(wtmp);
delete[]$1;
$$ = ptmp;
@ -2801,8 +2802,7 @@ port_reference
Module::port_t*ptmp = new Module::port_t;
ptmp->name = perm_string();
ptmp->expr = svector<PEIdent*>(1);
ptmp->expr[0] = tmp;
ptmp->expr.push_back(tmp);
delete[]$1;
$$ = ptmp;
}
@ -2813,8 +2813,7 @@ port_reference
PEIdent*wtmp = new PEIdent(lex_strings.make($1));
FILE_NAME(wtmp, @1);
ptmp->name = lex_strings.make($1);
ptmp->expr = svector<PEIdent*>(1);
ptmp->expr[0] = wtmp;
ptmp->expr.push_back(wtmp);
delete[]$1;
$$ = ptmp;
}
@ -2826,7 +2825,7 @@ port_reference_list
{ $$ = $1; }
| port_reference_list ',' port_reference
{ Module::port_t*tmp = $1;
tmp->expr = svector<PEIdent*>(tmp->expr, $3->expr);
append(tmp->expr, $3->expr);
delete $3;
$$ = tmp;
}
@ -2978,7 +2977,13 @@ real_variable
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
if ($2 != 0) {
yyerror(@2, "sorry: real variables do not currently support arrays.");
index_component_t index;
if ($2->size() > 1) {
yyerror(@2, "sorry: only 1 dimensional arrays "
"are currently supported.");
}
index = $2->front();
pform_set_reg_idx(name, index.msb, index.lsb);
delete $2;
}
$$ = $1;

View File

@ -384,20 +384,19 @@ Module::port_t* pform_module_port_reference(perm_string name,
PEIdent*tmp = new PEIdent(name);
FILE_NAME(tmp, file, lineno);
ptmp->name = name;
ptmp->expr = svector<PEIdent*>(1);
ptmp->expr[0] = tmp;
ptmp->expr.push_back(tmp);
return ptmp;
}
void pform_module_set_ports(svector<Module::port_t*>*ports)
void pform_module_set_ports(vector<Module::port_t*>*ports)
{
assert(pform_cur_module);
/* The parser parses ``module foo()'' as having one
unconnected port, but it is really a module with no
ports. Fix it up here. */
if (ports && (ports->count() == 1) && ((*ports)[0] == 0)) {
if (ports && (ports->size() == 1) && ((*ports)[0] == 0)) {
delete ports;
ports = 0;
}
@ -1327,7 +1326,7 @@ void pform_make_reginit(const struct vlltype&li,
FILE_NAME(lval, li);
PAssign*ass = new PAssign(lval, expr, true);
FILE_NAME(ass, li);
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
PProcess*top = new PProcess(IVL_PR_INITIAL, ass);
FILE_NAME(top, li);
pform_put_behavior_in_scope(top);
@ -1970,7 +1969,7 @@ svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names)
return out;
}
PProcess* pform_make_behavior(PProcess::Type type, Statement*st,
PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st,
svector<named_pexpr_t*>*attr)
{
PProcess*pp = new PProcess(type, st);

15
pform.h
View File

@ -143,7 +143,7 @@ extern PWire* pform_get_wire_in_scope(perm_string name);
*/
extern void pform_startmodule(const char*, const char*file, unsigned lineno,
svector<named_pexpr_t*>*attr);
extern void pform_module_set_ports(svector<Module::port_t*>*);
extern void pform_module_set_ports(vector<Module::port_t*>*);
/* This function is used to support the port definition in a
port_definition_list. In this case, we have everything needed to
@ -311,7 +311,7 @@ extern void pform_module_specify_path(PSpecPath*obj);
* pform_make_behavior creates processes that are declared with always
* or initial items.
*/
extern PProcess* pform_make_behavior(PProcess::Type, Statement*,
extern PProcess* pform_make_behavior(ivl_process_type_t, Statement*,
svector<named_pexpr_t*>*attr);
extern svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*);
@ -373,7 +373,6 @@ extern void pform_error_nested_modules();
* Functions for handling the parse of natures and disciplines. These
* functions are in pform_disciplines.cc
*/
class discipline_t;
extern void pform_start_nature(const char*name);
extern void pform_end_nature(const struct vlltype&loc);
@ -383,22 +382,22 @@ extern void pform_nature_access(const struct vlltype&loc, const char*name);
extern void pform_start_discipline(const char*name);
extern void pform_end_discipline(const struct vlltype&loc);
extern void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain);
extern void pform_discipline_domain(const struct vlltype&loc, ivl_dis_domain_t use_domain);
extern void pform_discipline_potential(const struct vlltype&loc, const char*name);
extern void pform_discipline_flow(const struct vlltype&loc, const char*name);
extern void pform_attach_discipline(const struct vlltype&loc,
discipline_t*discipline, list<perm_string>*names);
ivl_discipline_t discipline, list<perm_string>*names);
extern void pform_dump(ostream&out, const nature_t*);
extern void pform_dump(ostream&out, const discipline_t*);
extern void pform_dump(ostream&out, const ivl_discipline_s*);
/* ** pform_analog.cc
*/
extern void pform_make_analog_behavior(const struct vlltype&loc,
AProcess::Type type, AStatement*st);
ivl_process_type_t type, Statement*st);
extern AStatement*pform_contribution_statement(const struct vlltype&loc,
extern AContrib*pform_contribution_statement(const struct vlltype&loc,
PExpr*lval, PExpr*rval);
extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,

View File

@ -23,7 +23,7 @@
# include "parse_misc.h"
# include "AStatement.h"
AStatement* pform_contribution_statement(const struct vlltype&loc,
AContrib* pform_contribution_statement(const struct vlltype&loc,
PExpr*lval, PExpr*rval)
{
AContrib*tmp = new AContrib(lval, rval);
@ -31,8 +31,8 @@ AStatement* pform_contribution_statement(const struct vlltype&loc,
return tmp;
}
void pform_make_analog_behavior(const struct vlltype&loc, AProcess::Type pt,
AStatement*statement)
void pform_make_analog_behavior(const struct vlltype&loc, ivl_process_type_t pt,
Statement*statement)
{
AProcess*proc = new AProcess(pt, statement);
FILE_NAME(proc, loc);

View File

@ -24,7 +24,7 @@
# include "discipline.h"
map<perm_string,nature_t*> natures;
map<perm_string,discipline_t*> disciplines;
map<perm_string,ivl_discipline_t> disciplines;
map<perm_string,nature_t*> access_function_nature;
static perm_string nature_name = perm_string::perm_string();
@ -88,21 +88,21 @@ void pform_end_nature(const struct vlltype&loc)
static perm_string discipline_name;
static ddomain_t discipline_domain = DD_NONE;
static ivl_dis_domain_t discipline_domain = IVL_DIS_NONE;
static nature_t* discipline_potential = 0;
static nature_t* discipline_flow = 0;
void pform_start_discipline(const char*name)
{
discipline_name = lex_strings.make(name);
discipline_domain = DD_NONE;
discipline_domain = IVL_DIS_NONE;
}
void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain)
void pform_discipline_domain(const struct vlltype&loc, ivl_dis_domain_t use_domain)
{
assert(use_domain != DD_NONE);
assert(use_domain != IVL_DIS_NONE);
if (discipline_domain != DD_NONE) {
if (discipline_domain != IVL_DIS_NONE) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "Too many domain attributes for discipline "
<< discipline_name << "." << endl;
@ -159,18 +159,20 @@ void pform_end_discipline(const struct vlltype&loc)
{
// If the domain is not otherwise specified, then take it to
// be continuous if potential or flow natures are given.
if (discipline_domain == DD_NONE && (discipline_potential||discipline_flow))
discipline_domain = DD_CONTINUOUS;
if (discipline_domain == IVL_DIS_NONE && (discipline_potential||discipline_flow))
discipline_domain = IVL_DIS_CONTINUOUS;
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
discipline_potential, discipline_flow);
ivl_discipline_t tmp = new ivl_discipline_s(discipline_name,
discipline_domain,
discipline_potential,
discipline_flow);
disciplines[discipline_name] = tmp;
FILE_NAME(tmp, loc);
/* Clear the static variables for the next item. */
discipline_name = perm_string::perm_string();
discipline_domain = DD_NONE;
discipline_domain = IVL_DIS_NONE;
discipline_potential = 0;
discipline_flow = 0;
}
@ -183,7 +185,7 @@ void pform_end_discipline(const struct vlltype&loc)
* in the current lexical scope.
*/
void pform_attach_discipline(const struct vlltype&loc,
discipline_t*discipline, list<perm_string>*names)
ivl_discipline_t discipline, list<perm_string>*names)
{
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; cur ++ ) {
@ -197,7 +199,7 @@ void pform_attach_discipline(const struct vlltype&loc,
assert(cur_net);
}
if (discipline_t*tmp = cur_net->get_discipline()) {
if (ivl_discipline_t tmp = cur_net->get_discipline()) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "discipline " << discipline->name()
<< " cannot override existing discipline " << tmp->name()

View File

@ -135,17 +135,29 @@ ostream& operator<< (ostream&o, const pform_name_t&that)
return o;
}
std::ostream& operator << (std::ostream&out, ivl_process_type_t pt)
{
switch (pt) {
case IVL_PR_INITIAL:
out << "initial";
break;
case IVL_PR_ALWAYS:
out << "always";
break;
}
return out;
}
std::ostream& operator << (std::ostream&out, ddomain_t dom)
std::ostream& operator << (std::ostream&out, ivl_dis_domain_t dom)
{
switch (dom) {
case DD_NONE:
case IVL_DIS_NONE:
out << "no-domain";
break;
case DD_DISCRETE:
case IVL_DIS_DISCRETE:
out << "discrete";
break;
case DD_CONTINUOUS:
case IVL_DIS_CONTINUOUS:
out << "continuous";
break;
default:
@ -552,16 +564,6 @@ void Statement::dump(ostream&out, unsigned ind) const
dump_attributes_map(out, attributes, ind+2);
}
void AStatement::dump(ostream&out, unsigned ind) const
{
/* I give up. I don't know what type this statement is,
so just print the C++ typeid and let the user figure
it out. */
out << setw(ind) << "";
out << "/* " << get_fileline() << ": " << typeid(*this).name()
<< " */ ;" << endl;
}
void AContrib::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "";
@ -900,16 +902,8 @@ void PWhile::dump(ostream&out, unsigned ind) const
void PProcess::dump(ostream&out, unsigned ind) const
{
switch (type_) {
case PProcess::PR_INITIAL:
out << setw(ind) << "" << "initial";
break;
case PProcess::PR_ALWAYS:
out << setw(ind) << "" << "always";
break;
}
out << " /* " << get_fileline() << " */" << endl;
out << setw(ind) << "" << type_
<< " /* " << get_fileline() << " */" << endl;
dump_attributes_map(out, attributes, ind+2);
@ -919,10 +913,10 @@ void PProcess::dump(ostream&out, unsigned ind) const
void AProcess::dump(ostream&out, unsigned ind) const
{
switch (type_) {
case AProcess::PR_INITIAL:
case IVL_PR_INITIAL:
out << setw(ind) << "" << "analog initial";
break;
case AProcess::PR_ALWAYS:
case IVL_PR_ALWAYS:
out << setw(ind) << "" << "analog";
break;
}
@ -1149,7 +1143,7 @@ void Module::dump(ostream&out) const
out << "module " << mod_name() << ";" << endl;
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < ports.size() ; idx += 1) {
port_t*cur = ports[idx];
if (cur == 0) {
@ -1158,7 +1152,7 @@ void Module::dump(ostream&out) const
}
out << " ." << cur->name << "(" << *cur->expr[0];
for (unsigned wdx = 1 ; wdx < cur->expr.count() ; wdx += 1) {
for (unsigned wdx = 1 ; wdx < cur->expr.size() ; wdx += 1) {
out << ", " << *cur->expr[wdx];
}
@ -1306,7 +1300,7 @@ void pform_dump(std::ostream&out, const nature_t*nat)
out << "endnature" << endl;
}
void pform_dump(std::ostream&out, const discipline_t*dis)
void pform_dump(std::ostream&out, const ivl_discipline_s*dis)
{
out << "discipline " << dis->name() << endl;
out << " domain " << dis->domain() << ";" << endl;

View File

@ -335,7 +335,7 @@ static void syn_start_process(NetProcTop*t)
last_ = first_;
ptr_ = first_;
first_->token = (t->type() == NetProcTop::KALWAYS)? S_ALWAYS : S_INITIAL;
first_->token = (t->type() == IVL_PR_ALWAYS)? S_ALWAYS : S_INITIAL;
first_->top = t;
first_->next_ = 0;

22
sync.cc
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sync.cc,v 1.3 2002/09/24 00:58:35 steve Exp $"
#endif
# include "config.h"
@ -59,23 +56,8 @@ bool NetEvWait::is_synchronous()
bool NetProcTop::is_synchronous()
{
if (type_ == NetProcTop::KINITIAL)
if (type_ == IVL_PR_INITIAL)
return false;
return statement_->is_synchronous();
}
/*
* $Log: sync.cc,v $
* Revision 1.3 2002/09/24 00:58:35 steve
* More detailed check of process edge events.
*
* Revision 1.2 2002/09/16 21:55:06 steve
* Reject multiple probes on synchronous logic.
*
* Revision 1.1 2002/09/16 00:30:33 steve
* Add to synth2 support for synthesis of
* synchronous logic. This includes DFF enables
* modeled by if/then/else.
*
*/

View File

@ -131,10 +131,10 @@ void synth_f::process(class Design*des, class NetProcTop*top)
{
top_ = top;
switch (top->type()) {
case NetProcTop::KALWAYS:
case IVL_PR_ALWAYS:
proc_always_(des);
break;
case NetProcTop::KINITIAL:
case IVL_PR_INITIAL:
proc_initial_(des);
break;
}

View File

@ -20,6 +20,7 @@
# include "config.h"
# include "StringHeap.h"
# include "t-dll.h"
# include "discipline.h"
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
@ -81,6 +82,16 @@ extern "C" ivl_net_const_t ivl_design_const(ivl_design_t des, unsigned idx)
return des->consts[idx];
}
extern "C" ivl_dis_domain_t ivl_discipline_domain(ivl_discipline_t net)
{
return net->domain();
}
extern "C" const char* ivl_discipline_name(ivl_discipline_t net)
{
return net->name();
}
extern "C" ivl_expr_type_t ivl_expr_type(ivl_expr_t net)
{
if (net == 0)
@ -1729,6 +1740,11 @@ extern "C" unsigned ivl_signal_dimensions(ivl_signal_t net)
return net->array_dimensions_;
}
extern "C" ivl_discipline_t ivl_signal_discipline(ivl_signal_t net)
{
return net->discipline;
}
extern "C" const char* ivl_signal_attr(ivl_signal_t net, const char*key)
{
if (net->nattr == 0)

View File

@ -39,16 +39,8 @@ bool dll_target::process(const NetProcTop*net)
ivl_process_t obj = (struct ivl_process_s*)
calloc(1, sizeof(struct ivl_process_s));
switch (net->type()) {
case NetProcTop::KINITIAL:
obj->type_ = IVL_PR_INITIAL;
break;
case NetProcTop::KALWAYS:
obj->type_ = IVL_PR_ALWAYS;
break;
default:
assert(0);
}
obj->type_ = net->type();
FILE_NAME(obj, net);
/* Save the scope of the process. */

View File

@ -1782,7 +1782,7 @@ void dll_target::lpm_modulo(const NetModulo*net)
unsigned wid = net->width_r();
obj->width = wid;
obj->u_.arith.signed_flag = 0;
obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
const Nexus*nex;
@ -2410,6 +2410,7 @@ void dll_target::signal(const NetNet*net)
obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1;
obj->isint_ = false;
obj->local_ = net->local_flag()? 1 : 0;
obj->discipline = net->get_discipline();
obj->array_dimensions_ = net->array_dimensions();

View File

@ -623,6 +623,7 @@ struct ivl_signal_s {
ivl_signal_type_t type_;
ivl_signal_port_t port_;
ivl_variable_type_t data_type;
ivl_discipline_t discipline;
perm_string file;
unsigned lineno;

View File

@ -1238,17 +1238,24 @@ static void show_signal(ivl_signal_t net)
break;
}
const char*discipline_txt = "NONE";
if (ivl_signal_discipline(net)) {
ivl_discipline_t dis = ivl_signal_discipline(net);
discipline_txt = ivl_discipline_name(dis);
}
for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) {
nex = ivl_signal_nex(net, idx);
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] <width=%u%s> nexus=%s\n",
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] <width=%u%s> <discipline=%s> nexus=%s\n",
type, sign, port, data_type,
ivl_signal_msb(net), ivl_signal_lsb(net),
ivl_signal_basename(net),
idx, ivl_signal_array_base(net)+idx,
ivl_signal_width(net),
ivl_signal_local(net)? ", local":"",
discipline_txt,
ivl_nexus_name(nex));
show_nexus_details(net, nex);

View File

@ -198,11 +198,11 @@ vhdl_expr *vhdl_expr::resize(int newwidth)
else
return this; // Doesn't make sense to resize non-vector type
vhdl_fcall *resize = new vhdl_fcall("Resize", rtype);
resize->add_expr(this);
resize->add_expr(new vhdl_const_int(newwidth));
vhdl_fcall *resizef = new vhdl_fcall("Resize", rtype);
resizef->add_expr(this);
resizef->add_expr(new vhdl_const_int(newwidth));
return resize;
return resizef;
}
vhdl_expr *vhdl_const_int::to_vector(vhdl_type_name_t name, int w)

View File

@ -157,10 +157,10 @@ int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
// function in VHDL
assert(i < count);
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
assert(net);
ivl_expr_t netp = ivl_stmt_parm(stmt, i++);
assert(netp);
vhdl_expr *base = translate_expr(net);
vhdl_expr *base = translate_expr(netp);
if (NULL == base)
return 1;

View File

@ -698,11 +698,11 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent)
for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i);
for (unsigned i = ivl_signal_array_base(sig);
i < ivl_signal_array_count(sig);
i++) {
for (unsigned j = ivl_signal_array_base(sig);
j < ivl_signal_array_count(sig);
j++) {
// Make sure the nexus code is generated
ivl_nexus_t nex = ivl_signal_nex(sig, i);
ivl_nexus_t nex = ivl_signal_nex(sig, j);
seen_nexus(nex);
nexus_private_t *priv =
@ -712,7 +712,7 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent)
vhdl_scope *arch_scope = ent->get_arch()->get_scope();
if (priv->const_driver) {
assert(i == 0); // TODO: Make work for more words
assert(j == 0); // TODO: Make work for more words
vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex);

View File

@ -424,8 +424,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
ivl_event_t event = ivl_stmt_events(stmt, i);
int nany = ivl_event_nany(event);
for (int i = 0; i < nany; i++) {
ivl_nexus_t nexus = ivl_event_any(event, i);
for (int j = 0; j < nany; j++) {
ivl_nexus_t nexus = ivl_event_any(event, j);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
wait->add_sensitivity(ref->get_name());
@ -441,8 +441,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
ivl_event_t event = ivl_stmt_events(stmt, i);
int nany = ivl_event_nany(event);
for (int i = 0; i < nany; i++) {
ivl_nexus_t nexus = ivl_event_any(event, i);
for (int j = 0; j < nany; j++) {
ivl_nexus_t nexus = ivl_event_any(event, j);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
ref->set_name(ref->get_name() + "'Event");
@ -450,8 +450,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
}
int nneg = ivl_event_nneg(event);
for (int i = 0; i < nneg; i++) {
ivl_nexus_t nexus = ivl_event_neg(event, i);
for (int j = 0; j < nneg; j++) {
ivl_nexus_t nexus = ivl_event_neg(event, j);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
vhdl_fcall *detect =
new vhdl_fcall("falling_edge", vhdl_type::boolean());
@ -461,8 +461,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
}
int npos = ivl_event_npos(event);
for (int i = 0; i < npos; i++) {
ivl_nexus_t nexus = ivl_event_pos(event, i);
for (int j = 0; j < npos; j++) {
ivl_nexus_t nexus = ivl_event_pos(event, j);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
vhdl_fcall *detect =
new vhdl_fcall("rising_edge", vhdl_type::boolean());

View File

@ -354,23 +354,17 @@ static int draw_signal_real_real(ivl_expr_t exp)
{
ivl_signal_t sig = ivl_expr_signal(exp);
int res = allocate_word();
unsigned long word = 0;
if (ivl_signal_dimensions(sig) > 0) {
ivl_expr_t ix = ivl_expr_oper1(exp);
if (!number_is_immediate(ix, IMM_WID, 0)) {
/* XXXX Need to generate a %load/ar instruction. */
assert(0);
if (ivl_signal_dimensions(sig) == 0) {
fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, sig);
return res;
}
/* The index is constant, so we can return to direct
readout with the specific word selected. */
word = get_number_immediate(ix);
}
fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word);
ivl_expr_t word_ex = ivl_expr_oper1(exp);
int word_ix = allocate_word();
draw_eval_expr_into_integer(word_ex, word_ix);
fprintf(vvp_out, " %%load/ar %d, v%p, %d;\n", res, sig, word_ix);
clr_word(word_ix);
return res;
}

View File

@ -497,16 +497,30 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
ivl_signal_t var;
res = draw_eval_real(ivl_stmt_rval(net));
clr_word(res);
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
var = ivl_lval_sig(lval);
assert(var != 0);
assert(ivl_signal_dimensions(var) == 0);
if (ivl_signal_dimensions(var) == 0) {
clr_word(res);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
return 0;
}
// For now, only support 1-dimensional arrays.
assert(ivl_signal_dimensions(var) == 1);
// Calculate the word index into an index register
ivl_expr_t word_ex = ivl_lval_idx(lval);
int word_ix = allocate_word();
draw_eval_expr_into_integer(word_ex, word_ix);
// Generate an assignment to write to the array.
fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res);
clr_word(res);
clr_word(word_ix);
return 0;
}

View File

@ -1170,6 +1170,8 @@ static void draw_lpm_add(ivl_lpm_t net)
case IVL_LPM_MOD:
if (dto == IVL_VT_REAL)
type = "mod.r";
else if (ivl_lpm_signed(net))
type = "mod.s";
else
type = "mod";
break;

View File

@ -100,7 +100,8 @@ static int vpi_get_dec_size(vpiHandle item)
);
}
static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
static int array_from_iterator(struct strobe_cb_info*info, vpiHandle argv,
int check_no_aa_vars)
{
if (argv) {
vpiHandle item;
@ -111,13 +112,17 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
free(items);
info->nitems = 0;
info->items = 0;
return;
return check_no_aa_vars;
}
if (check_no_aa_vars && vpi_get(vpiAutomatic, items[0]))
check_no_aa_vars = 0;
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
items = realloc(items, (nitems+1)*sizeof(vpiHandle));
items[nitems] = item;
nitems += 1;
if (check_no_aa_vars && vpi_get(vpiAutomatic, item))
check_no_aa_vars = 0;
}
info->nitems = nitems;
@ -127,6 +132,7 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
info->nitems = 0;
info->items = 0;
}
return check_no_aa_vars;
}
/*
@ -902,7 +908,7 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8*name)
info = malloc(sizeof (struct strobe_cb_info));
info->default_format = get_default_format(name);
info->scope = scope;
array_from_iterator(info, argv);
array_from_iterator(info, argv, 0);
vpi_put_userdata(sys, info);
}
@ -995,7 +1001,13 @@ static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name)
info->mcd = 1;
}
array_from_iterator(info, argv);
if (!array_from_iterator(info, argv, 1)) {
vpi_printf("ERROR: %s parameters may not include automatically "
"allocated variables\n", name);
free(info->items);
free(info);
return 0;
}
info->name = strdup(name);
info->default_format = get_default_format(name);
info->scope= scope;
@ -1095,7 +1107,13 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
}
/* Make an array of handles from the argument list. */
array_from_iterator(&monitor_info, argv);
if (!array_from_iterator(&monitor_info, argv, 1)) {
vpi_printf("ERROR: $monitor parameters may not include "
"automatically allocated variables\n");
free(monitor_info.items);
monitor_info.nitems = 0;
return 0;
}
monitor_info.name = strdup(name);
monitor_info.default_format = get_default_format(name);
monitor_info.scope = scope;
@ -1211,7 +1229,7 @@ static PLI_INT32 sys_fdisplay_calltf(PLI_BYTE8*name)
assert(scope);
info.default_format = get_default_format(name);
info.scope = scope;
array_from_iterator(&info, argv);
array_from_iterator(&info, argv, 0);
do_display(mcd, &info);
free(info.items);
@ -1969,7 +1987,7 @@ static PLI_INT32 sys_swrite_calltf(PLI_BYTE8 *name)
info.name = name;
info.default_format = get_default_format(name);
info.scope = scope;
array_from_iterator(&info, argv);
array_from_iterator(&info, argv, 0);
/* Because %u and %z may put embedded NULL characters into the returned
* string strlen() may not match the real size! */
@ -2049,7 +2067,7 @@ static PLI_INT32 sys_sformat_calltf(PLI_BYTE8 *name)
info.name = name;
info.default_format = get_default_format(name);
info.scope = scope;
array_from_iterator(&info, argv);
array_from_iterator(&info, argv, 0);
idx = -1;
size = get_format(&result, fmt, &info, &idx);
free(fmt);

View File

@ -144,13 +144,25 @@ void vvp_arith_div::wide4_(vvp_net_ptr_t ptr)
}
vvp_vector2_t b2 (op_b_);
if (b2.is_NaN()) {
if (b2.is_NaN() || b2.is_zero()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
return;
}
vvp_vector2_t res2 = a2 / b2;
vvp_send_vec4(ptr.ptr()->out, vector2_to_vector4(res2, wid_), 0);
bool negate = false;
if (signed_flag_) {
if (a2.value(a2.size()-1)) {
a2 = -a2;
negate = true;
}
if (b2.value(b2.size()-1)) {
b2 = -b2;
negate = !negate;
}
}
vvp_vector2_t res = a2 / b2;
if (negate) res = -res;
vvp_send_vec4(ptr.ptr()->out, vector2_to_vector4(res, wid_), 0);
}
void vvp_arith_div::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
@ -180,17 +192,34 @@ void vvp_arith_div::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
the operands for now, and remember to put the sign back
later. */
if (signed_flag_) {
unsigned long sign_mask = 0;
if (op_a_.size() != 8 * sizeof(unsigned long)) {
sign_mask = -1UL << op_a_.size();
}
if (op_a_.value(op_a_.size()-1)) {
a = (-a) & ~ (-1UL << op_a_.size());
a = (-a) & ~sign_mask;
negate = !negate;
}
sign_mask = 0;
if (op_b_.size() != 8 * sizeof(unsigned long)) {
sign_mask = -1UL << op_b_.size();
}
if (op_b_.value(op_b_.size()-1)) {
b = (-b) & ~ (-1UL << op_b_.size());
b = (-b) & ~sign_mask;
negate = ! negate;
}
}
if (b == 0) {
vvp_vector4_t xval (wid_);
for (unsigned idx = 0 ; idx < wid_ ; idx += 1)
xval.set_bit(idx, BIT4_X);
vvp_send_vec4(ptr.ptr()->out, xval, 0);
return;
}
unsigned long val = a / b;
if (negate)
val = -val;
@ -229,12 +258,23 @@ void vvp_arith_mod::wide_(vvp_net_ptr_t ptr)
}
vvp_vector2_t b2 (op_b_);
if (b2.is_NaN()) {
if (b2.is_NaN() || b2.is_zero()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
return;
}
bool negate = false;
if (signed_flag_) {
if (a2.value(a2.size()-1)) {
a2 = -a2;
negate = true;
}
if (b2.value(b2.size()-1)) {
b2 = -b2;
}
}
vvp_vector2_t res = a2 % b2;
if (negate) res = -res;
vvp_send_vec4(ptr.ptr()->out, vector2_to_vector4(res, res.size()), 0);
}
@ -265,14 +305,21 @@ void vvp_arith_mod::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
the operands for now, and remember to put the sign back
later. */
if (signed_flag_) {
unsigned long sign_mask = 0;
if (op_a_.size() != 8 * sizeof(unsigned long)) {
sign_mask = -1UL << op_a_.size();
}
if (op_a_.value(op_a_.size()-1)) {
a = (-a) & ~ (-1UL << op_a_.size());
a = (-a) & ~sign_mask;
negate = !negate;
}
sign_mask = 0;
if (op_b_.size() != 8 * sizeof(unsigned long)) {
sign_mask = -1UL << op_b_.size();
}
if (op_b_.value(op_b_.size()-1)) {
b = (-b) & ~ (-1UL << op_b_.size());
negate = ! negate;
b = (-b) & ~sign_mask;
}
}

View File

@ -53,7 +53,28 @@ vvp_array_t array_find(const char*label)
/*
* The vpiArray object holds an array of vpi objects that themselves
* represent the words of the array. The vpi_array_t is a pointer to this.
* represent the words of the array. The vpi_array_t is a pointer to
* a struct __vpiArray.
*
* The details of the implementation depends on what this is an array
* of. The easiest case is if this is an array of nets.
*
* - Array of Nets:
* If this represents an array of nets, then the nets member points to
* an array of vpiHandle objects. Each vpiHandle is a word. This is
* done because typically each word of a net array is simultaneously
* driven and accessed by other means, so there is no advantage to
* compacting the array in any other way.
*
* - Array of vector4 words.
* In this case, the nets pointer is nil, and the vals4 member points
* to a vvl_vector4array_t object that is a compact representation of
* an array of vvp_vector4_t vectors.
*
* - Array of real variables
* The valsr member points to a vvp_realarray_t objects that has an
* array of double variables. This is very much line the way the
* vector4 array works.
*/
struct __vpiArray {
__vpiArray() { }
@ -70,7 +91,8 @@ struct __vpiArray {
// If this is a net array, nets lists the handles.
vpiHandle*nets;
// If this is a var array, then these are used instead of nets.
vvp_vector4array_t *vals;
vvp_vector4array_t *vals4;
vvp_realarray_t *valsr;
struct __vpiArrayWord*vals_words;
class vvp_fun_arrayport*ports_;
@ -127,7 +149,7 @@ struct __vpiArrayVthrA {
/* Get the array word size. This has only been checked for reg arrays. */
unsigned get_array_word_size(vvp_array_t array)
{
assert(array->vals);
assert(array->vals4);
return array->vals_width;
}
@ -424,7 +446,7 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
switch (code) {
case vpiSize:
return (int) parent->vals->width();
return (int) parent->vals4->width();
case vpiLeftRange:
return parent->msb.value;
@ -432,6 +454,9 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
case vpiRightRange:
return parent->lsb.value;
case vpiAutomatic:
return (int) parent->scope->is_automatic;
default:
return 0;
}
@ -461,9 +486,9 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
unsigned width = parent->vals->width();
unsigned width = parent->vals4->width();
vpip_vec4_get_value(parent->vals->get_word(index), width,
vpip_vec4_get_value(parent->vals4->get_word(index), width,
parent->signed_flag, value);
}
@ -539,7 +564,7 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int)
if (obj->array->nets)
return obj->array->nets[obj->next];
assert(obj->array->vals);
assert(obj->array->vals4);
if (obj->array->vals_words == 0)
array_make_vals_words(obj->array);
@ -612,6 +637,9 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
case vpiRightRange:
return parent->lsb.value;
case vpiAutomatic:
return (int) parent->scope->is_automatic;
// For now &A<> is only a constant select. This will need
// to be changed when it supports variable selection.
case vpiConstantSelect:
@ -702,10 +730,10 @@ void array_set_word(vvp_array_t arr,
if (address >= arr->array_count)
return;
if (arr->vals) {
if (arr->vals4) {
assert(arr->nets == 0);
if (part_off != 0 || val.size() != arr->vals_width) {
vvp_vector4_t tmp = arr->vals->get_word(address);
vvp_vector4_t tmp = arr->vals4->get_word(address);
if ((part_off + val.size()) > tmp.size()) {
cerr << "part_off=" << part_off
<< " val.size()=" << val.size()
@ -714,9 +742,9 @@ void array_set_word(vvp_array_t arr,
assert(0);
}
tmp.set_vec(part_off, val);
arr->vals->set_word(address, tmp);
arr->vals4->set_word(address, tmp);
} else {
arr->vals->set_word(address, val);
arr->vals4->set_word(address, val);
}
array_word_change(arr, address);
return;
@ -734,15 +762,22 @@ void array_set_word(vvp_array_t arr,
array_word_change(arr, address);
}
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
void array_set_word(vvp_array_t arr, unsigned address, double val)
{
if (arr->vals) {
assert(arr->valsr!= 0);
assert(arr->nets == 0);
return arr->vals->get_word(address);
arr->valsr->set_word(address, val);
}
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
{
if (arr->vals4) {
assert(arr->nets == 0);
return arr->vals4->get_word(address);
}
assert(arr->vals == 0);
assert(arr->vals4 == 0);
assert(arr->nets != 0);
if (address >= arr->array_count) {
@ -767,6 +802,26 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
return val;
}
double array_get_word_r(vvp_array_t arr, unsigned address)
{
if (arr->valsr) {
assert(arr->vals4 == 0);
assert(arr->nets == 0);
return arr->valsr->get_word(address);
}
assert(arr->nets);
vpiHandle word = arr->nets[address];
struct __vpiRealVar*vsig = vpip_realvar_from_handle(word);
assert(vsig);
vvp_fun_signal_real*sig = dynamic_cast<vvp_fun_signal_real*> (vsig->net->fun);
assert(sig);
double val = sig->real_value();
return val;
}
static vpiHandle vpip_make_array(char*label, const char*name,
int first_addr, int last_addr,
bool signed_flag)
@ -792,7 +847,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,
// Start off now knowing if we are nets or variables.
obj->nets = 0;
obj->vals = 0;
obj->vals4 = 0;
obj->valsr = 0;
obj->vals_width = 0;
vpip_make_dec_const(&obj->msb, 0);
vpip_make_dec_const(&obj->lsb, 0);
@ -842,6 +898,19 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
sig->is_netarray = 1;
sig->within.parent = &array->base;
sig->id.index = vpip_make_dec_const(addr + array->first_addr.value);
return;
}
if (struct __vpiRealVar*sig = (struct __vpiRealVar*)word) {
vvp_net_t*net = sig->net;
assert(net);
vvp_fun_signal_base*fun = dynamic_cast<vvp_fun_signal_base*>(net->fun);
assert(fun);
fun->attach_as_word(array, addr);
sig->is_netarray = 1;
sig->within.parent = &array->base;
sig->id.index = vpip_make_dec_const(addr + array->first_addr.value);
return;
}
}
@ -856,10 +925,10 @@ void compile_var_array(char*label, char*name, int last, int first,
/* Make the words. */
arr->vals_width = labs(msb-lsb) + 1;
if (vpip_peek_current_scope()->is_automatic) {
arr->vals = new vvp_vector4array_aa(arr->vals_width,
arr->vals4 = new vvp_vector4array_aa(arr->vals_width,
arr->array_count);
} else {
arr->vals = new vvp_vector4array_sa(arr->vals_width,
arr->vals4 = new vvp_vector4array_sa(arr->vals_width,
arr->array_count);
}
vpip_make_dec_const(&arr->msb, msb);
@ -878,14 +947,16 @@ void compile_real_array(char*label, char*name, int last, int first,
vpiHandle obj = vpip_make_array(label, name, first, last, true);
struct __vpiArray*arr = ARRAY_HANDLE(obj);
vvp_array_t array = array_find(label);
/* Make the words. */
for (unsigned idx = 0 ; idx < arr->array_count ; idx += 1) {
char buf[64];
snprintf(buf, sizeof buf, "%s_%u", label, idx);
compile_varw_real(strdup(buf), array, idx, msb, lsb);
}
arr->valsr = new vvp_realarray_t(arr->array_count);
arr->vals_width = 1;
/* Do these even make sense for real arrays? These are the
part select of a vector, but the real value is not
vectorable. */
vpip_make_dec_const(&arr->msb, msb);
vpip_make_dec_const(&arr->lsb, lsb);
count_real_arrays += 1;
count_real_array_words += arr->array_count;
@ -1133,7 +1204,7 @@ void array_word_change(vvp_array_t array, unsigned long addr)
if (cur->cb_data.cb_rtn != 0) {
if (cur->cb_data.value)
vpip_vec4_get_value(array->vals->get_word(addr),
vpip_vec4_get_value(array->vals4->get_word(addr),
array->vals_width,
array->signed_flag,
cur->cb_data.value);
@ -1269,7 +1340,7 @@ void compile_array_alias(char*label, char*name, char*src)
// Share the words with the source array.
obj->nets = mem->nets;
obj->vals = mem->vals;
obj->vals4 = mem->vals4;
obj->ports_ = 0;

View File

@ -39,12 +39,13 @@ extern void array_attach_word(vvp_array_t array, unsigned long addr,
extern void array_alias_word(vvp_array_t array, unsigned long addr,
vpiHandle word);
extern void array_set_word(vvp_array_t arr,
unsigned idx,
unsigned off,
vvp_vector4_t val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
unsigned off, vvp_vector4_t val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
double val);
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address);
extern double array_get_word_r(vvp_array_t array, unsigned address);
/* VPI hooks */

View File

@ -107,6 +107,7 @@ extern bool of_JMP0(vthread_t thr, vvp_code_t code);
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
extern bool of_JMP1(vthread_t thr, vvp_code_t code);
extern bool of_JOIN(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code);
@ -138,6 +139,7 @@ extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);

View File

@ -150,6 +150,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
@ -181,11 +182,11 @@ const static struct opcode_table_s opcode_table[] = {
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%set/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
// { "%set/x0/x",of_SET_X0_X,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} },
@ -978,7 +979,7 @@ void compile_arith_div_r(char*label, unsigned argc, struct symb_s*argv)
make_arith(arith, label, argc, argv);
}
void compile_arith_mod(char*label, long wid,
void compile_arith_mod(char*label, long wid, bool signed_flag,
unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
@ -989,7 +990,7 @@ void compile_arith_mod(char*label, long wid,
return;
}
vvp_arith_ *arith = new vvp_arith_mod(wid, false);
vvp_arith_ *arith = new vvp_arith_mod(wid, signed_flag);
make_arith(arith, label, argc, argv);
}

View File

@ -157,7 +157,7 @@ extern void compile_arith_cast_real(char*label, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_div(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_mod(char*label, long width,
extern void compile_arith_mod(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_mult(char*label, long width,
unsigned argc, struct symb_s*argv);

View File

@ -93,6 +93,7 @@
".arith/div.s" { return K_ARITH_DIV_S; }
".arith/mod" { return K_ARITH_MOD; }
".arith/mod.r" { return K_ARITH_MOD_R; }
".arith/mod.s" { return K_ARITH_MOD_S; }
".arith/mult" { return K_ARITH_MULT; }
".arith/mult.r" { return K_ARITH_MULT_R; }
".arith/pow" { return K_ARITH_POW; }

View File

@ -512,9 +512,14 @@ The <wid> is, line the %load/v, the result width. But unlike the
(%load/vp0/s) to the desired width.
* %load/wr <bit>, <vpi-label>
* %load/ar <bit>, <array-label>, <index>
This instruction reads a real value from the vpi-like object to a word
register.
The %load/wr instruction reads a real value from the vpi-like object
to a word register <bit>.
The %load/ar instruction reads a real value from an array. The <index>
is the index register that contains the canonical word address into
the array.
* %load/x1p <bit>, <functor-label>, <wid>
@ -708,8 +713,17 @@ The address (in canonical form) is precalculated and loaded into index
register 3. This is the address of the word within the array.
* %set/wr <vpi-label>, <bit>
* %set/ar <array-label>, <index>, <bit>
This instruction writes a real word to the specified VPI-like object.
The %set/wr instruction writes a real word to the specified VPI-like
object.
The %set/ar instruction writes a real work to the specified array
word. The <array-label> addresses the array, and the <index> is the
name of the index register to address into the word. The index
register must contain an integer value that is the canonical address
of the array word. The <bit> is the index register that contains the
real value word to write.
* %set/x0 <var-label>, <bit>, <wid>

View File

@ -67,7 +67,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_A K_ALIAS K_ALIAS_S K_ALIAS_R
%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD
%token K_ARITH_MOD_R
%token K_ARITH_MOD_R K_ARITH_MOD_S
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S
%token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT
@ -288,7 +288,7 @@ statement
| T_LABEL K_ARITH_MOD T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_mod($1, $3, obj.cnt, obj.vect);
compile_arith_mod($1, $3, false, obj.cnt, obj.vect);
}
| T_LABEL K_ARITH_MOD_R T_NUMBER ',' symbols ';'
@ -296,6 +296,11 @@ statement
compile_arith_mod_r($1, obj.cnt, obj.vect);
}
| T_LABEL K_ARITH_MOD_S T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_mod($1, $3, true, obj.cnt, obj.vect);
}
| T_LABEL K_ARITH_MULT T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_mult($1, $3, obj.cnt, obj.vect);

View File

@ -119,6 +119,14 @@ void delete_vpi_callback(struct __vpiCallback* ref)
*/
static struct __vpiCallback* make_value_change(p_cb_data data)
{
if (vpi_get(vpiAutomatic, data->obj)) {
fprintf(stderr, "vpi error: cannot place value change "
"callback on automatically allocated "
"variable '%s'\n",
vpi_get_str(vpiName, data->obj));
return 0;
}
struct __vpiCallback*obj = new_vpi_callback();
obj->cb_data = *data;
if (data->time) {

View File

@ -47,6 +47,9 @@ static int string_get(int code, vpiHandle ref)
case vpiConstType:
return vpiStringConst;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiStringConst\n", code);
@ -343,6 +346,9 @@ static int binary_get(int code, vpiHandle ref)
case vpiSize:
return rfp->bits.size();
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiBinaryConst\n", code);
@ -533,6 +539,9 @@ static int dec_get(int code, vpiHandle ref)
case vpiSize:
return 32;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiDecConst\n", code);
@ -636,6 +645,9 @@ static int real_get(int code, vpiHandle ref)
case vpiSigned:
return 1;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiDecConst\n", code);

View File

@ -58,6 +58,14 @@ struct __vpiScope* vpip_scope(__vpiSignal*sig)
return sig->within.scope;
}
struct __vpiScope* vpip_scope(__vpiRealVar*sig)
{
if (sig->is_netarray)
return (struct __vpiScope*) vpi_handle(vpiScope, sig->within.parent);
else
return sig->within.scope;
}
const char *vpip_string(const char*str)
{
static vpip_string_chunk first_chunk = {0, {0}};
@ -684,6 +692,14 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) {
vvp_time64_t dly;
if (vpi_get(vpiAutomatic, obj)) {
fprintf(stderr, "vpi error: cannot put a value with "
"a delay on automatically allocated "
"variable '%s'\n",
vpi_get_str(vpiName, obj));
return 0;
}
assert(when != 0);
switch (when->type) {

View File

@ -223,7 +223,6 @@ struct __vpiSignal {
unsigned signed_flag : 1;
unsigned isint_ : 1; // original type was integer
unsigned is_netarray : 1; // This is word of a net array
unsigned is_automatic : 1;
/* The represented value is here. */
vvp_net_t*node;
};
@ -354,17 +353,22 @@ extern void vpip_real_value_change(struct __vpiCallback*cbh,
*/
struct __vpiRealVar {
struct __vpiHandle base;
union { // The scope or parent array that contains me.
vpiHandle parent;
struct __vpiScope* scope;
} within;
/* The name of this variable, or the index for array words. */
union {
const char*name;
vpiHandle index;
} id;
unsigned is_netarray : 1; // This is word of a net array
vvp_net_t*net;
};
extern struct __vpiScope* vpip_scope(__vpiRealVar*sig);
extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net);
extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj);
/*
* When a loaded VPI module announces a system task/function, one

View File

@ -28,15 +28,24 @@
#endif
# include <assert.h>
struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj)
{
assert(obj);
if (obj->vpi_type->type_code == vpiRealVar)
return (struct __vpiRealVar*)obj;
else
return 0;
}
static int real_var_get(int code, vpiHandle ref)
{
assert(ref->vpi_type->type_code == vpiRealVar);
struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref;
struct __vpiRealVar*rfp = vpip_realvar_from_handle(ref);
switch (code) {
case vpiArray:
return rfp->parent != 0;
return rfp->is_netarray != 0;
case vpiSize:
return 1;
@ -45,7 +54,7 @@ static int real_var_get(int code, vpiHandle ref)
return 0; // Not implemented for now!
case vpiAutomatic:
return (int) rfp->scope->is_automatic;
return (int) vpip_scope(rfp)->is_automatic;
}
return 0;
@ -62,8 +71,8 @@ static char* real_var_get_str(int code, vpiHandle ref)
}
char *nm, *ixs;
if (rfp->parent) {
nm = strdup(vpi_get_str(vpiName, rfp->parent));
if (rfp->is_netarray) {
nm = strdup(vpi_get_str(vpiName, rfp->within.parent));
s_vpi_value vp;
vp.format = vpiDecStrVal;
vpi_get_value(rfp->id.index, &vp);
@ -73,7 +82,7 @@ static char* real_var_get_str(int code, vpiHandle ref)
ixs = NULL;
}
char *rbuf = generic_get_str(code, &rfp->scope->base, nm, ixs);
char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs);
free(nm);
return rbuf;
}
@ -87,10 +96,13 @@ static vpiHandle real_var_get_handle(int code, vpiHandle ref)
switch (code) {
case vpiParent:
return rfp->parent;
return rfp->is_netarray ? rfp->within.parent : 0;
case vpiIndex:
return rfp->parent ? rfp->id.index : 0;
return rfp->is_netarray ? rfp->id.index : 0;
case vpiScope:
return &(vpip_scope(rfp)->base);
}
return 0;
@ -103,7 +115,7 @@ static vpiHandle real_var_iterate(int code, vpiHandle ref)
struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref;
if (code == vpiIndex) {
return rfp->parent ? (rfp->id.index->vpi_type->iterate_)
return rfp->is_netarray ? (rfp->id.index->vpi_type->iterate_)
(code, rfp->id.index) : 0;
}
@ -179,22 +191,17 @@ void vpip_real_value_change(struct __vpiCallback*cbh,
fun->add_vpi_callback(cbh);
}
/*
* Since reals do not currently support arrays none of the array code
* has been tested! Though it should work since it is a copy of the
* signal code.
*/
vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net)
{
struct __vpiRealVar*obj = (struct __vpiRealVar*)
malloc(sizeof(struct __vpiRealVar));
obj->base.vpi_type = &vpip_real_var_rt;
obj->parent = 0;
obj->id.name = name ? vpip_name_string(name) : 0;
obj->is_netarray = 0;
obj->net = net;
obj->scope = vpip_peek_current_scope();
obj->within.scope = vpip_peek_current_scope();
return &obj->base;
}

View File

@ -75,6 +75,9 @@ static int scope_get(int code, vpiHandle obj)
case vpiTopModule:
return 0x0 == ref->scope;
case vpiAutomatic:
return (int) ref->is_automatic;
}
return 0;
@ -330,33 +333,29 @@ compile_scope_decl(char*label, char*type, char*name, const char*tname,
struct __vpiScope*scope = new struct __vpiScope;
count_vpi_scopes += 1;
if (strcmp(type,"module") == 0) {
char*base_type = 0;
if (strncmp(type,"auto",4) == 0) {
scope->is_automatic = true;
base_type = &type[4];
} else {
scope->is_automatic = false;
base_type = &type[0];
}
if (strcmp(base_type,"module") == 0) {
scope->base.vpi_type = &vpip_scope_module_rt;
scope->is_automatic = false;
} else if (strcmp(type,"autofunction") == 0) {
} else if (strcmp(base_type,"function") == 0) {
scope->base.vpi_type = &vpip_scope_function_rt;
scope->is_automatic = true;
} else if (strcmp(type,"function") == 0) {
scope->base.vpi_type = &vpip_scope_function_rt;
scope->is_automatic = false;
} else if (strcmp(type,"autotask") == 0) {
} else if (strcmp(base_type,"task") == 0) {
scope->base.vpi_type = &vpip_scope_task_rt;
scope->is_automatic = true;
} else if (strcmp(type,"task") == 0) {
scope->base.vpi_type = &vpip_scope_task_rt;
scope->is_automatic = false;
} else if (strcmp(type,"fork") == 0) {
} else if (strcmp(base_type,"fork") == 0) {
scope->base.vpi_type = &vpip_scope_fork_rt;
scope->is_automatic = false;
} else if (strcmp(type,"begin") == 0) {
} else if (strcmp(base_type,"begin") == 0) {
scope->base.vpi_type = &vpip_scope_begin_rt;
scope->is_automatic = false;
} else if (strcmp(type,"generate") == 0) {
} else if (strcmp(base_type,"generate") == 0) {
scope->base.vpi_type = &vpip_scope_begin_rt;
scope->is_automatic = false;
} else {
scope->base.vpi_type = &vpip_scope_module_rt;
scope->is_automatic = false;
assert(0);
}
@ -396,10 +395,6 @@ compile_scope_decl(char*label, char*type, char*name, const char*tname,
scope->time_units = sp->time_units;
scope->time_precision = sp->time_precision;
/* Scopes within automatic scopes are themselves automatic. */
if (sp->is_automatic)
scope->is_automatic = true;
} else {
scope->scope = 0x0;
@ -476,5 +471,3 @@ unsigned vpip_add_item_to_context(automatic_hooks_s*item,
/* Offset the context index by 2 to leave space for the list links. */
return 2 + idx;
}

View File

@ -528,10 +528,14 @@ static int signal_get(int code, vpiHandle ref)
else
return 0;
case vpiLeftRange: return rfp->msb;
case vpiRightRange: return rfp->lsb;
case vpiLeftRange:
return rfp->msb;
case vpiAutomatic: return rfp->is_automatic;
case vpiRightRange:
return rfp->lsb;
case vpiAutomatic:
return (int) vpip_scope(rfp)->is_automatic;
case _vpiNexusId:
if (rfp->msb == rfp->lsb)
@ -863,7 +867,6 @@ vpiHandle vpip_make_int(const char*name, int msb, int lsb, vvp_net_t*vec)
struct __vpiSignal*rfp = (struct __vpiSignal*)obj;
obj->vpi_type = &vpip_reg_rt;
rfp->isint_ = true;
rfp->is_automatic = vpip_peek_current_scope()->is_automatic;
return obj;
}
@ -876,7 +879,6 @@ vpiHandle vpip_make_reg(const char*name, int msb, int lsb,
vpiHandle obj = vpip_make_net(name, msb,lsb, signed_flag, vec);
struct __vpiSignal*rfp = (struct __vpiSignal*)obj;
obj->vpi_type = &vpip_reg_rt;
rfp->is_automatic = vpip_peek_current_scope()->is_automatic;
return obj;
}
@ -915,7 +917,6 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb,
obj->signed_flag = signed_flag? 1 : 0;
obj->isint_ = 0;
obj->is_netarray = 0;
obj->is_automatic = vpip_peek_current_scope()->is_automatic;
obj->node = node;
// Place this object within a scope. If this object is
@ -972,11 +973,15 @@ static int PV_get(int code, vpiHandle ref)
case vpiConstantSelect:
return rfp->twid == 0;
case vpiLeftRange: rval += rfp->width;
case vpiLeftRange:
rval += rfp->width;
case vpiRightRange:
rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp);
return rval;
case vpiAutomatic:
return vpi_get(vpiAutomatic, rfp->parent);
default:
fprintf(stderr, "PV_get: property %d is unknown\n", code);
}

View File

@ -93,6 +93,9 @@ static int timevar_time_get(int code, vpiHandle ref)
case vpiFuncType:
return vpiTimeFunc;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
@ -148,6 +151,9 @@ static int timevar_realtime_get(int code, vpiHandle ref)
case vpiFuncType:
return vpiRealFunc;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);

View File

@ -2752,6 +2752,20 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp)
return false;
}
/*
* %load/ar <bit>, <array-label>, <index>;
*/
bool of_LOAD_AR(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned idx = cp->bit_idx[1];
unsigned adr = thr->words[idx].w_int;
double word = array_get_word_r(cp->array, adr);
thr->words[bit].w_real = word;
return true;
}
/*
* %load/av <bit>, <array-label>, <wid> ;
*
@ -3071,7 +3085,7 @@ bool of_LOADI_WR(vthread_t thr, vvp_code_t cp)
static void do_verylong_mod(vthread_t thr, vvp_code_t cp,
bool left_is_neg, bool right_is_neg)
{
bool out_is_neg = left_is_neg != right_is_neg;
bool out_is_neg = left_is_neg;
int len=cp->number;
unsigned char *a, *z, *t;
a = new unsigned char[len+1];
@ -3936,6 +3950,24 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %set/av <label>, <index>, <bit>
*
* Write the real value in register <bit> to the array indexed by the
* integer value addressed bin index register <index>.
*/
bool of_SET_AR(vthread_t thr, vvp_code_t cp)
{
unsigned idx = cp->bit_idx[0];
unsigned bit = cp->bit_idx[1];
unsigned adr = thr->words[idx].w_int;
double value = thr->words[bit].w_real;
array_set_word(cp->array, adr, value);
return true;
}
/*
* This implements the "%set/av <label>, <bit>, <wid>" instruction. In
* this case, the <label> is an array label, and the <bit> and <wid>

View File

@ -1299,6 +1299,32 @@ bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag)
return flag;
}
vvp_realarray_t::vvp_realarray_t(unsigned wor)
: words_(wor)
{
array_ = new double[words_];
}
vvp_realarray_t::~vvp_realarray_t()
{
delete[]array_;
}
void vvp_realarray_t::set_word(unsigned word, double value)
{
if (word >= words_)
return;
array_[word] = value;
}
double vvp_realarray_t::get_word(unsigned word) const
{
if (word >= words_)
return 0.0;
else
return array_[word];
}
vvp_vector4array_t::vvp_vector4array_t(unsigned width__, unsigned words__)
: width_(width__), words_(words__)
{
@ -1994,6 +2020,21 @@ static void div_mod (vvp_vector2_t dividend, vvp_vector2_t divisor,
remainder = vvp_vector2_t(dividend, mask.size());
}
vvp_vector2_t operator - (const vvp_vector2_t&that)
{
vvp_vector2_t neg(that);
if (neg.wid_ == 0) return neg;
const unsigned words = (neg.wid_ + neg.BITS_PER_WORD-1) /
neg.BITS_PER_WORD;
for (unsigned idx = 0 ; idx < words ; idx += 1) {
neg.vec_[idx] = ~neg.vec_[idx];
}
neg += vvp_vector2_t(1, neg.wid_);
return neg;
}
vvp_vector2_t operator / (const vvp_vector2_t&dividend,
const vvp_vector2_t&divisor)
{

View File

@ -467,6 +467,26 @@ extern bool vector4_to_value(const vvp_vector4_t&a, vvp_time64_t&val);
#endif
extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed);
/*
* The __vpiArray handle uses instances of this to keep an array of
* real valued variables.
*/
class vvp_realarray_t {
public:
vvp_realarray_t(unsigned words);
~vvp_realarray_t();
unsigned words() const { return words_; }
double get_word(unsigned idx) const;
void set_word(unsigned idx, double val);
private:
unsigned words_;
double*array_;
};
/*
* vvp_vector4array_t
*/
@ -544,6 +564,7 @@ class vvp_vector4array_aa : public vvp_vector4array_t, public automatic_hooks_s
*/
class vvp_vector2_t {
friend vvp_vector2_t operator - (const vvp_vector2_t&);
friend vvp_vector2_t operator + (const vvp_vector2_t&,
const vvp_vector2_t&);
friend vvp_vector2_t operator * (const vvp_vector2_t&,
@ -599,6 +620,7 @@ extern bool operator >= (const vvp_vector2_t&, const vvp_vector2_t&);
extern bool operator < (const vvp_vector2_t&, const vvp_vector2_t&);
extern bool operator <= (const vvp_vector2_t&, const vvp_vector2_t&);
extern bool operator == (const vvp_vector2_t&, const vvp_vector2_t&);
extern vvp_vector2_t operator - (const vvp_vector2_t&);
extern vvp_vector2_t operator + (const vvp_vector2_t&, const vvp_vector2_t&);
extern vvp_vector2_t operator * (const vvp_vector2_t&, const vvp_vector2_t&);
extern vvp_vector2_t operator / (const vvp_vector2_t&, const vvp_vector2_t&);

View File

@ -270,6 +270,8 @@ void compile_netw_real(char*label, char*array_label, unsigned long array_addr,
int msb, int lsb,
unsigned argc, struct symb_s*argv)
{
cerr << "XXXX compile_netw_real: label=" << label
<< ", array_label=" << array_label << endl;
__compile_real(label, 0, array_label, array_addr,
msb, lsb, false, argc, argv);
}