Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
5911fbf872
22
BUGS.txt
22
BUGS.txt
|
|
@ -116,13 +116,17 @@ programs.
|
|||
|
||||
RESEARCHING EXISTING/PAST BUGS, AND FILING REPORTS
|
||||
|
||||
The URL <http://sourceforge.net/tracker/?group_id=149850> is the main
|
||||
bug tracking system. Once you believe you have found a bug, you may
|
||||
browse the bugs database for existing bugs that may be related to
|
||||
yours. You might find that your bug has already been fixed in a later
|
||||
release or snapshot. If that's the case, then you are set. Also,
|
||||
consider if you are reporting a bug or really asking for a new
|
||||
feature, and use the appropriate tracker.
|
||||
The URL <https://sourceforge.net/p/iverilog/bugs/> is the main
|
||||
bug tracking system, although some users have reported bugs at
|
||||
<https://github.com/steveicarus/iverilog/issues/>. Once you believe
|
||||
you have found a bug, you may browse the bugs database for existing
|
||||
bugs that may be related to yours. You might find that your bug has
|
||||
already been fixed in a later release or snapshot. If that's the case,
|
||||
then you are set. Also, consider if you are reporting a bug or really
|
||||
asking for a new feature, and use the appropriate tracker.
|
||||
|
||||
system (although you will also find bug rep
|
||||
|
||||
|
||||
The bug database supports basic keyword searches, and you can
|
||||
optionally limit your search to active bugs, or fixed bugs. You may
|
||||
|
|
@ -145,7 +149,7 @@ version from git. Please see the developer documentation for more
|
|||
detailed instructions -- <http://iverilog.wikia.com/wiki/>.
|
||||
|
||||
When you make a patch, submit it to the "Patches" tracker at
|
||||
<http://sourceforge.net/tracker/?group_id=149850>. Patches added to
|
||||
<https://sourceforge.net/p/iverilog/patches/>. Patches added to
|
||||
the "Patches" tracker enter the developer workflow, are checked,
|
||||
applied to the appropriate git branch, and are pushed. Then the
|
||||
tracker item is closed.
|
||||
|
|
@ -158,7 +162,7 @@ clarification before applying it.)
|
|||
|
||||
COPYRIGHT ISSUES
|
||||
|
||||
Icarus Verilog is Copyright (c) 1998-2008 Stephen Williams except
|
||||
Icarus Verilog is Copyright (c) 1998-2018 Stephen Williams except
|
||||
where otherwise noted. Minor patches are covered as derivative works
|
||||
(or editorial comment or whatever the appropriate legal term is) and
|
||||
folded into the rest of ivl. However, if a submission can reasonably
|
||||
|
|
|
|||
2
HName.cc
2
HName.cc
|
|
@ -40,7 +40,7 @@ hname_t::hname_t(perm_string text, int num)
|
|||
number_[0] = num;
|
||||
}
|
||||
|
||||
hname_t::hname_t(perm_string text, vector<int>&nums)
|
||||
hname_t::hname_t(perm_string text, const vector<int>&nums)
|
||||
: name_(text), number_(nums)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
13
HName.h
13
HName.h
|
|
@ -42,7 +42,7 @@ class hname_t {
|
|||
hname_t ();
|
||||
explicit hname_t (perm_string text);
|
||||
explicit hname_t (perm_string text, int num);
|
||||
explicit hname_t (perm_string text, std::vector<int>&nums);
|
||||
explicit hname_t (perm_string text, const std::vector<int>&nums);
|
||||
hname_t (const hname_t&that);
|
||||
~hname_t();
|
||||
|
||||
|
|
@ -56,12 +56,12 @@ class hname_t {
|
|||
|
||||
size_t has_numbers() const;
|
||||
int peek_number(size_t idx) const;
|
||||
const std::vector<int>&peek_numbers() const;
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
// If the number is anything other than INT_MIN, then this is
|
||||
// the numeric part of the name. Otherwise, it is not part of
|
||||
// the name at all.
|
||||
// If this vector has size, then the numbers all together make
|
||||
// up part of the hierarchical name.
|
||||
std::vector<int> number_;
|
||||
|
||||
private: // not implemented
|
||||
|
|
@ -82,6 +82,11 @@ inline int hname_t::peek_number(size_t idx) const
|
|||
return number_[idx];
|
||||
}
|
||||
|
||||
inline const std::vector<int>& hname_t::peek_numbers(void) const
|
||||
{
|
||||
return number_;
|
||||
}
|
||||
|
||||
inline size_t hname_t::has_numbers() const
|
||||
{
|
||||
return number_.size();
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ CTARGETFLAGS = @CTARGETFLAGS@
|
|||
M = LineInfo.o StringHeap.o
|
||||
|
||||
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-dll-analog.o
|
||||
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
|
||||
FF = cprop.o exposenodes.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 elaborate_analog.o elab_lval.o elab_net.o \
|
||||
|
|
|
|||
15
Module.cc
15
Module.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -32,12 +32,9 @@ Module::Module(LexicalScope*parent, perm_string n)
|
|||
{
|
||||
library_flag = false;
|
||||
is_cell = false;
|
||||
is_interface = false;
|
||||
program_block = false;
|
||||
uc_drive = UCD_NONE;
|
||||
timescale_warn_done = false;
|
||||
time_unit = 0;
|
||||
time_precision = 0;
|
||||
time_from_timescale = false;
|
||||
}
|
||||
|
||||
Module::~Module()
|
||||
|
|
@ -94,13 +91,15 @@ perm_string Module::get_port_name(unsigned idx) const
|
|||
{
|
||||
|
||||
assert(idx < ports.size());
|
||||
if (ports[idx] == 0) {
|
||||
if (ports[idx] == 0 || ports[idx]->name.str() == 0) {
|
||||
/* It is possible to have undeclared ports. These
|
||||
are ports that are skipped in the declaration,
|
||||
for example like so: module foo(x ,, y); The
|
||||
port between x and y is unnamed and thus
|
||||
inaccessible to binding by name. */
|
||||
return perm_string::literal("");
|
||||
inaccessible to binding by name. Port references
|
||||
that aren't simple or escaped identifiers are
|
||||
also inaccessible to binding by name. */
|
||||
return perm_string::literal("unnamed");
|
||||
}
|
||||
return ports[idx]->name;
|
||||
}
|
||||
|
|
|
|||
8
Module.h
8
Module.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_Module_H
|
||||
#define IVL_Module_H
|
||||
/*
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -121,12 +121,6 @@ class Module : public PScopeExtra, public LineInfo {
|
|||
|
||||
map<perm_string,PExpr*> attributes;
|
||||
|
||||
/* These are the timescale for this module. The default is
|
||||
set by the `timescale directive. */
|
||||
int time_unit, time_precision;
|
||||
bool time_from_timescale;
|
||||
bool timescale_warn_done;
|
||||
|
||||
/* The module has a list of generate schemes that appear in
|
||||
the module definition. These are used at elaboration time. */
|
||||
list<PGenerate*> generate_schemes;
|
||||
|
|
|
|||
21
PDelays.cc
21
PDelays.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2017 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
|
||||
|
|
@ -26,11 +26,6 @@
|
|||
# include "verinum.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
bool dly_used_no_timescale = false;
|
||||
bool dly_used_timescale = false;
|
||||
bool display_ts_dly_warning = true;
|
||||
|
||||
|
||||
PDelays::PDelays()
|
||||
{
|
||||
delete_flag_ = true;
|
||||
|
|
@ -80,19 +75,7 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr)
|
|||
{
|
||||
NetExpr*dex = elab_and_eval(des, scope, expr, -1);
|
||||
|
||||
/* Print a warning if we find default and `timescale based
|
||||
* delays in the design, since this is likely an error. */
|
||||
if (scope->time_from_timescale()) dly_used_timescale = true;
|
||||
else dly_used_no_timescale = true;
|
||||
|
||||
if (display_ts_dly_warning &&
|
||||
dly_used_no_timescale && dly_used_timescale) {
|
||||
cerr << "warning: Found both default and "
|
||||
"`timescale based delays. Use" << endl;
|
||||
cerr << " -Wtimescale to find the "
|
||||
"module(s) with no `timescale." << endl;
|
||||
display_ts_dly_warning = false;
|
||||
}
|
||||
check_for_inconsistent_delays(scope);
|
||||
|
||||
/* If the delay expression is a real constant or vector
|
||||
constant, then evaluate it, scale it to the local time
|
||||
|
|
|
|||
4
PExpr.cc
4
PExpr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2012 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com>
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -137,7 +137,7 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
|
|||
return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope);
|
||||
}
|
||||
|
||||
PECastSize::PECastSize(unsigned si, PExpr*b)
|
||||
PECastSize::PECastSize(PExpr*si, PExpr*b)
|
||||
: size_(si), base_(b)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
6
PExpr.h
6
PExpr.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_PExpr_H
|
||||
#define IVL_PExpr_H
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com>
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -971,7 +971,7 @@ class PECallFunction : public PExpr {
|
|||
class PECastSize : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PECastSize(unsigned expr_wid, PExpr*base);
|
||||
explicit PECastSize(PExpr*size, PExpr*base);
|
||||
~PECastSize();
|
||||
|
||||
void dump(ostream &out) const;
|
||||
|
|
@ -984,7 +984,7 @@ class PECastSize : public PExpr {
|
|||
width_mode_t&mode);
|
||||
|
||||
private:
|
||||
unsigned size_;
|
||||
PExpr* size_;
|
||||
PExpr* base_;
|
||||
};
|
||||
|
||||
|
|
|
|||
2
PGate.h
2
PGate.h
|
|
@ -217,6 +217,8 @@ class PGModule : public PGate {
|
|||
// method to pass the range to the pform.
|
||||
void set_range(PExpr*msb, PExpr*lsb);
|
||||
|
||||
map<perm_string,PExpr*> attributes;
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind =4) const;
|
||||
virtual void elaborate(Design*, NetScope*scope) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*sc) const;
|
||||
|
|
|
|||
42
PScope.cc
42
PScope.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008,2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-2017 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
|
||||
|
|
@ -19,21 +19,9 @@
|
|||
|
||||
# include "PScope.h"
|
||||
|
||||
PScope::PScope(perm_string n, LexicalScope*parent)
|
||||
: LexicalScope(parent), name_(n)
|
||||
bool LexicalScope::var_init_needs_explicit_lifetime() const
|
||||
{
|
||||
}
|
||||
|
||||
PScope::PScope(perm_string n)
|
||||
: LexicalScope(0), name_(n)
|
||||
{
|
||||
}
|
||||
|
||||
PScope::~PScope()
|
||||
{
|
||||
for(map<perm_string, data_type_t*>::iterator it = typedefs.begin();
|
||||
it != typedefs.end(); ++it)
|
||||
delete it->second;
|
||||
return false;
|
||||
}
|
||||
|
||||
PWire* LexicalScope::wires_find(perm_string name)
|
||||
|
|
@ -45,17 +33,29 @@ PWire* LexicalScope::wires_find(perm_string name)
|
|||
return (*cur).second;
|
||||
}
|
||||
|
||||
PScope::PScope(perm_string n, LexicalScope*parent)
|
||||
: LexicalScope(parent), name_(n)
|
||||
{
|
||||
time_unit = 0;
|
||||
time_precision = 0;
|
||||
time_unit_is_default = true;
|
||||
time_prec_is_default = true;
|
||||
}
|
||||
|
||||
PScope::~PScope()
|
||||
{
|
||||
for(map<perm_string, data_type_t*>::iterator it = typedefs.begin();
|
||||
it != typedefs.end(); ++it)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent)
|
||||
: PScope(n, parent)
|
||||
{
|
||||
}
|
||||
|
||||
PScopeExtra::PScopeExtra(perm_string n)
|
||||
: PScope(n)
|
||||
{
|
||||
time_unit_is_local = false;
|
||||
time_prec_is_local = false;
|
||||
}
|
||||
|
||||
PScopeExtra::~PScopeExtra()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
43
PScope.h
43
PScope.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_PScope_H
|
||||
#define IVL_PScope_H
|
||||
/*
|
||||
* Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-2017 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
|
||||
|
|
@ -36,6 +36,7 @@ class PProcess;
|
|||
class PClass;
|
||||
class PTask;
|
||||
class PWire;
|
||||
class Statement;
|
||||
|
||||
class Design;
|
||||
class NetScope;
|
||||
|
|
@ -52,10 +53,14 @@ class NetScope;
|
|||
class LexicalScope {
|
||||
|
||||
public:
|
||||
explicit LexicalScope(LexicalScope*parent) : parent_(parent) { }
|
||||
enum lifetime_t { INHERITED, STATIC, AUTOMATIC };
|
||||
|
||||
explicit LexicalScope(LexicalScope*parent) : default_lifetime(INHERITED), parent_(parent) { }
|
||||
// A virtual destructor is so that dynamic_cast can work.
|
||||
virtual ~LexicalScope() { }
|
||||
|
||||
lifetime_t default_lifetime;
|
||||
|
||||
struct range_t {
|
||||
// True if this is an exclude
|
||||
bool exclude_flag;
|
||||
|
|
@ -108,6 +113,9 @@ class LexicalScope {
|
|||
// creating implicit nets.
|
||||
map<perm_string,LineInfo*> genvars;
|
||||
|
||||
// Variable initializations in this scope
|
||||
vector<Statement*> var_inits;
|
||||
|
||||
// Behaviors (processes) in this scope
|
||||
list<PProcess*> behaviors;
|
||||
list<AProcess*> analog_behaviors;
|
||||
|
|
@ -117,6 +125,8 @@ class LexicalScope {
|
|||
|
||||
LexicalScope* parent_scope() const { return parent_; }
|
||||
|
||||
virtual bool var_init_needs_explicit_lifetime() const;
|
||||
|
||||
protected:
|
||||
void dump_typedefs_(ostream&out, unsigned indent) const;
|
||||
|
||||
|
|
@ -130,6 +140,10 @@ class LexicalScope {
|
|||
|
||||
void dump_wires_(ostream&out, unsigned indent) const;
|
||||
|
||||
void dump_var_inits_(ostream&out, unsigned indent) const;
|
||||
|
||||
bool elaborate_var_inits_(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
LexicalScope*parent_;
|
||||
};
|
||||
|
|
@ -145,12 +159,24 @@ class PScope : public LexicalScope {
|
|||
// modules do not nest in Verilog, the parent must be nil for
|
||||
// modules. Scopes for tasks and functions point to their
|
||||
// containing module.
|
||||
PScope(perm_string name, LexicalScope*parent);
|
||||
PScope(perm_string name);
|
||||
explicit PScope(perm_string name, LexicalScope*parent =0);
|
||||
virtual ~PScope();
|
||||
|
||||
perm_string pscope_name() const { return name_; }
|
||||
|
||||
/* These are the timescale for this scope. The value is
|
||||
set by the `timescale directive or, in SystemVerilog,
|
||||
by timeunit and timeprecision statements. */
|
||||
int time_unit, time_precision;
|
||||
|
||||
/* Flags used to support warnings about timescales. */
|
||||
bool time_unit_is_default;
|
||||
bool time_prec_is_default;
|
||||
|
||||
bool has_explicit_timescale() const {
|
||||
return !(time_unit_is_default || time_prec_is_default);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool elaborate_sig_wires_(Design*des, NetScope*scope) const;
|
||||
|
||||
|
|
@ -168,19 +194,22 @@ class PScope : public LexicalScope {
|
|||
class PScopeExtra : public PScope {
|
||||
|
||||
public:
|
||||
PScopeExtra(perm_string, LexicalScope*parent);
|
||||
PScopeExtra(perm_string);
|
||||
explicit PScopeExtra(perm_string, LexicalScope*parent =0);
|
||||
~PScopeExtra();
|
||||
|
||||
/* Task definitions within this module */
|
||||
std::map<perm_string,PTask*> tasks;
|
||||
std::map<perm_string,PFunction*> funcs;
|
||||
/* class definitions within this module. */
|
||||
/* Class definitions within this module. */
|
||||
std::map<perm_string,PClass*> classes;
|
||||
/* This is the lexical order of the classes, and is used by
|
||||
elaboration to choose an elaboration order. */
|
||||
std::vector<PClass*> classes_lexical;
|
||||
|
||||
/* Flags used to support warnings about timescales. */
|
||||
bool time_unit_is_local;
|
||||
bool time_prec_is_local;
|
||||
|
||||
protected:
|
||||
void dump_classes_(ostream&out, unsigned indent) const;
|
||||
void dump_tasks_(ostream&out, unsigned indent) const;
|
||||
|
|
|
|||
7
PTask.cc
7
PTask.cc
|
|
@ -30,6 +30,11 @@ PTaskFunc::~PTaskFunc()
|
|||
{
|
||||
}
|
||||
|
||||
bool PTaskFunc::var_init_needs_explicit_lifetime() const
|
||||
{
|
||||
return default_lifetime == STATIC;
|
||||
}
|
||||
|
||||
void PTaskFunc::set_ports(vector<pform_tf_port_t>*p)
|
||||
{
|
||||
assert(ports_ == 0);
|
||||
|
|
@ -41,7 +46,7 @@ void PTaskFunc::set_this(class_type_t*type, PWire*this_wire)
|
|||
assert(this_type_ == 0);
|
||||
this_type_ = type;
|
||||
|
||||
// Push a synthethis argument that is the "this" value.
|
||||
// Push a synthesis argument that is the "this" value.
|
||||
if (ports_==0)
|
||||
ports_ = new vector<pform_tf_port_t>;
|
||||
|
||||
|
|
|
|||
2
PTask.h
2
PTask.h
|
|
@ -41,6 +41,8 @@ class PTaskFunc : public PScope, public LineInfo {
|
|||
PTaskFunc(perm_string name, LexicalScope*parent);
|
||||
~PTaskFunc();
|
||||
|
||||
bool var_init_needs_explicit_lifetime() const;
|
||||
|
||||
void set_ports(std::vector<pform_tf_port_t>*p);
|
||||
|
||||
void set_this(class_type_t*use_type, PWire*this_wire);
|
||||
|
|
|
|||
|
|
@ -77,10 +77,16 @@ the configure scripts.
|
|||
Unpack the tar-ball and cd into the verilog-######### directory
|
||||
(presumably that is how you got to this README) and compile the source
|
||||
with the commands:
|
||||
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
If you are building from git, you have to run the command below before
|
||||
compile the source. This will generate the "configure" file, which is
|
||||
automatically done when building from tarball.
|
||||
|
||||
sh autoconf.sh
|
||||
|
||||
Normally, this command automatically figures out everything it needs
|
||||
to know. It generally works pretty well. There are a few flags to the
|
||||
configure script that modify its behavior:
|
||||
|
|
|
|||
15
Statement.cc
15
Statement.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -115,6 +115,11 @@ PBlock::~PBlock()
|
|||
delete list_[idx];
|
||||
}
|
||||
|
||||
bool PBlock::var_init_needs_explicit_lifetime() const
|
||||
{
|
||||
return default_lifetime == STATIC;
|
||||
}
|
||||
|
||||
PChainConstructor* PBlock::extract_chain_constructor()
|
||||
{
|
||||
if (list_.empty())
|
||||
|
|
@ -289,20 +294,20 @@ PDoWhile::~PDoWhile()
|
|||
}
|
||||
|
||||
PEventStatement::PEventStatement(const svector<PEEvent*>&ee)
|
||||
: expr_(ee), statement_(0)
|
||||
: expr_(ee), statement_(0), search_funcs_(false)
|
||||
{
|
||||
assert(expr_.count() > 0);
|
||||
}
|
||||
|
||||
|
||||
PEventStatement::PEventStatement(PEEvent*ee)
|
||||
: expr_(1), statement_(0)
|
||||
: expr_(1), statement_(0), search_funcs_(false)
|
||||
{
|
||||
expr_[0] = ee;
|
||||
}
|
||||
|
||||
PEventStatement::PEventStatement(void)
|
||||
: statement_(0)
|
||||
PEventStatement::PEventStatement(bool search_funcs)
|
||||
: statement_(0), search_funcs_(search_funcs)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
15
Statement.h
15
Statement.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_Statement_H
|
||||
#define IVL_Statement_H
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -108,7 +108,8 @@ class PAssign_ : public Statement {
|
|||
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
|
||||
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_type,
|
||||
ivl_variable_type_t lv_type,
|
||||
unsigned lv_width) const;
|
||||
unsigned lv_width,
|
||||
bool force_unsigned =false) const;
|
||||
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const;
|
||||
|
||||
NetExpr* elaborate_rval_obj_(Design*, NetScope*,
|
||||
|
|
@ -182,6 +183,8 @@ class PBlock : public PScope, public Statement {
|
|||
|
||||
BL_TYPE bl_type() const { return bl_type_; }
|
||||
|
||||
bool var_init_needs_explicit_lifetime() const;
|
||||
|
||||
// This is only used if this block is the statement list for a
|
||||
// constructor. We look for a PChainConstructor as the first
|
||||
// statement, and if it is there, extract it.
|
||||
|
|
@ -289,7 +292,7 @@ class PCAssign : public Statement {
|
|||
*/
|
||||
class PChainConstructor : public Statement {
|
||||
public:
|
||||
PChainConstructor(const list<PExpr*>&parms);
|
||||
explicit PChainConstructor(const list<PExpr*>&parms);
|
||||
~PChainConstructor();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
|
|
@ -399,8 +402,9 @@ class PEventStatement : public Statement {
|
|||
|
||||
explicit PEventStatement(const svector<PEEvent*>&ee);
|
||||
explicit PEventStatement(PEEvent*ee);
|
||||
// Make an @* statement.
|
||||
explicit PEventStatement(void);
|
||||
// Make an @* statement or make a special @* version with the items
|
||||
// from functions added and ouputs removed for always_comb/latch.
|
||||
explicit PEventStatement(bool search_funcs = false);
|
||||
|
||||
~PEventStatement();
|
||||
|
||||
|
|
@ -426,6 +430,7 @@ class PEventStatement : public Statement {
|
|||
private:
|
||||
svector<PEEvent*>expr_;
|
||||
Statement*statement_;
|
||||
bool search_funcs_;
|
||||
};
|
||||
|
||||
ostream& operator << (ostream&o, const PEventStatement&obj);
|
||||
|
|
|
|||
|
|
@ -223,8 +223,9 @@ AC_SUBST(strip_dynamic)
|
|||
# -------------
|
||||
AC_DEFUN([AX_C99_STRTOD],
|
||||
[# On MinGW we need to jump through hoops to get a C99 compliant strtod().
|
||||
# mingw-w64 doesn't need this, and the 64-bit version doesn't support it.
|
||||
case "${host}" in
|
||||
*-*-mingw*)
|
||||
*-pc-mingw32)
|
||||
LDFLAGS+=" -Wl,--undefined=___strtod,--wrap,strtod,--defsym,___wrap_strtod=___strtod"
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
44
compiler.h
44
compiler.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_compiler_H
|
||||
#define IVL_compiler_H
|
||||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2017 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
|
||||
|
|
@ -80,6 +80,10 @@ extern unsigned recursive_mod_limit;
|
|||
/* Implicit definitions of wires. */
|
||||
extern bool warn_implicit;
|
||||
|
||||
/* Warn if dimensions of port or var/net are implicitly taken from
|
||||
the input/output/inout declaration. */
|
||||
extern bool warn_implicit_dimensions;
|
||||
|
||||
/* inherit timescales across files. */
|
||||
extern bool warn_timescale;
|
||||
|
||||
|
|
@ -100,6 +104,9 @@ extern bool warn_sens_entire_arr;
|
|||
/* Warn about level-appropriate anachronisms. */
|
||||
extern bool warn_anachronisms;
|
||||
|
||||
/* Warn about nets that are references but not driven. */
|
||||
extern bool warn_floating_nets;
|
||||
|
||||
/* This is true if verbose output is requested. */
|
||||
extern bool verbose_flag;
|
||||
|
||||
|
|
@ -110,6 +117,13 @@ extern bool debug_emit;
|
|||
extern bool debug_synth2;
|
||||
extern bool debug_optimizer;
|
||||
|
||||
/* Ignore errors about missing modules */
|
||||
extern bool ignore_missing_modules;
|
||||
|
||||
/* Treat each source file as a separate compilation unit (as defined
|
||||
by SystemVerilog). */
|
||||
extern bool separate_compilation;
|
||||
|
||||
/* Control evaluation of functions at compile time:
|
||||
* 0 = only for functions in constant expressions
|
||||
* 1 = only for automatic functions
|
||||
|
|
@ -138,7 +152,8 @@ extern int build_library_index(const char*path, bool key_case_sensitive);
|
|||
|
||||
/* This is the generation of Verilog that the compiler is asked to
|
||||
support. Then there are also more detailed controls for more
|
||||
specific language features. */
|
||||
specific language features. Note that the compiler often assumes
|
||||
this is an ordered list. */
|
||||
enum generation_t {
|
||||
GN_VER1995 = 1,
|
||||
GN_VER2001_NOCONFIG = 2,
|
||||
|
|
@ -182,25 +197,24 @@ extern bool gn_strict_ca_eval_flag;
|
|||
standard expression width rules. */
|
||||
extern bool gn_strict_expr_width_flag;
|
||||
|
||||
/* If variables can be converted to uwires by a continuous assignment
|
||||
(assuming no procedural assign, then return true. This will be true
|
||||
for SystemVerilog */
|
||||
static inline bool gn_var_can_be_uwire(void)
|
||||
/* If this flag is true, then don't add a for-loop control variable
|
||||
to an implicit event_expression list if it is only used inside the
|
||||
loop. */
|
||||
extern bool gn_shared_loop_index_flag;
|
||||
|
||||
static inline bool gn_system_verilog(void)
|
||||
{
|
||||
if (generation_flag == GN_VER2005_SV ||
|
||||
generation_flag == GN_VER2009 ||
|
||||
generation_flag == GN_VER2012)
|
||||
if (generation_flag >= GN_VER2005_SV)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool gn_system_verilog(void)
|
||||
/* If variables can be converted to uwires by a continuous assignment
|
||||
(assuming no procedural assign), then return true. This will be true
|
||||
for SystemVerilog */
|
||||
static inline bool gn_var_can_be_uwire(void)
|
||||
{
|
||||
if (generation_flag == GN_VER2005_SV ||
|
||||
generation_flag == GN_VER2009 ||
|
||||
generation_flag == GN_VER2012)
|
||||
return true;
|
||||
return false;
|
||||
return gn_system_verilog();
|
||||
}
|
||||
|
||||
static inline bool gn_modules_nest(void)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_config_H /* -*- c++ -*- */
|
||||
#define IVL_config_H
|
||||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2015 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
|
||||
|
|
@ -55,6 +55,7 @@
|
|||
# undef HAVE_FSEEKO
|
||||
/* And this is needed by the fst files (copied from GTKWave). */
|
||||
# undef HAVE_LIBPTHREAD
|
||||
# undef HAVE_REALPATH
|
||||
|
||||
/*
|
||||
* Define this if you want to compile vvp with memory freeing and
|
||||
|
|
|
|||
|
|
@ -223,6 +223,10 @@ case "${host}" in
|
|||
CPPFLAGS="-mieee $CPPFLAGS"
|
||||
CFLAGS="-mieee $CFLAGS"
|
||||
;;
|
||||
*-*-mingw*)
|
||||
CXXFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $CXXFLAGS"
|
||||
CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $CFLAGS"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Do some more operating system specific setup. We put the file64_support
|
||||
|
|
@ -238,6 +242,9 @@ case "${host}" in
|
|||
esac
|
||||
AC_SUBST(file64_support)
|
||||
|
||||
# fstapi.c (from GTKWave) needs this define.
|
||||
AC_CHECK_FUNCS(realpath)
|
||||
|
||||
# Check that these functions exist. They are mostly C99
|
||||
# functions that older compilers may not yet support.
|
||||
AC_CHECK_FUNCS(fopen64)
|
||||
|
|
|
|||
620
cppcheck.sup
620
cppcheck.sup
|
|
@ -1,3 +1,619 @@
|
|||
// These are correct and are used to find the base (zero) pin.
|
||||
thisSubtraction:netlist.h:4976
|
||||
thisSubtraction:netlist.h:4985
|
||||
thisSubtraction:netlist.h:5082
|
||||
thisSubtraction:netlist.h:5091
|
||||
|
||||
// These are the functions that the compiler exports to the targets.
|
||||
//ivl_branch_island()
|
||||
unusedFunction:t-dll-api.cc:39
|
||||
//ivl_branch_terminal()
|
||||
unusedFunction:t-dll-api.cc:45
|
||||
|
||||
//ivl_const_bits()
|
||||
unusedFunction:t-dll-api.cc:196
|
||||
//ivl_const_delay()
|
||||
unusedFunction:t-dll-api.cc:214
|
||||
//ivl_const_file()
|
||||
unusedFunction:t-dll-api.cc:221
|
||||
//ivl_const_lineno()
|
||||
unusedFunction:t-dll-api.cc:227
|
||||
//ivl_const_nex()
|
||||
unusedFunction:t-dll-api.cc:233
|
||||
//ivl_const_real()
|
||||
unusedFunction:t-dll-api.cc:239
|
||||
//ivl_const_scope()
|
||||
unusedFunction:t-dll-api.cc:246
|
||||
//ivl_const_signed()
|
||||
unusedFunction:t-dll-api.cc:252
|
||||
//ivl_const_type()
|
||||
unusedFunction:t-dll-api.cc:190
|
||||
//ivl_const_width()
|
||||
unusedFunction:t-dll-api.cc:258
|
||||
|
||||
//ivl_design_const()
|
||||
unusedFunction:t-dll-api.cc:127
|
||||
//ivl_design_consts()
|
||||
unusedFunction:t-dll-api.cc:121
|
||||
//ivl_design_delay_sel()
|
||||
unusedFunction:t-dll-api.cc:52
|
||||
//ivl_design_discipline()
|
||||
unusedFunction:t-dll-api.cc:140
|
||||
//ivl_design_disciplines()
|
||||
unusedFunction:t-dll-api.cc:134
|
||||
//ivl_design_flag()
|
||||
unusedFunction:t-dll-api.cc:59
|
||||
//ivl_design_process()
|
||||
unusedFunction:t-dll-api.cc:66
|
||||
//ivl_design_root()
|
||||
unusedFunction:t-dll-api.cc:80
|
||||
//ivl_design_roots()
|
||||
unusedFunction:t-dll-api.cc:89
|
||||
//ivl_design_time_precision()
|
||||
unusedFunction:t-dll-api.cc:115
|
||||
|
||||
//ivl_discipline_domain()
|
||||
unusedFunction:t-dll-api.cc:147
|
||||
//ivl_discipline_flow()
|
||||
unusedFunction:t-dll-api.cc:153
|
||||
//ivl_discipline_name()
|
||||
unusedFunction:t-dll-api.cc:159
|
||||
//ivl_discipline_potential()
|
||||
unusedFunction:t-dll-api.cc:165
|
||||
|
||||
//ivl_enum_bits()
|
||||
unusedFunction:t-dll-api.cc:277
|
||||
//ivl_enum_file()
|
||||
unusedFunction:t-dll-api.cc:302
|
||||
//ivl_enum_lineno()
|
||||
unusedFunction:t-dll-api.cc:308
|
||||
//ivl_enum_name()
|
||||
unusedFunction:t-dll-api.cc:270
|
||||
//ivl_enum_names()
|
||||
unusedFunction:t-dll-api.cc:264
|
||||
//ivl_enum_signed()
|
||||
unusedFunction:t-dll-api.cc:296
|
||||
//ivl_enum_type()
|
||||
unusedFunction:t-dll-api.cc:284
|
||||
//ivl_enum_width()
|
||||
unusedFunction:t-dll-api.cc:290
|
||||
|
||||
//ivl_event_any()
|
||||
unusedFunction:t-dll-api.cc:369
|
||||
//ivl_event_file()
|
||||
unusedFunction:t-dll-api.cc:345
|
||||
//ivl_event_lineno()
|
||||
unusedFunction:t-dll-api.cc:351
|
||||
//ivl_event_name()
|
||||
unusedFunction:t-dll-api.cc:314
|
||||
//ivl_event_nany()
|
||||
unusedFunction:t-dll-api.cc:363
|
||||
//ivl_event_neg()
|
||||
unusedFunction:t-dll-api.cc:382
|
||||
//ivl_event_nneg()
|
||||
unusedFunction:t-dll-api.cc:376
|
||||
//ivl_event_npos()
|
||||
unusedFunction:t-dll-api.cc:389
|
||||
//ivl_event_pos()
|
||||
unusedFunction:t-dll-api.cc:395
|
||||
//ivl_event_scope()
|
||||
unusedFunction:t-dll-api.cc:357
|
||||
|
||||
//ivl_expr_bits()
|
||||
unusedFunction:t-dll-api.cc:402
|
||||
//ivl_expr_branch()
|
||||
unusedFunction:t-dll-api.cc:409
|
||||
//ivl_expr_def()
|
||||
unusedFunction:t-dll-api.cc:416
|
||||
//ivl_expr_delay_val()
|
||||
unusedFunction:t-dll-api.cc:432
|
||||
//ivl_expr_dvalue()
|
||||
unusedFunction:t-dll-api.cc:439
|
||||
//ivl_expr_enumtype()
|
||||
unusedFunction:t-dll-api.cc:446
|
||||
//ivl_expr_event()
|
||||
unusedFunction:t-dll-api.cc:656
|
||||
//ivl_expr_file()
|
||||
unusedFunction:t-dll-api.cc:178
|
||||
//ivl_expr_lineno()
|
||||
unusedFunction:t-dll-api.cc:184
|
||||
//ivl_expr_name()
|
||||
unusedFunction:t-dll-api.cc:459
|
||||
//ivl_expr_nature()
|
||||
unusedFunction:t-dll-api.cc:483
|
||||
//ivl_expr_net_type()
|
||||
unusedFunction:t-dll-api.cc:453
|
||||
//ivl_expr_opcode()
|
||||
unusedFunction:t-dll-api.cc:490
|
||||
//ivl_expr_oper1()
|
||||
unusedFunction:t-dll-api.cc:506
|
||||
//ivl_expr_oper2()
|
||||
unusedFunction:t-dll-api.cc:544
|
||||
//ivl_expr_oper3()
|
||||
unusedFunction:t-dll-api.cc:570
|
||||
//ivl_expr_parameter()
|
||||
unusedFunction:t-dll-api.cc:584
|
||||
//ivl_expr_parm()
|
||||
unusedFunction:t-dll-api.cc:599
|
||||
//ivl_expr_parms()
|
||||
unusedFunction:t-dll-api.cc:626
|
||||
//ivl_expr_repeat()
|
||||
unusedFunction:t-dll-api.cc:649
|
||||
//ivl_expr_scope()
|
||||
unusedFunction:t-dll-api.cc:670
|
||||
//ivl_expr_sel_type()
|
||||
unusedFunction:t-dll-api.cc:677
|
||||
//ivl_expr_signed()
|
||||
unusedFunction:t-dll-api.cc:702
|
||||
//ivl_expr_sized()
|
||||
unusedFunction:t-dll-api.cc:708
|
||||
//ivl_expr_string()
|
||||
unusedFunction:t-dll-api.cc:714
|
||||
//ivl_expr_type()
|
||||
unusedFunction:t-dll-api.cc:171
|
||||
//ivl_expr_uvalue()
|
||||
unusedFunction:t-dll-api.cc:721
|
||||
//ivl_expr_value()
|
||||
unusedFunction:t-dll-api.cc:747
|
||||
//ivl_expr_width()
|
||||
unusedFunction:t-dll-api.cc:753
|
||||
|
||||
//ivl_file_table_index()
|
||||
unusedFunction:t-dll-api.cc:795
|
||||
//ivl_file_table_item()
|
||||
unusedFunction:t-dll-api.cc:785
|
||||
//ivl_file_table_size()
|
||||
unusedFunction:t-dll-api.cc:813
|
||||
|
||||
//ivl_island_flag_set()
|
||||
unusedFunction:t-dll-api.cc:822
|
||||
//ivl_island_flag_test()
|
||||
unusedFunction:t-dll-api.cc:837
|
||||
|
||||
//ivl_logic_attr()
|
||||
unusedFunction:t-dll-api.cc:864
|
||||
//ivl_logic_attr_cnt()
|
||||
unusedFunction:t-dll-api.cc:880
|
||||
//ivl_logic_attr_val()
|
||||
unusedFunction:t-dll-api.cc:886
|
||||
//ivl_logic_basename()
|
||||
unusedFunction:t-dll-api.cc:935
|
||||
//ivl_logic_delay()
|
||||
unusedFunction:t-dll-api.cc:974
|
||||
//ivl_logic_drive0()
|
||||
unusedFunction:t-dll-api.cc:894
|
||||
//ivl_logic_drive1()
|
||||
unusedFunction:t-dll-api.cc:911
|
||||
//ivl_logic_file()
|
||||
unusedFunction:t-dll-api.cc:846
|
||||
//ivl_logic_is_cassign()
|
||||
unusedFunction:t-dll-api.cc:858
|
||||
//ivl_logic_lineno()
|
||||
unusedFunction:t-dll-api.cc:852
|
||||
//ivl_logic_name()
|
||||
unusedFunction:t-dll-api.cc:928
|
||||
//ivl_logic_pins()
|
||||
unusedFunction:t-dll-api.cc:953
|
||||
//ivl_logic_scope()
|
||||
unusedFunction:t-dll-api.cc:941
|
||||
//ivl_logic_type()
|
||||
unusedFunction:t-dll-api.cc:947
|
||||
//ivl_logic_udp()
|
||||
unusedFunction:t-dll-api.cc:966
|
||||
//ivl_logic_width()
|
||||
unusedFunction:t-dll-api.cc:981
|
||||
|
||||
//ivl_lpm_array()
|
||||
unusedFunction:t-dll-api.cc:1109
|
||||
//ivl_lpm_aset_value()
|
||||
unusedFunction:t-dll-api.cc:1160
|
||||
//ivl_lpm_async_clr()
|
||||
unusedFunction:t-dll-api.cc:1054
|
||||
//ivl_lpm_async_set()
|
||||
unusedFunction:t-dll-api.cc:1085
|
||||
//ivl_lpm_base()
|
||||
unusedFunction:t-dll-api.cc:1121
|
||||
//ivl_lpm_basename()
|
||||
unusedFunction:t-dll-api.cc:1048
|
||||
//ivl_lpm_clk()
|
||||
unusedFunction:t-dll-api.cc:1148
|
||||
//ivl_lpm_data()
|
||||
unusedFunction:t-dll-api.cc:1221
|
||||
//ivl_lpm_datab()
|
||||
unusedFunction:t-dll-api.cc:1321
|
||||
//ivl_lpm_define()
|
||||
unusedFunction:t-dll-api.cc:1183
|
||||
//ivl_lpm_delay()
|
||||
unusedFunction:t-dll-api.cc:1078
|
||||
//ivl_lpm_drive0()
|
||||
unusedFunction:t-dll-api.cc:1453
|
||||
//ivl_lpm_drive1()
|
||||
unusedFunction:t-dll-api.cc:1470
|
||||
//ivl_lpm_enable()
|
||||
unusedFunction:t-dll-api.cc:1195
|
||||
//ivl_lpm_file()
|
||||
unusedFunction:t-dll-api.cc:1209
|
||||
//ivl_lpm_lineno()
|
||||
unusedFunction:t-dll-api.cc:1215
|
||||
//ivl_lpm_name()
|
||||
unusedFunction:t-dll-api.cc:1355
|
||||
//ivl_lpm_negedge()
|
||||
unusedFunction:t-dll-api.cc:1136
|
||||
//ivl_lpm_select()
|
||||
unusedFunction:t-dll-api.cc:1493
|
||||
//ivl_lpm_selects()
|
||||
unusedFunction:t-dll-api.cc:1510
|
||||
//ivl_lpm_signed()
|
||||
unusedFunction:t-dll-api.cc:1528
|
||||
//ivl_lpm_size()
|
||||
unusedFunction:t-dll-api.cc:1587
|
||||
//ivl_lpm_sset_value()
|
||||
unusedFunction:t-dll-api.cc:1171
|
||||
//ivl_lpm_string()
|
||||
unusedFunction:t-dll-api.cc:1640
|
||||
//ivl_lpm_sync_clr()
|
||||
unusedFunction:t-dll-api.cc:1066
|
||||
//ivl_lpm_sync_set()
|
||||
unusedFunction:t-dll-api.cc:1097
|
||||
//ivl_lpm_trigger()
|
||||
unusedFunction:t-dll-api.cc:1659
|
||||
//ivl_lpm_type()
|
||||
unusedFunction:t-dll-api.cc:1647
|
||||
//ivl_lpm_width()
|
||||
unusedFunction:t-dll-api.cc:1653
|
||||
|
||||
//ivl_lval_idx()
|
||||
unusedFunction:t-dll-api.cc:1681
|
||||
//ivl_lval_mux()
|
||||
unusedFunction:t-dll-api.cc:1676
|
||||
//ivl_lval_nest()
|
||||
unusedFunction:t-dll-api.cc:1726
|
||||
//ivl_lval_part_off()
|
||||
unusedFunction:t-dll-api.cc:1690
|
||||
//ivl_lval_property_idx()
|
||||
unusedFunction:t-dll-api.cc:1708
|
||||
//ivl_lval_sel_type()
|
||||
unusedFunction:t-dll-api.cc:1696
|
||||
//ivl_lval_sig()
|
||||
unusedFunction:t-dll-api.cc:1714
|
||||
|
||||
//ivl_nature_name()
|
||||
unusedFunction:t-dll-api.cc:1735
|
||||
|
||||
//ivl_nexus_get_private()
|
||||
unusedFunction:t-dll-api.cc:1756
|
||||
//ivl_nexus_name()
|
||||
unusedFunction:t-dll-api.cc:1745
|
||||
//ivl_nexus_ptr_branch()
|
||||
unusedFunction:t-dll-api.cc:1799
|
||||
//ivl_nexus_ptr_con()
|
||||
unusedFunction:t-dll-api.cc:1808
|
||||
//ivl_nexus_ptr_sig()
|
||||
unusedFunction:t-dll-api.cc:1835
|
||||
//ivl_nexus_ptr_switch()
|
||||
unusedFunction:t-dll-api.cc:1844
|
||||
//ivl_nexus_set_private()
|
||||
unusedFunction:t-dll-api.cc:1762
|
||||
|
||||
//ivl_parameter_basename()
|
||||
unusedFunction:t-dll-api.cc:1853
|
||||
//ivl_parameter_expr()
|
||||
unusedFunction:t-dll-api.cc:1896
|
||||
//ivl_parameter_file()
|
||||
unusedFunction:t-dll-api.cc:1902
|
||||
//ivl_parameter_lineno()
|
||||
unusedFunction:t-dll-api.cc:1908
|
||||
//ivl_parameter_local()
|
||||
unusedFunction:t-dll-api.cc:1859
|
||||
//ivl_parameter_lsb()
|
||||
unusedFunction:t-dll-api.cc:1877
|
||||
//ivl_parameter_msb()
|
||||
unusedFunction:t-dll-api.cc:1871
|
||||
//ivl_parameter_scope()
|
||||
unusedFunction:t-dll-api.cc:1914
|
||||
//ivl_parameter_signed()
|
||||
unusedFunction:t-dll-api.cc:1865
|
||||
//ivl_parameter_width()
|
||||
unusedFunction:t-dll-api.cc:1887
|
||||
|
||||
//ivl_path_condit()
|
||||
unusedFunction:t-dll-api.cc:1920
|
||||
//ivl_path_delay()
|
||||
unusedFunction:t-dll-api.cc:1932
|
||||
//ivl_path_is_condit()
|
||||
unusedFunction:t-dll-api.cc:1926
|
||||
//ivl_path_scope()
|
||||
unusedFunction:t-dll-api.cc:1938
|
||||
//ivl_path_source()
|
||||
unusedFunction:t-dll-api.cc:1945
|
||||
//ivl_path_source_negedge()
|
||||
unusedFunction:t-dll-api.cc:1957
|
||||
//ivl_path_source_posedge()
|
||||
unusedFunction:t-dll-api.cc:1951
|
||||
|
||||
//ivl_process_analog()
|
||||
unusedFunction:t-dll-api.cc:1981
|
||||
//ivl_process_attr_cnt()
|
||||
unusedFunction:t-dll-api.cc:1999
|
||||
//ivl_process_attr_val()
|
||||
unusedFunction:t-dll-api.cc:2005
|
||||
//ivl_process_file()
|
||||
unusedFunction:t-dll-api.cc:1963
|
||||
//ivl_process_lineno()
|
||||
unusedFunction:t-dll-api.cc:1969
|
||||
//ivl_process_scope()
|
||||
unusedFunction:t-dll-api.cc:1987
|
||||
//ivl_process_stmt()
|
||||
unusedFunction:t-dll-api.cc:1993
|
||||
//ivl_process_type()
|
||||
unusedFunction:t-dll-api.cc:1975
|
||||
|
||||
//ivl_scope_attr_cnt()
|
||||
unusedFunction:t-dll-api.cc:2013
|
||||
//ivl_scope_attr_val()
|
||||
unusedFunction:t-dll-api.cc:2019
|
||||
//ivl_scope_basename()
|
||||
unusedFunction:t-dll-api.cc:2027
|
||||
//ivl_scope_child()
|
||||
unusedFunction:t-dll-api.cc:2054
|
||||
//ivl_scope_children()
|
||||
unusedFunction:t-dll-api.cc:2033
|
||||
//ivl_scope_childs()
|
||||
unusedFunction:t-dll-api.cc:2047
|
||||
//ivl_scope_class()
|
||||
unusedFunction:t-dll-api.cc:2061
|
||||
//ivl_scope_classes()
|
||||
unusedFunction:t-dll-api.cc:2068
|
||||
//ivl_scope_def()
|
||||
unusedFunction:t-dll-api.cc:2075
|
||||
//ivl_scope_def_file()
|
||||
unusedFunction:t-dll-api.cc:2081
|
||||
//ivl_scope_def_lineno()
|
||||
unusedFunction:t-dll-api.cc:2087
|
||||
//ivl_scope_enumerate()
|
||||
unusedFunction:t-dll-api.cc:2099
|
||||
//ivl_scope_enumerates()
|
||||
unusedFunction:t-dll-api.cc:2093
|
||||
//ivl_scope_event()
|
||||
unusedFunction:t-dll-api.cc:2112
|
||||
//ivl_scope_events()
|
||||
unusedFunction:t-dll-api.cc:2106
|
||||
//ivl_scope_file()
|
||||
unusedFunction:t-dll-api.cc:2119
|
||||
//ivl_scope_func_signed
|
||||
unusedFunction:t-dll-api.cc:2132
|
||||
//ivl_scope_func_type
|
||||
unusedFunction:t-dll-api.cc:2125
|
||||
//ivl_scope_func_width
|
||||
unusedFunction:t-dll-api.cc:2140
|
||||
//ivl_scope_is_auto()
|
||||
unusedFunction:t-dll-api.cc:2148
|
||||
//ivl_scope_is_cell()
|
||||
unusedFunction:t-dll-api.cc:2154
|
||||
//ivl_scope_lineno()
|
||||
unusedFunction:t-dll-api.cc:2160
|
||||
//ivl_scope_log()
|
||||
unusedFunction:t-dll-api.cc:2172
|
||||
//ivl_scope_logs()
|
||||
unusedFunction:t-dll-api.cc:2166
|
||||
//ivl_scope_lpm()
|
||||
unusedFunction:t-dll-api.cc:2185
|
||||
//ivl_scope_lpms()
|
||||
unusedFunction:t-dll-api.cc:2179
|
||||
//ivl_scope_mod_module_port_name()
|
||||
unusedFunction:t-dll-api.cc:2264
|
||||
//ivl_scope_mod_module_port_type()
|
||||
unusedFunction:t-dll-api.cc:2273
|
||||
//ivl_scope_mod_module_port_width()
|
||||
unusedFunction:t-dll-api.cc:2285
|
||||
//ivl_scope_mod_module_ports()
|
||||
unusedFunction:t-dll-api.cc:2257
|
||||
//ivl_scope_mod_port()
|
||||
unusedFunction:t-dll-api.cc:2310
|
||||
//ivl_scope_param()
|
||||
unusedFunction:t-dll-api.cc:2243
|
||||
//ivl_scope_params()
|
||||
unusedFunction:t-dll-api.cc:2237
|
||||
//ivl_scope_parent()
|
||||
unusedFunction:t-dll-api.cc:2250
|
||||
//ivl_scope_port()
|
||||
unusedFunction:t-dll-api.cc:2301
|
||||
//ivl_scope_ports()
|
||||
unusedFunction:t-dll-api.cc:2292
|
||||
//ivl_scope_sig()
|
||||
unusedFunction:t-dll-api.cc:2324
|
||||
//ivl_scope_sigs()
|
||||
unusedFunction:t-dll-api.cc:2318
|
||||
//ivl_scope_switch()
|
||||
unusedFunction:t-dll-api.cc:2337
|
||||
//ivl_scope_switches()
|
||||
unusedFunction:t-dll-api.cc:2331
|
||||
//ivl_scope_time_precision()
|
||||
unusedFunction:t-dll-api.cc:2344
|
||||
//ivl_scope_time_units()
|
||||
unusedFunction:t-dll-api.cc:2350
|
||||
//ivl_scope_tname()
|
||||
unusedFunction:t-dll-api.cc:2362
|
||||
//ivl_scope_type()
|
||||
unusedFunction:t-dll-api.cc:2356
|
||||
|
||||
//ivl_signal_array_addr_swapped()
|
||||
unusedFunction:t-dll-api.cc:2380
|
||||
//ivl_signal_array_base()
|
||||
unusedFunction:t-dll-api.cc:2368
|
||||
//ivl_signal_array_count()
|
||||
unusedFunction:t-dll-api.cc:2374
|
||||
//ivl_signal_attr()
|
||||
unusedFunction:t-dll-api.cc:2398
|
||||
//ivl_signal_attr_cnt()
|
||||
unusedFunction:t-dll-api.cc:2414
|
||||
//ivl_signal_attr_val()
|
||||
unusedFunction:t-dll-api.cc:2420
|
||||
//ivl_signal_basename()
|
||||
unusedFunction:t-dll-api.cc:2427
|
||||
//ivl_signal_data_type()
|
||||
unusedFunction:t-dll-api.cc:2578
|
||||
//ivl_signal_dimensions()
|
||||
unusedFunction:t-dll-api.cc:2386
|
||||
//ivl_signal_discipline()
|
||||
unusedFunction:t-dll-api.cc:2392
|
||||
//ivl_signal_file()
|
||||
unusedFunction:t-dll-api.cc:2555
|
||||
//ivl_signal_forced_net()
|
||||
unusedFunction:t-dll-api.cc:2549
|
||||
//ivl_signal_integer()
|
||||
unusedFunction:t-dll-api.cc:2567
|
||||
//ivl_signal_lineno()
|
||||
unusedFunction:t-dll-api.cc:2561
|
||||
//ivl_signal_local()
|
||||
unusedFunction:t-dll-api.cc:2536
|
||||
//ivl_signal_lsb()
|
||||
unusedFunction:t-dll-api.cc:2501
|
||||
//ivl_signal_module_port_index()
|
||||
unusedFunction:t-dll-api.cc:2530
|
||||
//ivl_signal_msb()
|
||||
unusedFunction:t-dll-api.cc:2491
|
||||
//ivl_signal_name()
|
||||
unusedFunction:t-dll-api.cc:2433
|
||||
//ivl_signal_nex()
|
||||
unusedFunction:t-dll-api.cc:2454
|
||||
//ivl_signal_npath()
|
||||
unusedFunction:t-dll-api.cc:2591
|
||||
//ivl_signal_packed_dimensions()
|
||||
unusedFunction:t-dll-api.cc:2471
|
||||
//ivl_signal_packed_lsb()
|
||||
unusedFunction:t-dll-api.cc:2484
|
||||
//ivl_signal_packed_msb()
|
||||
unusedFunction:t-dll-api.cc:2477
|
||||
//ivl_signal_path()
|
||||
unusedFunction:t-dll-api.cc:2597
|
||||
//ivl_signal_port()
|
||||
unusedFunction:t-dll-api.cc:2524
|
||||
//ivl_signal_scope()
|
||||
unusedFunction:t-dll-api.cc:2511
|
||||
//ivl_signal_signed()
|
||||
unusedFunction:t-dll-api.cc:2542
|
||||
//ivl_signal_width()
|
||||
unusedFunction:t-dll-api.cc:2517
|
||||
|
||||
//ivl_statement_type()
|
||||
unusedFunction:t-dll-api.cc:2610
|
||||
|
||||
//ivl_stmt_block_count()
|
||||
unusedFunction:t-dll-api.cc:2643
|
||||
//ivl_stmt_block_scope()
|
||||
unusedFunction:t-dll-api.cc:2628
|
||||
//ivl_stmt_block_stmt()
|
||||
unusedFunction:t-dll-api.cc:2658
|
||||
//ivl_stmt_call()
|
||||
unusedFunction:t-dll-api.cc:2674
|
||||
//ivl_stmt_case_count()
|
||||
unusedFunction:t-dll-api.cc:2695
|
||||
//ivl_stmt_case_expr()
|
||||
unusedFunction:t-dll-api.cc:2710
|
||||
//ivl_stmt_case_stmt()
|
||||
unusedFunction:t-dll-api.cc:2727
|
||||
//ivl_stmt_cond_expr()
|
||||
unusedFunction:t-dll-api.cc:2744
|
||||
//ivl_stmt_cond_false()
|
||||
unusedFunction:t-dll-api.cc:2771
|
||||
//ivl_stmt_cond_true()
|
||||
unusedFunction:t-dll-api.cc:2781
|
||||
//ivl_stmt_delay_expr()
|
||||
unusedFunction:t-dll-api.cc:2791
|
||||
//ivl_stmt_delay_val()
|
||||
unusedFunction:t-dll-api.cc:2808
|
||||
//ivl_stmt_events()
|
||||
unusedFunction:t-dll-api.cc:2834
|
||||
//ivl_stmt_file()
|
||||
unusedFunction:t-dll-api.cc:2616
|
||||
//ivl_stmt_lexp()
|
||||
unusedFunction:t-dll-api.cc:2862
|
||||
//ivl_stmt_lineno()
|
||||
unusedFunction:t-dll-api.cc:2622
|
||||
//ivl_stmt_lval()
|
||||
unusedFunction:t-dll-api.cc:2874
|
||||
//ivl_stmt_lvals()
|
||||
unusedFunction:t-dll-api.cc:2893
|
||||
//ivl_stmt_lwidth()
|
||||
unusedFunction:t-dll-api.cc:2911
|
||||
//ivl_stmt_name()
|
||||
unusedFunction:t-dll-api.cc:2944
|
||||
//ivl_stmt_nevent()
|
||||
unusedFunction:t-dll-api.cc:2815
|
||||
//ivl_stmt_opcode()
|
||||
unusedFunction:t-dll-api.cc:2957
|
||||
//ivl_stmt_parm()
|
||||
unusedFunction:t-dll-api.cc:2969
|
||||
//ivl_stmt_parm_count()
|
||||
unusedFunction:t-dll-api.cc:2983
|
||||
//ivl_stmt_rval()
|
||||
unusedFunction:t-dll-api.cc:2995
|
||||
//ivl_stmt_sfunc_as_task()
|
||||
unusedFunction:t-dll-api.cc:3013
|
||||
//ivl_stmt_sub_stmt()
|
||||
unusedFunction:t-dll-api.cc:3026
|
||||
|
||||
//ivl_switch_a()
|
||||
unusedFunction:t-dll-api.cc:3067
|
||||
//ivl_switch_b()
|
||||
unusedFunction:t-dll-api.cc:3073
|
||||
//ivl_switch_basename()
|
||||
unusedFunction:t-dll-api.cc:3049
|
||||
//ivl_switch_delay()
|
||||
unusedFunction:t-dll-api.cc:3103
|
||||
//ivl_switch_enable()
|
||||
unusedFunction:t-dll-api.cc:3079
|
||||
//ivl_switch_file()
|
||||
unusedFunction:t-dll-api.cc:3110
|
||||
//ivl_switch_island()
|
||||
unusedFunction:t-dll-api.cc:3116
|
||||
//ivl_switch_lineno()
|
||||
unusedFunction:t-dll-api.cc:3122
|
||||
//ivl_switch_offset()
|
||||
unusedFunction:t-dll-api.cc:3097
|
||||
//ivl_switch_part()
|
||||
unusedFunction:t-dll-api.cc:3091
|
||||
//ivl_switch_scope()
|
||||
unusedFunction:t-dll-api.cc:3055
|
||||
//ivl_switch_type()
|
||||
unusedFunction:t-dll-api.cc:3061
|
||||
//ivl_switch_width()
|
||||
unusedFunction:t-dll-api.cc:3085
|
||||
|
||||
//ivl_type_base()
|
||||
unusedFunction:t-dll-api.cc:3128
|
||||
//ivl_type_element()
|
||||
unusedFunction:t-dll-api.cc:3134
|
||||
//ivl_type_name()
|
||||
unusedFunction:t-dll-api.cc:3166
|
||||
//ivl_type_packed_dimensions()
|
||||
unusedFunction:t-dll-api.cc:3143
|
||||
//ivl_type_packed_lsb()
|
||||
unusedFunction:t-dll-api.cc:3150
|
||||
//ivl_type_packed_msb()
|
||||
unusedFunction:t-dll-api.cc:3158
|
||||
//ivl_type_prop_type()
|
||||
unusedFunction:t-dll-api.cc:3191
|
||||
//ivl_type_properties()
|
||||
unusedFunction:t-dll-api.cc:3174
|
||||
//ivl_type_signed()
|
||||
unusedFunction:t-dll-api.cc:3199
|
||||
|
||||
//ivl_udp_file()
|
||||
unusedFunction:t-dll-api.cc:1036
|
||||
//ivl_udp_init()
|
||||
unusedFunction:t-dll-api.cc:999
|
||||
//ivl_udp_lineno()
|
||||
unusedFunction:t-dll-api.cc:1042
|
||||
//ivl_udp_name()
|
||||
unusedFunction:t-dll-api.cc:1029
|
||||
//ivl_udp_nin()
|
||||
unusedFunction:t-dll-api.cc:993
|
||||
//ivl_udp_port()
|
||||
unusedFunction:t-dll-api.cc:1005
|
||||
//ivl_udp_row()
|
||||
unusedFunction:t-dll-api.cc:1014
|
||||
//ivl_udp_rows()
|
||||
unusedFunction:t-dll-api.cc:1023
|
||||
// ivl_udp_sequ()
|
||||
unusedFunction:t-dll-api.cc:987
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -187,9 +187,15 @@ ostream& operator << (ostream&fd, NetCaseCmp::kind_t that)
|
|||
case NetCaseCmp::NEQ:
|
||||
fd << "!==";
|
||||
break;
|
||||
case NetCaseCmp::XEQ:
|
||||
case NetCaseCmp::WEQ:
|
||||
fd << "==?";
|
||||
break;
|
||||
case NetCaseCmp::WNE:
|
||||
fd << "!=?";
|
||||
break;
|
||||
case NetCaseCmp::XEQ:
|
||||
fd << "==x?";
|
||||
break;
|
||||
case NetCaseCmp::ZEQ:
|
||||
fd << "==z?";
|
||||
break;
|
||||
|
|
@ -677,13 +683,25 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
|
|||
void NetFF::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_FF: " << name()
|
||||
<< " scope=" << scope_path(scope())
|
||||
<< " aset_value=" << aset_value_ << endl;
|
||||
<< " scope=" << scope_path(scope());
|
||||
if (negedge_)
|
||||
o << " negedge";
|
||||
else
|
||||
o << " posedge";
|
||||
o << " aset_value=" << aset_value_ << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetLatch::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_LATCH: " << name()
|
||||
<< " scope=" << scope_path(scope()) << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetLiteral::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "constant real " << real_
|
||||
|
|
@ -972,6 +990,18 @@ void NetProcTop::dump(ostream&o, unsigned ind) const
|
|||
o << "always /* " << get_fileline() << " in "
|
||||
<< scope_path(scope_) << " */" << endl;
|
||||
break;
|
||||
case IVL_PR_ALWAYS_COMB:
|
||||
o << "always_comb /* " << get_fileline() << " in "
|
||||
<< scope_path(scope_) << " */" << endl;
|
||||
break;
|
||||
case IVL_PR_ALWAYS_FF:
|
||||
o << "always_ff /* " << get_fileline() << " in "
|
||||
<< scope_path(scope_) << " */" << endl;
|
||||
break;
|
||||
case IVL_PR_ALWAYS_LATCH:
|
||||
o << "always_latch /* " << get_fileline() << " in "
|
||||
<< scope_path(scope_) << " */" << endl;
|
||||
break;
|
||||
case IVL_PR_FINAL:
|
||||
o << "final /* " << get_fileline() << " in "
|
||||
<< scope_path(scope_) << " */" << endl;
|
||||
|
|
@ -999,6 +1029,13 @@ void NetAnalogTop::dump(ostream&o, unsigned ind) const
|
|||
<< scope_path(scope_) << " */" << endl;
|
||||
break;
|
||||
|
||||
// These are not used in an analog context.
|
||||
case IVL_PR_ALWAYS_COMB:
|
||||
case IVL_PR_ALWAYS_FF:
|
||||
case IVL_PR_ALWAYS_LATCH:
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case IVL_PR_FINAL:
|
||||
o << "analog final /* " << get_fileline() << " in "
|
||||
<< scope_path(scope_) << " */" << endl;
|
||||
|
|
@ -1378,6 +1415,8 @@ void NetScope::dump(ostream&o) const
|
|||
if (is_interface()) o << " (interface)";
|
||||
o << " " << children_.size() << " children, "
|
||||
<< classes_.size() << " classes" << endl;
|
||||
if (unit() && !is_unit())
|
||||
o << " in compilation unit " << unit()->basename() << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1)
|
||||
o << " (* " << attr_key(idx) << " = "
|
||||
|
|
@ -1617,11 +1656,14 @@ void NetEBinary::dump(ostream&o) const
|
|||
case 'A':
|
||||
o << "~&";
|
||||
break;
|
||||
case 'e':
|
||||
o << "==";
|
||||
break;
|
||||
case 'E':
|
||||
o << "===";
|
||||
break;
|
||||
case 'e':
|
||||
o << "==";
|
||||
case 'w':
|
||||
o << "==?";
|
||||
break;
|
||||
case 'G':
|
||||
o << ">=";
|
||||
|
|
@ -1638,6 +1680,9 @@ void NetEBinary::dump(ostream&o) const
|
|||
case 'N':
|
||||
o << "!==";
|
||||
break;
|
||||
case 'W':
|
||||
o << "!=?";
|
||||
break;
|
||||
case 'o':
|
||||
o << "||";
|
||||
break;
|
||||
|
|
@ -1890,18 +1935,6 @@ void Design::dump(ostream&o) const
|
|||
cur->second->dump(o);
|
||||
}
|
||||
|
||||
o << "$ROOT CLASSESS:" << endl;
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++cur) {
|
||||
cur->second->dump_scope(o);
|
||||
}
|
||||
|
||||
o << "$ROOT TASKS/FUNCTIONS:" << endl;
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
cur->first->dump(o);
|
||||
}
|
||||
|
||||
o << "SCOPES:" << endl;
|
||||
for (list<NetScope*>::const_iterator scope = root_scopes_.begin();
|
||||
scope != root_scopes_.end(); ++ scope ) {
|
||||
|
|
|
|||
2
dosify.c
2
dosify.c
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/*
|
||||
* This is a simple program to make a dosified copy of the
|
||||
* original. That is, it converts unix style line ends to DOS
|
||||
* original. That is, it converts Unix style line ends to DOS
|
||||
* style. This is useful for installing text files.
|
||||
*
|
||||
* The exact substitution is to replace \n with \r\n. If the line
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ config.h: $(srcdir)/config.h.in Makefile
|
|||
|
||||
# Windows specific...
|
||||
res.rc: $(srcdir)/res.rc.in ../version.exe
|
||||
sed -e 's;@PRODUCTVERSION@;'`../version.exe '%M,%m,%n,0'`';' \
|
||||
sed -e 's;@PRODUCTVERSION@;'`../version.exe '%M,%n,0,0'`';' \
|
||||
$(srcdir)/res.rc.in > $@
|
||||
|
||||
res.o: res.rc
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2015 Gus Baldauf (gus@picturel.com)
|
||||
* Copyright (c) 2002 Gus Baldauf (gus@picturel.com)
|
||||
* Copyright (c) 2015 Martin Whitaker
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
/*
|
||||
* iverilog-vpi.c
|
||||
*
|
||||
* this program provides the functionality of iverilog-vpi.sh under Win32
|
||||
* this program provides the functionality of iverilog-vpi.sh under Windows
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -52,8 +53,8 @@ static struct global_strings {
|
|||
char *pIVL; /* path to IVL directory */
|
||||
char *pCCFLAGS; /* compiler flags for compiling C source files */
|
||||
char *pCXFLAGS; /* compiler flags for compiling C++ source files */
|
||||
char *pLDLIBS; /* LDLIBS option */
|
||||
char *pNewPath; /* new PATH environment variable setting */
|
||||
char *pLDLIBS; /* linker flags for final linking stage */
|
||||
char *pCCNAME; /* base name of compiler */
|
||||
char *pLD; /* what to use for a linker */
|
||||
} gstr;
|
||||
|
||||
|
|
@ -79,8 +80,8 @@ static void myExit(int exitVal)
|
|||
deInitDynString(gstr.pCCFLAGS);
|
||||
deInitDynString(gstr.pCXFLAGS);
|
||||
deInitDynString(gstr.pLDLIBS);
|
||||
deInitDynString(gstr.pNewPath);
|
||||
free(gstr.pLD);
|
||||
deInitDynString(gstr.pCCNAME);
|
||||
deInitDynString(gstr.pLD);
|
||||
|
||||
exit(exitVal);
|
||||
}
|
||||
|
|
@ -89,9 +90,8 @@ static void myExit(int exitVal)
|
|||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,"usage: iverilog-vpi" IVERILOG_SUFFIX " [src and obj files]...\n");
|
||||
fprintf(stderr," or iverilog-vpi" IVERILOG_SUFFIX " -mingw=dir\n");
|
||||
fprintf(stderr," or iverilog-vpi" IVERILOG_SUFFIX " -ivl=dir\n");
|
||||
fprintf(stderr, "usage: iverilog-vpi" IVERILOG_SUFFIX " [options] [src and obj files]...\n");
|
||||
fprintf(stderr, " or iverilog-vpi" IVERILOG_SUFFIX " -mingw=dir\n");
|
||||
myExit(1);
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ static void initDynString(char **str)
|
|||
*str = (char *) malloc(1);
|
||||
|
||||
if (!*str) {
|
||||
fprintf(stderr,"error: out of memory\n");
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
myExit(4);
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +111,8 @@ static void initDynString(char **str)
|
|||
|
||||
static void init(void)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
initDynString(&gstr.pCCSRC);
|
||||
initDynString(&gstr.pCXSRC);
|
||||
initDynString(&gstr.pOBJ);
|
||||
|
|
@ -123,7 +125,14 @@ static void init(void)
|
|||
initDynString(&gstr.pCCFLAGS);
|
||||
initDynString(&gstr.pCXFLAGS);
|
||||
initDynString(&gstr.pLDLIBS);
|
||||
initDynString(&gstr.pNewPath);
|
||||
initDynString(&gstr.pCCNAME);
|
||||
initDynString(&gstr.pLD);
|
||||
|
||||
/* Get the base name of the C compiler. */
|
||||
assign(&gstr.pCCNAME, IVERILOG_VPI_CC);
|
||||
ptr = strchr(gstr.pCCNAME, ' ');
|
||||
if (ptr != NULL) *ptr = '\0';
|
||||
|
||||
/* By default use the C compiler to link the programs. */
|
||||
assign(&gstr.pLD, IVERILOG_VPI_CC);
|
||||
}
|
||||
|
|
@ -139,7 +148,7 @@ static int endsIn (char *end, char *str)
|
|||
|
||||
ext = str + (strlen(str) - strlen(end));
|
||||
|
||||
return stricmp(end,ext) ? 0 : 1;
|
||||
return stricmp(end, ext) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* return true if "str" begins with "prefix", case insensitive */
|
||||
|
|
@ -149,7 +158,7 @@ static int startsWith (char *prefix, char *str)
|
|||
if (strlen(prefix) >= strlen(str))
|
||||
return 0;
|
||||
|
||||
return strnicmp(prefix,str,strlen(prefix)) ? 0 : 1;
|
||||
return strnicmp(prefix, str, strlen(prefix)) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* append "app" to "ptr", allocating memory as needed */
|
||||
|
|
@ -158,26 +167,26 @@ static int startsWith (char *prefix, char *str)
|
|||
static void appendn (char **ptr, char *app, size_t count)
|
||||
{
|
||||
char *nptr = (char *) realloc(*ptr, strlen(*ptr) +
|
||||
(count?count:strlen(app)) + 1);
|
||||
(count ? count : strlen(app)) + 1);
|
||||
|
||||
if (nptr == NULL) {
|
||||
fprintf(stderr,"error: out of memory\n");
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
free(*ptr);
|
||||
myExit(4);
|
||||
}
|
||||
*ptr = nptr;
|
||||
|
||||
if (count)
|
||||
strncat(*ptr,app,count);
|
||||
strncat(*ptr, app, count);
|
||||
else
|
||||
strcat(*ptr,app);
|
||||
strcat(*ptr, app);
|
||||
}
|
||||
|
||||
/* append "app" to "ptr", allocating memory as needed */
|
||||
|
||||
static void append (char **ptr, char *app)
|
||||
{
|
||||
appendn(ptr,app,0);
|
||||
appendn(ptr, app, 0);
|
||||
}
|
||||
|
||||
/* if the string does not end with a backslash, add one */
|
||||
|
|
@ -185,7 +194,7 @@ static void append (char **ptr, char *app)
|
|||
static void appendBackSlash(char **str)
|
||||
{
|
||||
if ((*str)[strlen(*str)-1] != '\\')
|
||||
append(str,"\\");
|
||||
append(str, "\\");
|
||||
}
|
||||
|
||||
/* copy count characters of "str" to "ptr", allocating memory as needed */
|
||||
|
|
@ -193,28 +202,28 @@ static void appendBackSlash(char **str)
|
|||
|
||||
static void assignn (char **ptr, char *str, size_t count)
|
||||
{
|
||||
char *nptr = (char *) realloc(*ptr, (count?count:strlen(str)) + 1);
|
||||
char *nptr = (char *) realloc(*ptr, (count ? count : strlen(str)) + 1);
|
||||
|
||||
if (nptr == NULL) {
|
||||
fprintf(stderr,"error: out of memory\n");
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
free(*ptr);
|
||||
myExit(4);
|
||||
}
|
||||
*ptr = nptr;
|
||||
|
||||
if (count) {
|
||||
strncpy(*ptr,str,count);
|
||||
strncpy(*ptr, str, count);
|
||||
(*ptr)[count] = 0;
|
||||
}
|
||||
else
|
||||
strcpy(*ptr,str);
|
||||
strcpy(*ptr, str);
|
||||
}
|
||||
|
||||
/* copy count characters of "str" to "ptr", allocating memory as needed */
|
||||
|
||||
static void assign (char **ptr, char *str)
|
||||
{
|
||||
assignn(ptr,str,0);
|
||||
assignn(ptr, str, 0);
|
||||
}
|
||||
|
||||
/* get a copy of a Icarus Verilog registry string key */
|
||||
|
|
@ -226,11 +235,11 @@ static int GetRegistryKey(char *key, char **value)
|
|||
char *regKeyBuffer;
|
||||
DWORD regKeyType, regKeySize;
|
||||
|
||||
lrv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Icarus Verilog",0,KEY_QUERY_VALUE,&hkKey);
|
||||
lrv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Icarus Verilog", 0, KEY_QUERY_VALUE, &hkKey);
|
||||
if (lrv != ERROR_SUCCESS)
|
||||
return 0;
|
||||
|
||||
lrv = RegQueryValueEx(hkKey,key,NULL,®KeyType,NULL,®KeySize);
|
||||
lrv = RegQueryValueEx(hkKey, key, NULL, ®KeyType, NULL, ®KeySize);
|
||||
if ((lrv != ERROR_SUCCESS) || (regKeyType != REG_SZ) || (!regKeySize)) {
|
||||
lrv = RegCloseKey(hkKey);
|
||||
return 0;
|
||||
|
|
@ -239,7 +248,7 @@ static int GetRegistryKey(char *key, char **value)
|
|||
regKeyBuffer = (char *) malloc(regKeySize+1);
|
||||
if (!regKeyBuffer) {
|
||||
lrv = RegCloseKey(hkKey);
|
||||
fprintf(stderr,"error: out of memory\n");
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
myExit(4);
|
||||
}
|
||||
regKeyBuffer[regKeySize] = 0; /* makes sure there is a trailing NULL */
|
||||
|
|
@ -255,7 +264,7 @@ static int GetRegistryKey(char *key, char **value)
|
|||
|
||||
RegCloseKey(hkKey);
|
||||
|
||||
assign(value,regKeyBuffer);
|
||||
assign(value, regKeyBuffer);
|
||||
free(regKeyBuffer);
|
||||
|
||||
return 1;
|
||||
|
|
@ -265,27 +274,30 @@ static int GetRegistryKey(char *key, char **value)
|
|||
|
||||
static void SetRegistryKey(char *key, char *value)
|
||||
{
|
||||
long lrv;
|
||||
HKEY hkKey;
|
||||
DWORD res;
|
||||
|
||||
if (RegCreateKeyEx(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
"Software\\Icarus Verilog",
|
||||
0,
|
||||
"",
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS,NULL,
|
||||
&hkKey,
|
||||
&res) != ERROR_SUCCESS)
|
||||
return;
|
||||
lrv = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Icarus Verilog", 0, "",
|
||||
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkKey, &res);
|
||||
if (lrv != ERROR_SUCCESS) {
|
||||
char message[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, lrv, LANG_USER_DEFAULT,
|
||||
message, sizeof(message), NULL);
|
||||
fprintf(stderr, "error: couldn't write to registry - %s\n", message);
|
||||
if (lrv == ERROR_ACCESS_DENIED) {
|
||||
fprintf(stderr, " try running as administrator\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* This needs an unsigned char *, but for MinGW the char is signed. */
|
||||
RegSetValueEx(hkKey, key, 0, REG_SZ, (unsigned char *) value,
|
||||
strlen(value)+1);
|
||||
RegCloseKey(hkKey);
|
||||
|
||||
printf("info: storing %s in Windows' registry entry\n",value);
|
||||
printf(" HKEY_LOCAL_MACHINE\\Software\\Icarus Verilog\\%s\n",key);
|
||||
printf("info: storing %s in Windows' registry entry\n", value);
|
||||
printf(" HKEY_LOCAL_MACHINE\\Software\\Icarus Verilog\\%s\n", key);
|
||||
}
|
||||
|
||||
/* parse the command line, assign results to global variable strings */
|
||||
|
|
@ -302,7 +314,6 @@ static int parse(int argc, char *argv[])
|
|||
char lib_option[] = "-l";
|
||||
char inc_option[] = "-I";
|
||||
char mingw_option[] = "-mingw=";
|
||||
char ivl_option[] = "-ivl=";
|
||||
char def_option[] = "-D";
|
||||
|
||||
if (argc == 1) return 0;
|
||||
|
|
@ -342,7 +353,7 @@ static int parse(int argc, char *argv[])
|
|||
/* Check for compiled object files */
|
||||
else if (endsIn(dot_o_ext, argv[idx])) {
|
||||
++srcFileCnt;
|
||||
append(&gstr.pOBJ," ");
|
||||
append(&gstr.pOBJ, " ");
|
||||
append(&gstr.pOBJ, argv[idx]);
|
||||
if (!*gstr.pOUT)
|
||||
assignn(&gstr.pOUT, argv[idx],
|
||||
|
|
@ -352,10 +363,6 @@ static int parse(int argc, char *argv[])
|
|||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --name option */
|
||||
else if (startsWith(name_option, argv[idx])) {
|
||||
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
|
||||
|
|
@ -396,7 +403,7 @@ static int parse(int argc, char *argv[])
|
|||
/* Check for the --install-dir option */
|
||||
else if (stricmp("--install-dir", argv[idx]) == 0) {
|
||||
setup_ivl_environment();
|
||||
printf("%s\\\\lib\\\\ivl" IVERILOG_SUFFIX "\\\\.\n", gstr.pIVL);
|
||||
printf("%s\\lib\\ivl" IVERILOG_SUFFIX "\\.\n", gstr.pIVL);
|
||||
myExit(0);
|
||||
}
|
||||
/* This is different than iverilog-vpi.sh, we don't
|
||||
|
|
@ -405,15 +412,16 @@ static int parse(int argc, char *argv[])
|
|||
}
|
||||
|
||||
/* In case there is a --name without source/object files */
|
||||
if (0 == srcFileCnt) assign(&gstr.pOUT,"");
|
||||
if (0 == srcFileCnt) assign(&gstr.pOUT, "");
|
||||
|
||||
/* Normally it's an error if there are no source or object files */
|
||||
/* Unless we are setting the IVL or MinGW registry entries */
|
||||
if (!*gstr.pOUT) {
|
||||
if (!*gstr.pMINGW && !*gstr.pIVL) return 0;
|
||||
} else
|
||||
if (*gstr.pOUT) {
|
||||
/* We have a valid result file so add the .vpi extension */
|
||||
append(&gstr.pOUT, ".vpi");
|
||||
} else {
|
||||
/* Unless we are setting the MinGW registry entry, it's
|
||||
an error if there are no source or object files */
|
||||
if (!*gstr.pMINGW) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -424,58 +432,27 @@ static void checkMingwDir(char *root)
|
|||
{
|
||||
int irv;
|
||||
struct _stat stat_buf;
|
||||
|
||||
char *path, *comp, *cp;
|
||||
initDynString(&path);
|
||||
assign(&path,gstr.pMINGW);
|
||||
appendBackSlash(&path);
|
||||
append(&path,"bin\\");
|
||||
/* Get just the compiler name (the first word) */
|
||||
comp = strdup(IVERILOG_VPI_CC);
|
||||
cp = strchr(comp, ' ');
|
||||
if (cp != NULL) *cp = '\0';
|
||||
append(&path, comp);
|
||||
append(&path,".exe");
|
||||
free(comp);
|
||||
|
||||
irv = _stat(path,&stat_buf);
|
||||
deInitDynString(path);
|
||||
|
||||
if (irv) {
|
||||
fprintf(stderr,"error: %s does not appear to be the valid root directory\n",root);
|
||||
fprintf(stderr," of MinGW. Use the -mingw option of iverilog-vpi.exe to\n");
|
||||
fprintf(stderr," point to the MinGW root directory. For a Windows command\n");
|
||||
fprintf(stderr," shell the option would be something like -mingw=c:\\mingw\n");
|
||||
fprintf(stderr," For a Cygwin shell the option would be something like\n");
|
||||
fprintf(stderr," -mingw=c:\\\\mingw\n");
|
||||
myExit(5);
|
||||
}
|
||||
}
|
||||
|
||||
/* do minimal check that the Icarus Verilog root directory looks valid */
|
||||
|
||||
static void checkIvlDir(char *root)
|
||||
{
|
||||
int irv;
|
||||
struct _stat stat_buf;
|
||||
|
||||
char *path;
|
||||
|
||||
initDynString(&path);
|
||||
assign(&path,gstr.pIVL);
|
||||
assign(&path, gstr.pMINGW);
|
||||
appendBackSlash(&path);
|
||||
append(&path,"bin\\vvp" IVERILOG_SUFFIX ".exe");
|
||||
append(&path, "bin\\");
|
||||
append(&path, gstr.pCCNAME);
|
||||
append(&path, ".exe");
|
||||
|
||||
irv = _stat(path,&stat_buf);
|
||||
deInitDynString(path);
|
||||
|
||||
if (irv) {
|
||||
fprintf(stderr,"error: %s does not appear to be the valid root directory of\n",root);
|
||||
fprintf(stderr," Icarus Verilog. Use the -ivl option of iverilog-vpi" IVERILOG_SUFFIX " to\n");
|
||||
fprintf(stderr," point to the Icarus Verilog root directory. For a Windows\n");
|
||||
fprintf(stderr," command shell the option would be something like -ivl=c:\\iverilog\n");
|
||||
fprintf(stderr," For a Cygwin shell the option would be something like\n");
|
||||
fprintf(stderr," -ivl=c:\\\\iverilog\n");
|
||||
myExit(6);
|
||||
fprintf(stderr, "error: %s\n", root);
|
||||
fprintf(stderr, " does not appear to be the valid root directory of\n");
|
||||
fprintf(stderr, " MinGW. Use the -mingw option of iverilog-vpi.exe to\n");
|
||||
fprintf(stderr, " point to the MinGW root directory. For a Windows command\n");
|
||||
fprintf(stderr, " shell the option would be something like -mingw=c:\\mingw\n");
|
||||
fprintf(stderr, " For a Cygwin shell the option would be something like\n");
|
||||
fprintf(stderr, " -mingw=c:\\\\mingw\n");
|
||||
myExit(5);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -485,67 +462,91 @@ static void checkIvlDir(char *root)
|
|||
|
||||
static void setup_mingw_environment(void)
|
||||
{
|
||||
char *pOldPATH = getenv("PATH"); /* get current path */
|
||||
char buffer[1]; /* doesn't matter how big this is, as we don't use the result */
|
||||
char *path;
|
||||
|
||||
if (*gstr.pMINGW) {
|
||||
checkMingwDir(gstr.pMINGW);
|
||||
SetRegistryKey(IVL_REGKEY_MINGW,gstr.pMINGW);
|
||||
} else if (!GetRegistryKey(IVL_REGKEY_MINGW,&gstr.pMINGW)) {
|
||||
fprintf(stderr,"error: can not locate the MinGW root directory, use the -mingw option of\n");
|
||||
fprintf(stderr," iverilog-vpi.exe to point to the MinGW root directory. For\n");
|
||||
fprintf(stderr," a Windows command shell the option would be something like\n");
|
||||
fprintf(stderr," -mingw=c:\\mingw For a Cygwin shell the option would be\n");
|
||||
fprintf(stderr," something like -mingw=c:\\\\mingw\n");
|
||||
myExit(5);
|
||||
}
|
||||
if (!*gstr.pOUT) SetRegistryKey(IVL_REGKEY_MINGW, gstr.pMINGW);
|
||||
|
||||
} else if (GetRegistryKey(IVL_REGKEY_MINGW, &gstr.pMINGW)) {
|
||||
checkMingwDir(gstr.pMINGW);
|
||||
|
||||
} else if (SearchPath(NULL, gstr.pCCNAME, ".exe", sizeof(buffer), buffer, NULL)) {
|
||||
return;
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "error: cannot locate the MinGW C compiler - either add its location\n");
|
||||
fprintf(stderr, " to the PATH environment variable or use the -mingw option of\n");
|
||||
fprintf(stderr, " iverilog-vpi.exe to point to the MinGW root directory. For\n");
|
||||
fprintf(stderr, " a Windows command shell the option would be something like\n");
|
||||
fprintf(stderr, " -mingw=c:\\mingw For a Cygwin shell the option would be\n");
|
||||
fprintf(stderr, " something like -mingw=c:\\\\mingw\n");
|
||||
myExit(5);
|
||||
}
|
||||
|
||||
/* Create new path with MinGW in it */
|
||||
assign(&gstr.pNewPath,"PATH=");
|
||||
append(&gstr.pNewPath,gstr.pMINGW);
|
||||
appendBackSlash(&gstr.pNewPath);
|
||||
append(&gstr.pNewPath, "\\");
|
||||
append(&gstr.pNewPath,"bin;");
|
||||
append(&gstr.pNewPath,pOldPATH);
|
||||
initDynString(&path);
|
||||
assign(&path, "PATH=");
|
||||
append(&path, gstr.pMINGW);
|
||||
appendBackSlash(&path);
|
||||
append(&path, "bin;");
|
||||
append(&path, getenv("PATH"));
|
||||
|
||||
/* Place new path in environment */
|
||||
_putenv(gstr.pNewPath);
|
||||
_putenv(path);
|
||||
deInitDynString(path);
|
||||
}
|
||||
|
||||
/* see if we can find iverilog root */
|
||||
|
||||
#define IVL_REGKEY_IVL "InstallDir"
|
||||
/* find the iverilog root and initialise the compiler options */
|
||||
|
||||
static void setup_ivl_environment(void)
|
||||
{
|
||||
if (*gstr.pIVL) {
|
||||
checkIvlDir(gstr.pIVL);
|
||||
SetRegistryKey(IVL_REGKEY_IVL,gstr.pIVL);
|
||||
} else if (!GetRegistryKey(IVL_REGKEY_IVL,&gstr.pIVL)) {
|
||||
fprintf(stderr,"error: can not locate the Icarus Verilog root directory, use the -ivl option\n");
|
||||
fprintf(stderr," of iverilog-vpi" IVERILOG_SUFFIX " to point to the Icarus Verilog root directory.\n");
|
||||
fprintf(stderr," For a Windows command shell the option would be something like\n");
|
||||
fprintf(stderr," -ivl=c:\\iverilog For a Cygwin shell the option would be something\n");
|
||||
fprintf(stderr," like -ivl=c:\\\\iverilog\n");
|
||||
myExit(6);
|
||||
}
|
||||
char path[4096];
|
||||
char *ptr;
|
||||
|
||||
/* Extract the Icarus Verilog root directory from the path to the
|
||||
command. The command path will look something like this:
|
||||
|
||||
C:\iverilog\bin\iverilog-vpi.exe
|
||||
|
||||
The corresponding root directory is
|
||||
|
||||
C:\iverilog
|
||||
|
||||
so we chop off the file name and the last directory. */
|
||||
GetModuleFileName(NULL, path, sizeof(path));
|
||||
ptr = strrchr(path, '\\');
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "error: couldn't find start of program name in command path '%s'\n", path);
|
||||
myExit(6);
|
||||
}
|
||||
*ptr = 0;
|
||||
ptr = strrchr(path, '\\');
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "error: couldn't find start of bin directory in command path '%s'\n", path);
|
||||
myExit(6);
|
||||
}
|
||||
*ptr = 0;
|
||||
assign(&gstr.pIVL, path);
|
||||
|
||||
/* Build up the CCFLAGS option string */
|
||||
assign(&gstr.pCCFLAGS,IVERILOG_VPI_CFLAGS " -I\"");
|
||||
append(&gstr.pCCFLAGS,gstr.pIVL);
|
||||
assign(&gstr.pCCFLAGS, IVERILOG_VPI_CFLAGS " -I\"");
|
||||
append(&gstr.pCCFLAGS, gstr.pIVL);
|
||||
appendBackSlash(&gstr.pCCFLAGS);
|
||||
append(&gstr.pCCFLAGS,"\\include\\\\iverilog\"" IVERILOG_SUFFIX);
|
||||
append(&gstr.pCCFLAGS, "include\\iverilog\"" IVERILOG_SUFFIX);
|
||||
|
||||
/* Build up the CXFLAGS option string */
|
||||
assign(&gstr.pCXFLAGS,IVERILOG_VPI_CXXFLAGS " -I\"");
|
||||
append(&gstr.pCXFLAGS,gstr.pIVL);
|
||||
assign(&gstr.pCXFLAGS, IVERILOG_VPI_CXXFLAGS " -I\"");
|
||||
append(&gstr.pCXFLAGS, gstr.pIVL);
|
||||
appendBackSlash(&gstr.pCXFLAGS);
|
||||
append(&gstr.pCXFLAGS,"\\include\\\\iverilog\"" IVERILOG_SUFFIX);
|
||||
append(&gstr.pCXFLAGS, "include\\iverilog\"" IVERILOG_SUFFIX);
|
||||
|
||||
/* Build up the LDFLAGS option string */
|
||||
assign(&gstr.pLDLIBS,"-L\"");
|
||||
append(&gstr.pLDLIBS,gstr.pIVL);
|
||||
assign(&gstr.pLDLIBS, "-L\"");
|
||||
append(&gstr.pLDLIBS, gstr.pIVL);
|
||||
appendBackSlash(&gstr.pLDLIBS);
|
||||
append(&gstr.pLDLIBS,"\\lib\" " IVERILOG_VPI_LDLIBS);
|
||||
append(&gstr.pLDLIBS, "lib\" " IVERILOG_VPI_LDLIBS);
|
||||
}
|
||||
|
||||
/* compile source modules */
|
||||
|
|
@ -609,12 +610,7 @@ static void compile_and_link(void)
|
|||
|
||||
/* To make the output match iverilog-vpi.sh do not print out the
|
||||
* root directories */
|
||||
|
||||
// printf("MinGW root directory: %s.\n", gstr.pMINGW);
|
||||
checkMingwDir(gstr.pMINGW);
|
||||
|
||||
// printf("Icarus Verilog root directory: %s.\n", gstr.pIVL);
|
||||
checkIvlDir(gstr.pIVL);
|
||||
|
||||
/* compile the C source files (*.c) */
|
||||
compile(gstr.pCCSRC, gstr.pCCFLAGS, &gstr.pOBJ, &compile_errors, IVERILOG_VPI_CC );
|
||||
|
|
@ -622,7 +618,7 @@ static void compile_and_link(void)
|
|||
compile(gstr.pCXSRC, gstr.pCXFLAGS, &gstr.pOBJ, &compile_errors, IVERILOG_VPI_CXX);
|
||||
|
||||
if (compile_errors) {
|
||||
fprintf(stderr,"iverilog-vpi: %d file(s) failed to compile.\n",
|
||||
fprintf(stderr, "iverilog-vpi: %d file(s) failed to compile.\n",
|
||||
compile_errors);
|
||||
myExit(2);
|
||||
}
|
||||
|
|
@ -653,7 +649,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
init();
|
||||
|
||||
if (!parse(argc,argv)) usage();
|
||||
if (!parse(argc, argv)) usage();
|
||||
|
||||
setup_mingw_environment();
|
||||
setup_ivl_environment();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2017 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
|
||||
|
|
@ -124,7 +124,8 @@ int cmdfile_stack_ptr = 0;
|
|||
"-c" { return TOK_Dc; }
|
||||
"-f" { return TOK_Dc; }
|
||||
|
||||
/* Notice the -v flag. */
|
||||
/* Notice the -l or -v flag. */
|
||||
"-l" { return TOK_Dv; }
|
||||
"-v" { return TOK_Dv; }
|
||||
|
||||
/* Notice the -y flag. */
|
||||
|
|
@ -251,7 +252,7 @@ void destroy_lexor(void)
|
|||
{
|
||||
# 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
|
||||
# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
|
||||
yylex_destroy();
|
||||
# endif
|
||||
# endif
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
.TH iverilog 1 "December 16th, 2014" "" "Version %M.%m.%n %E"
|
||||
.TH iverilog 1 "Nov 8th, 2017" "" "Version %M.%n%E"
|
||||
.SH NAME
|
||||
iverilog - Icarus Verilog compiler
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B iverilog
|
||||
[\-ESVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]]
|
||||
[\-Pparameter=value] [\-pflag=value]
|
||||
[\-dname] [\-g1995|\-g2001|\-g2005|\-g2005-sv|\-g2009|\-g2012|\-g<feature>]
|
||||
[\-ESuVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]]
|
||||
[\-Pparameter=value] [\-pflag=value] [\-dname]
|
||||
[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g<feature>]
|
||||
[\-Iincludedir] [\-mmodule] [\-M[mode=]file] [\-Nfile] [\-ooutputfilename]
|
||||
[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] sourcefile
|
||||
[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] [\-lfile]
|
||||
sourcefile
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
|
|
@ -30,7 +31,7 @@ different set of programs. The path given is used to locate
|
|||
\fIivlpp\fP, \fIivl\fP, code generators and the VPI modules.
|
||||
.TP 8
|
||||
.B -c\fIfile\fP -f\fIfile\fP
|
||||
These flags specifies an input file that contains a list of Verilog
|
||||
These flags specify an input file that contains a list of Verilog
|
||||
source files. This is similar to the \fIcommand file\fP of other
|
||||
Verilog simulators, in that it is a file that contains the file names
|
||||
instead of taking them on the command line. See \fBCommand Files\fP below.
|
||||
|
|
@ -133,12 +134,29 @@ parameter assignment is evaluated as a lossless expression, as is any
|
|||
expression containing an unsized constant number, and unsized constant
|
||||
numbers are not truncated to integer width.
|
||||
.TP 8
|
||||
.B -gshared-loop-index\fI|\fP-gno-shared-loop-index
|
||||
Enable (default) or disable the exclusion of for-loop control variables
|
||||
from implicit event_expression lists. When enabled, if a for-loop control
|
||||
variable (loop index) is only used inside the for-loop statement, the
|
||||
compiler will not include it in an implicit event_expression list it
|
||||
calculates for that statement or any enclosing statement. This allows
|
||||
the same control variable to be used in multiple processes without risk
|
||||
of entering an infinite loop caused by each process triggering all other
|
||||
processes that use the same varaible. For strict compliance with the
|
||||
standards, this behaviour should be disabled.
|
||||
.TP 8
|
||||
.B -I\fIincludedir\fP
|
||||
Append directory \fIincludedir\fP to list of directories searched
|
||||
for Verilog include files. The \fB\-I\fP switch may be used many times
|
||||
to specify several directories to search, the directories are searched
|
||||
in the order they appear on the command line.
|
||||
.TP 8
|
||||
.B -l\fIfile\fP
|
||||
Add the specified file to the list of source files to be compiled,
|
||||
but mark it as a library file. All modules contained within that
|
||||
file will be treated as library modules, and only elaborated if
|
||||
they are instantiated by other modules in the design.
|
||||
.TP 8
|
||||
.B -M\fIpath\fP
|
||||
This is equivalent to \fB\-Mall=path\fP. Preserved for backwards
|
||||
compatibility.
|
||||
|
|
@ -204,6 +222,12 @@ will suppress the warning that the compiler is making a choice.
|
|||
Use this switch to specify the target output format. See the
|
||||
\fBTARGETS\fP section below for a list of valid output formats.
|
||||
.TP 8
|
||||
.B -u
|
||||
Treat each source file as a separate compilation unit (as defined in
|
||||
SystemVerilog). If compiling for an \fIIEEE1364\fP generation, this
|
||||
will just reset all compiler directives (including macro definitions)
|
||||
before each new file is processed.
|
||||
.TP 8
|
||||
.B -v
|
||||
Turn on verbose messages. This will print the command lines that are
|
||||
executed to perform the actual compilation, along with version
|
||||
|
|
@ -292,8 +316,14 @@ after a \fB\-Wall\fP argument to suppress isolated warning types.
|
|||
|
||||
.TP 8
|
||||
.B all
|
||||
This enables the implicit, portbind, select\-range, timescale, and
|
||||
sensitivity\-entire\-array warning categories.
|
||||
This enables the anachronisms, implicit, macro-replacement, portbind,
|
||||
select\-range, timescale, and sensitivity\-entire\-array warning
|
||||
categories.
|
||||
|
||||
.TP 8
|
||||
.B anachronisms
|
||||
This enables warnings for use of features that have been deprecated
|
||||
or removed in the selected generation of the Verilog language.
|
||||
|
||||
.TP 8
|
||||
.B implicit
|
||||
|
|
@ -301,6 +331,13 @@ This enables warnings for creation of implicit declarations. For
|
|||
example, if a scalar wire X is used but not declared in the Verilog
|
||||
source, this will print a warning at its first use.
|
||||
|
||||
.TP 8
|
||||
.B macro-redefinition\fI | \fPmacro-replacement
|
||||
This enables preprocessor warnings when a macro is being redefined.
|
||||
The first variant prints a warning any time a macro is redefined.
|
||||
The second variant only prints a warning if the macro text changes.
|
||||
Use \fBno-macro-redefinition\fP to turn off all warnings of this type.
|
||||
|
||||
.TP 8
|
||||
.B portbind
|
||||
This enables warnings for ports of module instantiations that are not
|
||||
|
|
@ -379,6 +416,11 @@ The function returns an integer.
|
|||
The function returns a vector with the given width, and is signed or
|
||||
unsigned according to the flag.
|
||||
|
||||
.TP 8
|
||||
.B vpiSysFuncString
|
||||
The function returns a string. This is an Icarus-specific extension, not
|
||||
available in the VPI standard.
|
||||
|
||||
.SH "COMMAND FILES"
|
||||
The command file allows the user to place source file names and
|
||||
certain command line switches into a text file instead of on a long
|
||||
|
|
@ -397,6 +439,15 @@ A \fB\-c\fP or \fB\-f\fP token prefixes a command file, exactly like it
|
|||
does on the command line. The cmdfile may be on the same line or the
|
||||
next non-comment line.
|
||||
|
||||
.TP 8
|
||||
.B -l\ \fIfile\fP -v\ \fIfile\fP
|
||||
A \fB\-l\fP token prefixes a library file in the command file,
|
||||
exactly like it does on the command line. The parameter to the \fB\-l\fP
|
||||
flag may be on the same line or the next non-comment line. \fB\-v\fP is
|
||||
an alias for \fB\-l\fP, provided for compatibility with other simulators.
|
||||
|
||||
Variables in the \fIfile\fP are substituted.
|
||||
|
||||
.TP 8
|
||||
.B -y\ \fIlibdir\fP
|
||||
A \fB\-y\fP token prefixes a library directory in the command file,
|
||||
|
|
@ -520,14 +571,14 @@ Steve Williams (steve@icarus.com)
|
|||
|
||||
.SH SEE ALSO
|
||||
vvp(1),
|
||||
.BR "<http://www.icarus.com/eda/verilog/>"
|
||||
.BR "<http://iverilog.icarus.com/>"
|
||||
|
||||
Tips on using, debugging, and developing the compiler can be found at
|
||||
.BR "<http://iverilog.wikia.com/>"
|
||||
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 2002\-2014 Stephen Williams
|
||||
Copyright \(co 2002\-2017 Stephen Williams
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
|
|
|
|||
277
driver/main.c
277
driver/main.c
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -38,13 +38,13 @@ const char NOTICE[] =
|
|||
;
|
||||
|
||||
const char HELP[] =
|
||||
"Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]\n"
|
||||
"Usage: iverilog [-EiSuvV] [-B base] [-c cmdfile|-f cmdfile]\n"
|
||||
" [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g<feature>]\n"
|
||||
" [-D macro[=defn]] [-I includedir]\n"
|
||||
" [-M [mode=]depfile] [-m module]\n"
|
||||
" [-N file] [-o filename] [-p flag=value]\n"
|
||||
" [-s topmodule] [-t target] [-T min|typ|max]\n"
|
||||
" [-W class] [-y dir] [-Y suf] source_file(s)\n"
|
||||
" [-W class] [-y dir] [-Y suf] [-l file] source_file(s)\n"
|
||||
"\n"
|
||||
"See the man page for details.";
|
||||
|
||||
|
|
@ -128,6 +128,7 @@ const char*gen_icarus = "icarus-misc";
|
|||
const char*gen_io_range_error = "io-range-error";
|
||||
const char*gen_strict_ca_eval = "no-strict-ca-eval";
|
||||
const char*gen_strict_expr_width = "no-strict-expr-width";
|
||||
const char*gen_shared_loop_index = "shared-loop-index";
|
||||
const char*gen_verilog_ams = "no-verilog-ams";
|
||||
|
||||
/* Boolean: true means use a default include dir, false means don't */
|
||||
|
|
@ -137,7 +138,12 @@ int gen_std_include = 1;
|
|||
of the include list. */
|
||||
int gen_relative_include = 0;
|
||||
|
||||
char warning_flags[16] = "n";
|
||||
char warning_flags[17] = "n";
|
||||
|
||||
int separate_compilation_flag = 0;
|
||||
|
||||
/* Boolean: true means ignore errors about missing modules */
|
||||
int ignore_missing_modules = 0;
|
||||
|
||||
unsigned integer_width = 32;
|
||||
|
||||
|
|
@ -340,10 +346,15 @@ static int t_version_only(void)
|
|||
|
||||
static void build_preprocess_command(int e_flag)
|
||||
{
|
||||
snprintf(tmp, sizeof tmp, "%s%civlpp %s%s -F\"%s\" -f\"%s\" -p\"%s\" ",
|
||||
ivlpp_dir, sep, verbose_flag?" -v":"",
|
||||
e_flag?"":" -L", defines_path, source_path,
|
||||
compiled_defines_path);
|
||||
snprintf(tmp, sizeof tmp, "%s%civlpp %s%s%s -F\"%s\" -f\"%s\" -p\"%s\"%s",
|
||||
ivlpp_dir, sep,
|
||||
verbose_flag ? " -v" : "",
|
||||
e_flag ? "" : " -L",
|
||||
strchr(warning_flags, 'r') ? " -Wredef-all " :
|
||||
strchr(warning_flags, 'R') ? " -Wredef-chg " : "",
|
||||
defines_path, source_path,
|
||||
compiled_defines_path,
|
||||
e_flag ? "" : " | ");
|
||||
}
|
||||
|
||||
static int t_preprocess_only(void)
|
||||
|
|
@ -406,8 +417,12 @@ static int t_compile(void)
|
|||
{
|
||||
unsigned rc;
|
||||
|
||||
/* Start by building the preprocess command line. */
|
||||
build_preprocess_command(0);
|
||||
/* Start by building the preprocess command line, if required.
|
||||
This pipes into the main ivl command. */
|
||||
if (!separate_compilation_flag)
|
||||
build_preprocess_command(0);
|
||||
else
|
||||
strcpy(tmp, "");
|
||||
|
||||
size_t ncmd = strlen(tmp);
|
||||
char*cmd = malloc(ncmd + 1);
|
||||
|
|
@ -417,8 +432,8 @@ static int t_compile(void)
|
|||
int rtn;
|
||||
#endif
|
||||
|
||||
/* Build the ivl command and pipe it to the preprocessor. */
|
||||
snprintf(tmp, sizeof tmp, " | %s%civl", base, sep);
|
||||
/* Build the ivl command. */
|
||||
snprintf(tmp, sizeof tmp, "%s%civl", base, sep);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
|
|
@ -446,7 +461,16 @@ static int t_compile(void)
|
|||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
snprintf(tmp, sizeof tmp, " -C\"%s\" -- -", iconfig_common_path);
|
||||
snprintf(tmp, sizeof tmp, " -C\"%s\"", iconfig_common_path);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (separate_compilation_flag)
|
||||
snprintf(tmp, sizeof tmp, " -F\"%s\"", source_path);
|
||||
else
|
||||
snprintf(tmp, sizeof tmp, " -- -");
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
|
|
@ -496,6 +520,8 @@ static void process_warning_switch(const char*name)
|
|||
if (strcmp(name,"all") == 0) {
|
||||
process_warning_switch("anachronisms");
|
||||
process_warning_switch("implicit");
|
||||
process_warning_switch("implicit-dimensions");
|
||||
process_warning_switch("macro-replacement");
|
||||
process_warning_switch("portbind");
|
||||
process_warning_switch("select-range");
|
||||
process_warning_switch("timescale");
|
||||
|
|
@ -503,9 +529,21 @@ static void process_warning_switch(const char*name)
|
|||
} else if (strcmp(name,"anachronisms") == 0) {
|
||||
if (! strchr(warning_flags, 'n'))
|
||||
strcat(warning_flags, "n");
|
||||
} else if (strcmp(name,"floating-nets") == 0) {
|
||||
if (! strchr(warning_flags, 'f'))
|
||||
strcat(warning_flags, "f");
|
||||
} else if (strcmp(name,"implicit") == 0) {
|
||||
if (! strchr(warning_flags, 'i'))
|
||||
strcat(warning_flags, "i");
|
||||
} else if (strcmp(name,"implicit-dimensions") == 0) {
|
||||
if (! strchr(warning_flags, 'd'))
|
||||
strcat(warning_flags, "d");
|
||||
} else if (strcmp(name,"macro-redefinition") == 0) {
|
||||
if (! strchr(warning_flags, 'r'))
|
||||
strcat(warning_flags, "r");
|
||||
} else if (strcmp(name,"macro-replacement") == 0) {
|
||||
if (! strchr(warning_flags, 'R'))
|
||||
strcat(warning_flags, "R");
|
||||
} else if (strcmp(name,"portbind") == 0) {
|
||||
if (! strchr(warning_flags, 'p'))
|
||||
strcat(warning_flags, "p");
|
||||
|
|
@ -532,12 +570,35 @@ static void process_warning_switch(const char*name)
|
|||
cp[0] = cp[1];
|
||||
cp += 1;
|
||||
}
|
||||
} else if (strcmp(name,"no-floating-nets") == 0) {
|
||||
char*cp = strchr(warning_flags, 'f');
|
||||
if (cp) while (*cp) {
|
||||
cp[0] = cp[1];
|
||||
cp += 1;
|
||||
}
|
||||
} else if (strcmp(name,"no-implicit") == 0) {
|
||||
char*cp = strchr(warning_flags, 'i');
|
||||
if (cp) while (*cp) {
|
||||
cp[0] = cp[1];
|
||||
cp += 1;
|
||||
}
|
||||
} else if (strcmp(name,"no-implicit-dimensions") == 0) {
|
||||
char*cp = strchr(warning_flags, 'd');
|
||||
if (cp) while (*cp) {
|
||||
cp[0] = cp[1];
|
||||
cp += 1;
|
||||
}
|
||||
} else if (strcmp(name,"no-macro-redefinition") == 0) {
|
||||
char*cp = strchr(warning_flags, 'r');
|
||||
if (cp) while (*cp) {
|
||||
cp[0] = cp[1];
|
||||
cp += 1;
|
||||
}
|
||||
cp = strchr(warning_flags, 'R');
|
||||
if (cp) while (*cp) {
|
||||
cp[0] = cp[1];
|
||||
cp += 1;
|
||||
}
|
||||
} else if (strcmp(name,"no-portbind") == 0) {
|
||||
char*cp = strchr(warning_flags, 'p');
|
||||
if (cp) while (*cp) {
|
||||
|
|
@ -720,6 +781,12 @@ static int process_generation(const char*name)
|
|||
else if (strcmp(name,"no-strict-expr-width") == 0)
|
||||
gen_strict_expr_width = "no-strict-expr-width";
|
||||
|
||||
else if (strcmp(name,"shared-loop-index") == 0)
|
||||
gen_shared_loop_index = "shared-loop-index";
|
||||
|
||||
else if (strcmp(name,"no-shared-loop-index") == 0)
|
||||
gen_shared_loop_index = "no-shared-loop-index";
|
||||
|
||||
else if (strcmp(name,"verilog-ams") == 0)
|
||||
gen_verilog_ams = "verilog-ams";
|
||||
|
||||
|
|
@ -745,7 +812,8 @@ static int process_generation(const char*name)
|
|||
" icarus-misc | no-icarus-misc\n"
|
||||
" io-range-error | no-io-range-error\n"
|
||||
" strict-ca-eval | no-strict-ca-eval\n"
|
||||
" strict-expr-width | no-strict-expr-width\n");
|
||||
" strict-expr-width | no-strict-expr-width\n"
|
||||
" shared-loop-index | no-shared-loop-index\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -798,58 +866,108 @@ static void add_sft_file(const char *module)
|
|||
free(file);
|
||||
}
|
||||
|
||||
static void find_ivl_root_failed(const char *reason)
|
||||
{
|
||||
fprintf(stderr, "Cannot locate IVL modules : %s\n", reason);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void find_ivl_root(void)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
const char *ivl_lib_prefix = "\\lib";
|
||||
const char *ivl_lib_suffix = "\\ivl" IVL_SUFFIX;
|
||||
#else
|
||||
const char *ivl_lib_prefix = IVL_LIB;
|
||||
const char *ivl_lib_suffix = "/ivl" IVL_SUFFIX;
|
||||
#endif
|
||||
ssize_t len = 0;
|
||||
char *s;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
/* First try the location specified in the build process. */
|
||||
if (access(IVL_ROOT, F_OK) != -1) {
|
||||
assert(strlen(IVL_ROOT) < sizeof ivl_root);
|
||||
strcpy(ivl_root, IVL_ROOT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* If that fails, calculate the ivl_root from the path to the
|
||||
command. This is always necessary on Windows because of the
|
||||
installation process, but may also be necessary on other OSs
|
||||
if the package has been relocated.
|
||||
|
||||
On Windows we know the command path is formed like this:
|
||||
|
||||
$(prefix)\bin\iverilog.exe
|
||||
|
||||
The module path in a Windows installation is the path:
|
||||
|
||||
$(prefix)\lib\ivl$(suffix)
|
||||
|
||||
so we chop the file name and the last directory by
|
||||
turning the last two \ characters to null. Then we append
|
||||
the lib\ivl$(suffix) to finish.
|
||||
|
||||
On other OSs, we expect the command path to be:
|
||||
|
||||
$(prefix)/bin/iverilog
|
||||
|
||||
and the module path to be:
|
||||
|
||||
$(prefix)/$(lib)/ivl$(suffix)
|
||||
|
||||
so we extract the $(prefix) from the command location as for
|
||||
Windows and the $(lib) from IVL_LIB. This will of course fail
|
||||
if the user has overridden $(bindir) or $(libdir), but there's
|
||||
not a lot we can do in that case.
|
||||
*/
|
||||
#ifdef __MINGW32__
|
||||
char tmppath[MAXSIZE];
|
||||
len = GetModuleFileName(NULL, tmppath, sizeof tmppath);
|
||||
if (len >= (ssize_t) sizeof ivl_root) {
|
||||
find_ivl_root_failed("command path exceeds size of string buffer.");
|
||||
}
|
||||
/* Convert to a short name to remove any embedded spaces. */
|
||||
len = GetShortPathName(tmppath, ivl_root, sizeof ivl_root);
|
||||
#else
|
||||
len = readlink("/proc/self/exe", ivl_root, sizeof ivl_root);
|
||||
#endif
|
||||
if (len >= (ssize_t) sizeof ivl_root) {
|
||||
find_ivl_root_failed("command path exceeds size of string buffer.");
|
||||
}
|
||||
if (len <= 0) {
|
||||
find_ivl_root_failed("couldn't get command path from OS.");
|
||||
}
|
||||
s = strrchr(ivl_root, sep);
|
||||
if (s == 0) {
|
||||
find_ivl_root_failed("missing first separator in command path.");
|
||||
}
|
||||
*s = 0;
|
||||
s = strrchr(ivl_root, sep);
|
||||
if (s == 0) {
|
||||
find_ivl_root_failed("missing second separator in command path.");
|
||||
}
|
||||
*s = 0;
|
||||
len = s - ivl_root;
|
||||
s = strrchr(ivl_lib_prefix, sep);
|
||||
assert(s);
|
||||
if (len + strlen(s) + strlen(ivl_lib_suffix) >= (ssize_t) sizeof ivl_root) {
|
||||
find_ivl_root_failed("module path exceeds size of string buffer.");
|
||||
}
|
||||
strcat(ivl_root, s);
|
||||
strcat(ivl_root, ivl_lib_suffix);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int e_flag = 0;
|
||||
int version_flag = 0;
|
||||
int opt;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
/* Calculate the ivl_root from the path to the command. This
|
||||
is necessary because of the installation process on
|
||||
Windows. Mostly, it is those darn drive letters, but oh
|
||||
well. We know the command path is formed like this:
|
||||
|
||||
D:\iverilog\bin\iverilog.exe
|
||||
|
||||
The module path in a Windows installation is the path:
|
||||
|
||||
D:\iverilog\lib\ivl$(suffix)
|
||||
|
||||
so we chop the file name and the last directory by
|
||||
turning the last two \ characters to null. Then we append
|
||||
the lib\ivl$(suffix) to finish. */
|
||||
char *s;
|
||||
char tmppath[MAXSIZE];
|
||||
GetModuleFileName(NULL, tmppath, sizeof tmppath);
|
||||
/* Convert to a short name to remove any embedded spaces. */
|
||||
GetShortPathName(tmppath, ivl_root, sizeof ivl_root);
|
||||
s = strrchr(ivl_root, sep);
|
||||
if (s) *s = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s: Missing first %c in exe path!\n",
|
||||
argv[0], sep);
|
||||
exit(1);
|
||||
}
|
||||
s = strrchr(ivl_root, sep);
|
||||
if (s) *s = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s: Missing second %c in exe path!\n",
|
||||
argv[0], sep);
|
||||
exit(1);
|
||||
}
|
||||
strcat(ivl_root, "\\lib\\ivl" IVL_SUFFIX);
|
||||
|
||||
find_ivl_root();
|
||||
base = ivl_root;
|
||||
|
||||
#else
|
||||
/* In a UNIX environment, the IVL_ROOT from the Makefile is
|
||||
dependable. It points to the $prefix/lib/ivl directory,
|
||||
where the sub-parts are installed. */
|
||||
strcpy(ivl_root, IVL_ROOT);
|
||||
base = ivl_root;
|
||||
#endif
|
||||
|
||||
/* Create a temporary file for communicating input parameters
|
||||
to the preprocessor. */
|
||||
source_path = strdup(my_tempfile("ivrlg", &source_file));
|
||||
|
|
@ -910,7 +1028,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iM:m:N:o:P:p:Ss:T:t:uvVW:y:Y:")) != EOF) {
|
||||
|
||||
switch (opt) {
|
||||
case 'B':
|
||||
|
|
@ -965,6 +1083,14 @@ int main(int argc, char **argv)
|
|||
process_include_dir(optarg);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
ignore_missing_modules = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
process_file_name(optarg, 1);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (process_depfile(optarg) != 0)
|
||||
return -1;
|
||||
|
|
@ -1005,6 +1131,9 @@ int main(int argc, char **argv)
|
|||
case 't':
|
||||
targ = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
separate_compilation_flag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_flag = 1;
|
||||
break;
|
||||
|
|
@ -1047,19 +1176,10 @@ int main(int argc, char **argv)
|
|||
|
||||
if (version_flag || verbose_flag) {
|
||||
printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n");
|
||||
printf("Copyright 1998-2013 Stephen Williams\n\n");
|
||||
printf("Copyright 1998-2017 Stephen Williams\n\n");
|
||||
puts(NOTICE);
|
||||
}
|
||||
|
||||
if (synth_flag) {
|
||||
fprintf(stderr, "Warning: Synthesis is not currently being "
|
||||
"maintained and may not\n");
|
||||
fprintf(stderr, " function correctly. V0.8 was the "
|
||||
"last release branch to\n");
|
||||
fprintf(stderr, " have active synthesis development "
|
||||
"and support!\n");
|
||||
}
|
||||
|
||||
/* Make a common conf file path to reflect the target. */
|
||||
snprintf(iconfig_common_path, sizeof iconfig_common_path, "%s%c%s%s.conf",
|
||||
base, sep, targ, synth_flag? "-s" : "");
|
||||
|
|
@ -1072,6 +1192,7 @@ int main(int argc, char **argv)
|
|||
how to handle them. */
|
||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "sys_func:%s%cvhdl_textio.sft\n", base, sep);
|
||||
|
||||
/* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams,
|
||||
* then include the v2005_math library. */
|
||||
|
|
@ -1107,9 +1228,11 @@ int main(int argc, char **argv)
|
|||
fprintf(iconfig_file, "generation:%s\n", gen_io_range_error);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_strict_ca_eval);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_strict_expr_width);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_shared_loop_index);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_verilog_ams);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_icarus);
|
||||
fprintf(iconfig_file, "warnings:%s\n", warning_flags);
|
||||
fprintf(iconfig_file, "ignore_missing_modules:%s\n", ignore_missing_modules ? "true" : "false");
|
||||
fprintf(iconfig_file, "out:%s\n", opath);
|
||||
if (depfile) {
|
||||
fprintf(iconfig_file, "depfile:%s\n", depfile);
|
||||
|
|
@ -1186,8 +1309,12 @@ int main(int argc, char **argv)
|
|||
will append to the file, so this is necessary to make sure
|
||||
it starts out empty. */
|
||||
if (depfile) {
|
||||
FILE*fd = fopen(depfile, "w");
|
||||
fclose(fd);
|
||||
FILE *fd = fopen(depfile, "w");
|
||||
if (!fd) {
|
||||
fprintf(stderr, "%s: can't open %s file.\n\n%s\n", argv[0], depfile, HELP);
|
||||
return 1;
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
if (source_count == 0 && !version_flag) {
|
||||
|
|
@ -1202,8 +1329,12 @@ int main(int argc, char **argv)
|
|||
/* Write the preprocessor command needed to preprocess a
|
||||
single file. This may be used to preprocess library
|
||||
files. */
|
||||
fprintf(iconfig_file, "ivlpp:%s%civlpp -L -F\"%s\" -P\"%s\"\n",
|
||||
ivlpp_dir, sep, defines_path, compiled_defines_path);
|
||||
fprintf(iconfig_file, "ivlpp:%s%civlpp %s -L -F\"%s\" -P\"%s\"\n",
|
||||
ivlpp_dir, sep,
|
||||
strchr(warning_flags, 'r') ? "-Wredef-all" :
|
||||
strchr(warning_flags, 'R') ? "-Wredef-chg" : "",
|
||||
defines_path, compiled_defines_path
|
||||
);
|
||||
|
||||
/* Done writing to the iconfig file. Close it now. */
|
||||
fclose(iconfig_file);
|
||||
|
|
|
|||
297
elab_expr.cc
297
elab_expr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -90,7 +90,7 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd)
|
|||
|
||||
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
|
||||
ivl_variable_type_t lv_type, unsigned lv_width,
|
||||
PExpr*expr, bool need_const)
|
||||
PExpr*expr, bool need_const, bool force_unsigned)
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << expr->get_fileline() << ": elaborate_rval_expr: "
|
||||
|
|
@ -135,7 +135,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
|
|||
}
|
||||
|
||||
return elab_and_eval(des, scope, expr, context_wid, need_const,
|
||||
false, lv_type);
|
||||
false, lv_type, force_unsigned);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -329,10 +329,12 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
case '>': // > Should be handled by PEBComp
|
||||
case 'e': // == Should be handled by PEBComp
|
||||
case 'E': // === Should be handled by PEBComp
|
||||
case 'w': // ==? Should be handled by PEBComp
|
||||
case 'L': // <= Should be handled by PEBComp
|
||||
case 'G': // >= Should be handled by PEBComp
|
||||
case 'n': // != Should be handled by PEBComp
|
||||
case 'N': // !== Should be handled by PEBComp
|
||||
case 'W': // !=? Should be handled by PEBComp
|
||||
case 'p': // ** should be handled by PEBPower
|
||||
ivl_assert(*this, 0);
|
||||
default:
|
||||
|
|
@ -668,6 +670,18 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'w': /* ==? */
|
||||
case 'W': /* !=? */
|
||||
if ((lp->expr_type() != IVL_VT_BOOL && lp->expr_type() != IVL_VT_LOGIC) ||
|
||||
(rp->expr_type() != IVL_VT_BOOL && rp->expr_type() != IVL_VT_LOGIC)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< human_readable_op(op_)
|
||||
<< " operator may only have INTEGRAL operands."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -675,10 +689,7 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
|
|||
NetExpr*tmp = new NetEBComp(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
unsigned PEBLogic::test_width(Design*, NetScope*, width_mode_t&)
|
||||
|
|
@ -716,10 +727,7 @@ NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope,
|
|||
NetExpr*tmp = new NetEBLogic(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
|
|
@ -1035,8 +1043,7 @@ NetExpr*PEBShift::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
|||
tmp->set_line(*this);
|
||||
tmp = new NetESelect(lp, tmp, 1);
|
||||
tmp->set_line(*this);
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(true);
|
||||
tmp = pad_to_width(tmp, expr_wid, true, *this);
|
||||
|
||||
delete rp;
|
||||
return tmp;
|
||||
|
|
@ -1277,7 +1284,6 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
|
||||
perm_string member_name;
|
||||
ivl_type_t member_type = 0;
|
||||
pform_name_t use_path = path_;
|
||||
perm_string method_name = peek_tail_name(use_path);
|
||||
use_path.pop_back();
|
||||
|
|
@ -1317,11 +1323,8 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
|||
|
||||
const netclass_t* class_type = net->class_type();
|
||||
int midx = class_type->property_idx_from_name(member_name);
|
||||
if (midx >= 0)
|
||||
member_type = class_type->get_prop_type(midx);
|
||||
else
|
||||
member_type = 0;
|
||||
use_path = tmp_path;
|
||||
ivl_type_t member_type = 0;
|
||||
if (midx >= 0) member_type = class_type->get_prop_type(midx);
|
||||
|
||||
use_darray = dynamic_cast<const netdarray_t*> (member_type);
|
||||
|
||||
|
|
@ -1335,7 +1338,7 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
|||
if (net == 0)
|
||||
return 0;
|
||||
|
||||
// Look fonr built in string attributes.
|
||||
// Look for built in string attributes.
|
||||
if (net->data_type()==IVL_VT_STRING) {
|
||||
|
||||
if (method_name == "len") {
|
||||
|
|
@ -1410,27 +1413,11 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
|
|||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::cast_to_width_: "
|
||||
<< "cast to " << wid
|
||||
<< " bits " << (signed_flag_?"signed":"unsigned")
|
||||
<< " bits " << (signed_flag_ ? "signed" : "unsigned")
|
||||
<< " from expr_width()=" << expr->expr_width() << endl;
|
||||
}
|
||||
|
||||
/* If the expression is a const, then replace it with a new
|
||||
const. This is a more efficient result. */
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
tmp->cast_signed(signed_flag_);
|
||||
if (wid > tmp->expr_width()) {
|
||||
tmp = new NetEConst(verinum(tmp->value(), wid));
|
||||
tmp->set_line(*this);
|
||||
delete expr;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESelect*tmp = new NetESelect(expr, 0, wid);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
tmp->set_line(*this);
|
||||
|
||||
return tmp;
|
||||
return cast_to_width(expr, wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1469,6 +1456,13 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!type_is_vectorable(expr_type_)) {
|
||||
cerr << get_fileline() << ": error: The argument to "
|
||||
<< name << " must be a vector type." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: "
|
||||
<< name << " expression is the argument cast to expr_wid=" << expr_wid << endl;
|
||||
|
|
@ -1535,7 +1529,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
|
||||
PExpr*expr = parms_[0];
|
||||
|
||||
verinum val (expr->has_sign()? verinum::V1 : verinum::V0, 1);
|
||||
verinum val (expr->has_sign() ? verinum::V1 : verinum::V0, 1);
|
||||
NetEConst*sub = new NetEConst(val);
|
||||
sub->set_line(*this);
|
||||
|
||||
|
|
@ -1576,6 +1570,18 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
/* These functions can work in a constant context with a signal expression. */
|
||||
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0]))) {
|
||||
if (strcmp(name, "$dimensions") == 0) need_const = false;
|
||||
else if (strcmp(name, "$high") == 0) need_const = false;
|
||||
else if (strcmp(name, "$increment") == 0) need_const = false;
|
||||
else if (strcmp(name, "$left") == 0) need_const = false;
|
||||
else if (strcmp(name, "$low") == 0) need_const = false;
|
||||
else if (strcmp(name, "$right") == 0) need_const = false;
|
||||
else if (strcmp(name, "$size") == 0) need_const = false;
|
||||
else if (strcmp(name, "$unpacked_dimensions") == 0) need_const = false;
|
||||
}
|
||||
|
||||
unsigned parm_errors = 0;
|
||||
unsigned missing_parms = 0;
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
|
|
@ -1597,7 +1603,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
|
||||
if (missing_parms > 0) {
|
||||
cerr << get_fileline() << ": error: The function " << name
|
||||
<< " has been called with empty parameters." << endl;
|
||||
<< " has been called with missing/empty parameters." << endl;
|
||||
cerr << get_fileline() << ": : Verilog doesn't allow "
|
||||
<< "passing empty parameters to functions." << endl;
|
||||
des->errors += 1;
|
||||
|
|
@ -1606,10 +1612,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
if (missing_parms || parm_errors)
|
||||
return 0;
|
||||
|
||||
NetExpr*tmp = pad_to_width(fun, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(fun, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
|
||||
|
|
@ -1666,10 +1669,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
|
|||
NetExpr*tmp = new NetEAccess(branch, nature);
|
||||
tmp->set_line(*this);
|
||||
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1678,7 +1678,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
|
|||
static NetExpr* check_for_enum_methods(const LineInfo*li,
|
||||
Design*des, NetScope*scope,
|
||||
const netenum_t*netenum,
|
||||
pform_name_t use_path,
|
||||
const pform_name_t&use_path,
|
||||
perm_string method_name,
|
||||
NetExpr*expr,
|
||||
unsigned rtn_wid,
|
||||
|
|
@ -2017,7 +2017,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
}
|
||||
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
NetExpr *base = packed_base? packed_base : make_const_val(off);
|
||||
NetExpr *base = packed_base ? packed_base : make_const_val(off);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
|
|
@ -2281,15 +2281,12 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
|
|||
if(res->darray_type())
|
||||
return func;
|
||||
|
||||
NetExpr*tmp = pad_to_width(func, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(func, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": internal error: Unable to locate "
|
||||
"function return value for " << path_
|
||||
<< " in " << dscope->basename() << "." << endl;
|
||||
"function return value for " << path_
|
||||
<< " in " << dscope->basename() << "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2313,6 +2310,21 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
|||
const unsigned parm_count = parms.size() - parm_off;
|
||||
const unsigned actual_count = parms_.size();
|
||||
|
||||
/* The parser can't distinguish between a function call with
|
||||
no arguments and a function call with one empty argument,
|
||||
and always supplies one empty argument. Handle the no
|
||||
argument case here. */
|
||||
if ((parm_count == 0) && (actual_count == 1) && (parms_[0] == 0))
|
||||
return 0;
|
||||
|
||||
if (actual_count > parm_count) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Too many arguments (" << actual_count
|
||||
<< ", expecting " << parm_count << ")"
|
||||
<< " in call to function." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
unsigned pidx = idx + parm_off;
|
||||
PExpr*tmp = (idx < actual_count) ? parms_[idx] : 0;
|
||||
|
|
@ -2343,7 +2355,7 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
|||
} else if (def->port_defe(pidx)) {
|
||||
if (! gn_system_verilog()) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<<"Found (and using) default function argument "
|
||||
<< "Found (and using) default function argument "
|
||||
<< "requires SystemVerilog." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
|
@ -2357,7 +2369,7 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
|||
|
||||
if (missing_parms > 0) {
|
||||
cerr << get_fileline() << ": error: The function " << path_
|
||||
<< " has been called with empty parameters." << endl;
|
||||
<< " has been called with missing/empty parameters." << endl;
|
||||
cerr << get_fileline() << ": : Verilog doesn't allow "
|
||||
<< "passing empty parameters to functions." << endl;
|
||||
parm_errors += 1;
|
||||
|
|
@ -2506,22 +2518,54 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
|
||||
unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
{
|
||||
expr_width_ = size_;
|
||||
ivl_assert(*this, size_);
|
||||
ivl_assert(*this, base_);
|
||||
|
||||
NetExpr*size_ex = elab_and_eval(des, scope, size_, -1, true);
|
||||
NetEConst*size_ce = dynamic_cast<NetEConst*>(size_ex);
|
||||
expr_width_ = size_ce ? size_ce->value().as_ulong() : 0;
|
||||
delete size_ex;
|
||||
if (expr_width_ == 0) {
|
||||
cerr << get_fileline() << ": error: Cast size expression "
|
||||
"must be constant and greater than zero." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
width_mode_t tmp_mode = PExpr::SIZED;
|
||||
base_->test_width(des, scope, tmp_mode);
|
||||
|
||||
return size_;
|
||||
if (!type_is_vectorable(base_->expr_type())) {
|
||||
cerr << get_fileline() << ": error: Cast base expression "
|
||||
"must be a vector type." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
expr_type_ = base_->expr_type();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = base_->has_sign();
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned, unsigned) const
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS);
|
||||
NetESelect*sel = new NetESelect(sub, 0, size_);
|
||||
sel->set_line(*this);
|
||||
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
||||
|
||||
return sel;
|
||||
ivl_assert(*this, size_);
|
||||
ivl_assert(*this, base_);
|
||||
|
||||
NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), flags);
|
||||
|
||||
// Perform the cast. The extension method (zero/sign), if needed,
|
||||
// depends on the type of the base expression.
|
||||
NetExpr*tmp = cast_to_width(sub, expr_width_, base_->has_sign(), *this);
|
||||
|
||||
// Pad up to the expression width. The extension method (zero/sign)
|
||||
// depends on the type of enclosing expression.
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid)
|
||||
|
|
@ -2567,7 +2611,7 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
// Find rounded up length that can fit the whole casted array of vectors
|
||||
int len = base->expr_width() + vector->packed_width() - 1;
|
||||
if(base->expr_width() > vector->packed_width()) {
|
||||
if(base->expr_width() > (unsigned)vector->packed_width()) {
|
||||
len /= vector->packed_width();
|
||||
} else {
|
||||
len /= base->expr_width();
|
||||
|
|
@ -2625,17 +2669,15 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
if((base_->expr_type() != IVL_VT_BOOL) &&
|
||||
(base_->expr_type() != IVL_VT_LOGIC)) {
|
||||
cerr << get_fileline() << ": cannot be casted to string." << endl;
|
||||
cerr << get_fileline() << ": cannot be cast to a string." << endl;
|
||||
ivl_assert(*this, false);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": sorry: I don't know how to cast expression." << endl;
|
||||
ivl_assert(*this, false);
|
||||
|
||||
return expr;
|
||||
cerr << get_fileline() << ": sorry: This cast operation is not yet supported." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
|
|
@ -2666,7 +2708,7 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
|
|||
expr_is_string = NO;
|
||||
}
|
||||
|
||||
expr_type_ = (expr_is_string==YES)? IVL_VT_STRING : IVL_VT_LOGIC;
|
||||
expr_type_ = (expr_is_string==YES) ? IVL_VT_STRING : IVL_VT_LOGIC;
|
||||
signed_flag_ = false;
|
||||
|
||||
// If there is a repeat expression, then evaluate the constant
|
||||
|
|
@ -2733,6 +2775,7 @@ NetExpr* PEConcat::elaborate_expr(Design*, NetScope*,
|
|||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
// fallthrough
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "I don't know how to elaborate(ivl_type_t)"
|
||||
|
|
@ -2827,17 +2870,16 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
|||
concat->set(idx, parms[off+idx]);
|
||||
}
|
||||
|
||||
if (wid_sum == 0 && concat_depth < 2) {
|
||||
cerr << get_fileline() << ": error: Concatenation may not "
|
||||
<< "have zero width in this context." << endl;
|
||||
if (wid_sum == 0 && expr_type_ != IVL_VT_STRING) {
|
||||
cerr << get_fileline() << ": error: Concatenation/replication "
|
||||
<< "may not have zero width in this context." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
delete concat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*tmp = pad_to_width(concat, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
NetExpr*tmp = pad_to_width(concat, expr_wid, signed_flag_, *this);
|
||||
|
||||
concat_depth -= 1;
|
||||
return tmp;
|
||||
|
|
@ -2924,7 +2966,7 @@ bool PEIdent::calculate_bits_(Design*des, NetScope*scope,
|
|||
NetEConst*msb_c = dynamic_cast<NetEConst*>(msb_ex);
|
||||
if (msb_c == 0) {
|
||||
cerr << index_tail.msb->get_fileline() << ": error: "
|
||||
"Bit select expressionsmust be constant."
|
||||
"Bit select expressions must be constant."
|
||||
<< endl;
|
||||
cerr << index_tail.msb->get_fileline() << ": : "
|
||||
"This msb expression violates the rule: "
|
||||
|
|
@ -3020,7 +3062,7 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
|
|||
NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1, true);
|
||||
NetEConst*wid_c = dynamic_cast<NetEConst*>(wid_ex);
|
||||
|
||||
wid = wid_c? wid_c->value().as_ulong() : 0;
|
||||
wid = wid_c ? wid_c->value().as_ulong() : 0;
|
||||
if (wid == 0) {
|
||||
cerr << index_tail.lsb->get_fileline() << ": error: "
|
||||
"Indexed part widths must be constant and greater than zero."
|
||||
|
|
@ -3121,6 +3163,25 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
|
|||
}
|
||||
}
|
||||
|
||||
// Look for the enumeration attributes.
|
||||
if (const netenum_t*netenum = net->enumeration()) {
|
||||
if (member_name == "num") {
|
||||
expr_type_ = IVL_VT_BOOL;
|
||||
expr_width_ = 32;
|
||||
min_width_ = 32;
|
||||
signed_flag_= true;
|
||||
return 32;
|
||||
}
|
||||
if ((member_name == "first") || (member_name == "last") ||
|
||||
(member_name == "next") || (member_name == "prev")) {
|
||||
expr_type_ = netenum->base_type();
|
||||
expr_width_ = netenum->packed_width();;
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = netenum->get_signed();
|
||||
return expr_width_;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3169,7 +3230,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
bool parts_defined;
|
||||
calculate_parts_(des, scope, msb, lsb, parts_defined);
|
||||
if (parts_defined)
|
||||
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
|
||||
use_width = 1 + ((msb>lsb) ? (msb-lsb) : (lsb-msb));
|
||||
else
|
||||
use_width = UINT_MAX;
|
||||
break;
|
||||
|
|
@ -3203,7 +3264,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
ivl_assert(*this, 0);
|
||||
}
|
||||
|
||||
if (const netdarray_t*darray = net? net->darray_type() : 0) {
|
||||
if (const netdarray_t*darray = net ? net->darray_type() : 0) {
|
||||
switch (use_sel) {
|
||||
case index_component_t::SEL_BIT:
|
||||
case index_component_t::SEL_BIT_LAST:
|
||||
|
|
@ -3257,7 +3318,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
<< net->name() << " is a net, "
|
||||
<< "type=" << expr_type_
|
||||
<< ", width=" << expr_width_
|
||||
<< ", signed_=" << (signed_flag_?"true":"false")
|
||||
<< ", signed_=" << (signed_flag_ ? "true" : "false")
|
||||
<< ", use_depth=" << use_depth
|
||||
<< ", packed_dimensions=" << net->packed_dimensions()
|
||||
<< ", unpacked_dimensions=" << net->unpacked_dimensions()
|
||||
|
|
@ -3428,29 +3489,41 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
if (net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Expecting idents with ntype to be signals." << endl;
|
||||
cerr << get_fileline() << ": error: Unable to bind variable `"
|
||||
<< path_ << "' in `" << scope_path(use_scope) << "'" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! ntype->type_compatible(net->net_type())) {
|
||||
cerr << get_fileline() << ": internal_error: "
|
||||
<< "net type doesn't match context type." << endl;
|
||||
if (const netdarray_t*array_type = dynamic_cast<const netdarray_t*> (ntype)) {
|
||||
if (array_type->type_compatible(net->net_type())) {
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "net type=";
|
||||
// Icarus allows a dynamic array to be initialised with a
|
||||
// single elementary value, so try that next.
|
||||
ntype = array_type->element_type();
|
||||
}
|
||||
|
||||
if (! ntype->type_compatible(net->net_type())) {
|
||||
cerr << get_fileline() << ": error: the type of the variable '"
|
||||
<< path_ << "' doesn't match the context type." << endl;
|
||||
|
||||
cerr << get_fileline() << ": : " << "variable type=";
|
||||
if (net->net_type())
|
||||
net->net_type()->debug_dump(cerr);
|
||||
else
|
||||
cerr << "<nil>";
|
||||
cerr << endl;
|
||||
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "context type=";
|
||||
cerr << get_fileline() << ": : " << "context type=";
|
||||
ivl_assert(*this, ntype);
|
||||
ntype->debug_dump(cerr);
|
||||
cerr << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
ivl_assert(*this, ntype->type_compatible(net->net_type()));
|
||||
|
||||
|
|
@ -3490,7 +3563,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
use_comp.index, net->unpacked_dimensions(),
|
||||
need_const, net->unpacked_count(),
|
||||
need_const,
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
|
@ -3754,10 +3827,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
if (!tmp) return 0;
|
||||
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
// If the identifier names a signal (a register or wire)
|
||||
|
|
@ -3793,10 +3863,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< ", tmp=" << *tmp << endl;
|
||||
}
|
||||
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
|
||||
return tmp;
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
// If the identifier is a named event
|
||||
|
|
@ -3843,7 +3910,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
// Maybe this is a method attached to an enumeration name? If
|
||||
// this is system verilog, then test to see if the name is
|
||||
// this is SystemVerilog, then test to see if the name is
|
||||
// really a method attached to an object.
|
||||
if (gn_system_verilog() && found_in==0 && path_.size() >= 2) {
|
||||
pform_name_t use_path = path_;
|
||||
|
|
@ -3896,9 +3963,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
member_comp);
|
||||
if (!tmp) return 0;
|
||||
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
return tmp;
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
if (net->class_type() != 0) {
|
||||
|
|
@ -3921,7 +3986,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
if ( !(SYS_TASK_ARG & flags) ) {
|
||||
// I cannot interpret this identifier. Error message.
|
||||
cerr << get_fileline() << ": error: Unable to bind "
|
||||
<< (NEED_CONST & flags ? "parameter" : "wire/reg/memory")
|
||||
<< ((NEED_CONST & flags) ? "parameter" : "wire/reg/memory")
|
||||
<< " `" << path_ << "' in `" << scope_path(scope) << "'"
|
||||
<< endl;
|
||||
if (scope->need_const_func()) {
|
||||
|
|
@ -4015,7 +4080,7 @@ static verinum param_part_select_bits(const verinum&par_val, long wid,
|
|||
// If the input is a string, and the part select is working on
|
||||
// byte boundaries, then make the result into a string.
|
||||
if (par_val.is_string() && (labs(lsv)%8 == 0) && (wid%8 == 0))
|
||||
return result.as_string();
|
||||
return verinum(result.as_string());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -4477,7 +4542,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
|||
<< "Elaborate parameter <" << path_
|
||||
<< "> as enumeration constant." << *etmp << endl;
|
||||
tmp = etmp->dup_expr();
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
|
||||
} else {
|
||||
perm_string name = peek_tail_name(path_);
|
||||
|
|
@ -4563,7 +4628,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
|||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, net->unpacked_dimensions(),
|
||||
need_const, net->unpacked_count(),
|
||||
need_const,
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
|
@ -4996,6 +5061,8 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
|||
ivl_assert(*this, index_tail.lsb == 0);
|
||||
|
||||
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
|
||||
if (!mux)
|
||||
return 0;
|
||||
|
||||
if (const netdarray_t*darray = net->sig()->darray_type()) {
|
||||
// Special case: This is a select of a dynamic
|
||||
|
|
@ -5312,9 +5379,8 @@ NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*scope,
|
|||
// expression. Elaborate the expression as an element
|
||||
// type. The run-time will assign this value to each element.
|
||||
const netarray_t*array_type = dynamic_cast<const netarray_t*> (ntype);
|
||||
ivl_type_t elem_type = array_type->element_type();
|
||||
|
||||
init_val = init_->elaborate_expr(des, scope, elem_type, flags);
|
||||
init_val = init_->elaborate_expr(des, scope, array_type, flags);
|
||||
}
|
||||
|
||||
NetENew*tmp = new NetENew(ntype, size, init_val);
|
||||
|
|
@ -5565,6 +5631,10 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode)
|
|||
|
||||
NetExpr* PENumber::elaborate_expr(Design*des, NetScope*, ivl_type_t ntype, unsigned) const
|
||||
{
|
||||
// Icarus allows dynamic arrays to be initialised with a single value.
|
||||
if (const netdarray_t*array_type = dynamic_cast<const netdarray_t*> (ntype))
|
||||
ntype = array_type->element_type();
|
||||
|
||||
const netvector_t*use_type = dynamic_cast<const netvector_t*> (ntype);
|
||||
if (use_type == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
|
|
@ -5611,7 +5681,7 @@ NetEConst* PENumber::elaborate_expr(Design*, NetScope*,
|
|||
unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
|
||||
{
|
||||
expr_type_ = IVL_VT_BOOL;
|
||||
expr_width_ = text_? verinum(text_).len() : 0;
|
||||
expr_width_ = text_ ? verinum(text_).len() : 0;
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = false;
|
||||
|
||||
|
|
@ -5671,7 +5741,6 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
} else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) {
|
||||
expr_type_ = IVL_VT_LOGIC;
|
||||
} else {
|
||||
ivl_assert(*this, tru_type == fal_type);
|
||||
expr_type_ = tru_type;
|
||||
}
|
||||
if (expr_type_ == IVL_VT_REAL) {
|
||||
|
|
@ -6067,7 +6136,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
tmp->set_line(*this);
|
||||
}
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
break;
|
||||
|
||||
case '&': // Reduction AND
|
||||
|
|
@ -6085,7 +6154,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
tmp = new NetEUReduce(op_, ip);
|
||||
tmp->set_line(*this);
|
||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
break;
|
||||
|
||||
case '~':
|
||||
|
|
|
|||
72
elab_lval.cc
72
elab_lval.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -75,15 +75,8 @@
|
|||
*/
|
||||
NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool, bool) const
|
||||
{
|
||||
NetNet*ll = 0;
|
||||
if (ll == 0) {
|
||||
cerr << get_fileline() << ": Assignment l-value too complex."
|
||||
<< endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetAssign_*lv = new NetAssign_(ll);
|
||||
return lv;
|
||||
cerr << get_fileline() << ": Assignment l-value too complex." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -138,6 +131,9 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* A concatenation is always unsigned. */
|
||||
tmp->set_signed(false);
|
||||
|
||||
/* Link the new l-value to the previous one. */
|
||||
NetAssign_*last = tmp;
|
||||
while (last->more)
|
||||
|
|
@ -287,13 +283,13 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
}
|
||||
|
||||
// We are processing the tail of a string of names. For
|
||||
// example, the verilog may be "a.b.c", so we are processing
|
||||
// example, the Verilog may be "a.b.c", so we are processing
|
||||
// "c" at this point. (Note that if method_name is not nil,
|
||||
// then this is "a.b.c.method" and "a.b.c" is a struct or class.)
|
||||
const name_component_t&name_tail = path_.back();
|
||||
|
||||
// Use the last index to determine what kind of select
|
||||
// (bit/part/etc) we are processing. For example, the verilog
|
||||
// (bit/part/etc) we are processing. For example, the Verilog
|
||||
// may be "a.b.c[1][2][<index>]". All but the last index must
|
||||
// be simple expressions, only the <index> may be a part
|
||||
// select etc., so look at it to determine how we will be
|
||||
|
|
@ -399,6 +395,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
/* No select expressions. */
|
||||
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
lv->set_signed(reg->get_signed());
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
|
@ -485,7 +482,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
|||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Found initialzers for property " << class_type->get_prop_name(pidx) << endl;
|
||||
<< "Found initializers for property " << class_type->get_prop_name(pidx) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -543,8 +540,6 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned array_need_words = reg->unpacked_count();
|
||||
|
||||
// Make sure there are enough indices to address an array element.
|
||||
const index_component_t&index_head = name_tail.index.front();
|
||||
if (index_head.sel == index_component_t::SEL_PART) {
|
||||
|
|
@ -562,7 +557,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
|||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, reg->unpacked_dimensions(),
|
||||
false, array_need_words,
|
||||
false,
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
|
@ -689,20 +684,24 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
unsigned long lwid;
|
||||
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
|
||||
ivl_assert(*this, rcl);
|
||||
cerr << get_fileline() << ": warning: L-value packed array "
|
||||
<< "select of " << reg->name();
|
||||
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
||||
cerr << " has an undefined index." << endl;
|
||||
|
||||
if (warn_ob_select) {
|
||||
cerr << get_fileline()
|
||||
<< ": warning: L-value packed array select of "
|
||||
<< reg->name();
|
||||
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
||||
cerr << " has an undefined index." << endl;
|
||||
}
|
||||
lv->set_part(new NetEConst(verinum(verinum::Vx)), lwid);
|
||||
return true;
|
||||
// The index is undefined and this is a bit select.
|
||||
} else {
|
||||
cerr << get_fileline() << ": warning: L-value bit select of "
|
||||
<< reg->name();
|
||||
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
||||
cerr << " has an undefined index." << endl;
|
||||
|
||||
if (warn_ob_select) {
|
||||
cerr << get_fileline()
|
||||
<< ": warning: L-value bit select of "
|
||||
<< reg->name();
|
||||
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
||||
cerr << " has an undefined index." << endl;
|
||||
}
|
||||
lv->set_part(new NetEConst(verinum(verinum::Vx)), 1);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -799,12 +798,10 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
// Constant bit select that does something useful.
|
||||
long loff = reg->sb_to_idx(prefix_indices,lsb);
|
||||
|
||||
if (loff < 0 || loff >= (long)reg->vector_width()) {
|
||||
cerr << get_fileline() << ": error: bit select "
|
||||
if (warn_ob_select && (loff < 0 || loff >= (long)reg->vector_width())) {
|
||||
cerr << get_fileline() << ": warning: bit select "
|
||||
<< reg->name() << "[" <<lsb<<"]"
|
||||
<< " is out of range." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
|
|
@ -870,10 +867,13 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
|||
ivl_assert(*this, reg);
|
||||
|
||||
if (! parts_defined_flag) {
|
||||
cerr << get_fileline() << ": warning: L-value part select of "
|
||||
<< reg->name();
|
||||
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
||||
cerr << " has an undefined index." << endl;
|
||||
if (warn_ob_select) {
|
||||
cerr << get_fileline()
|
||||
<< ": warning: L-value part select of "
|
||||
<< reg->name();
|
||||
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
||||
cerr << " has an undefined index." << endl;
|
||||
}
|
||||
// Use a width of two here so we can distinguish between an
|
||||
// undefined bit or part select.
|
||||
lv->set_part(new NetEConst(verinum(verinum::Vx)), 2);
|
||||
|
|
@ -936,11 +936,11 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
|||
}
|
||||
|
||||
/* If the part select extends beyond the extremes of the
|
||||
variable, then report an error. Note that loff is
|
||||
variable, then output a warning. Note that loff is
|
||||
converted to normalized form so is relative the
|
||||
variable pins. */
|
||||
|
||||
if (loff < 0 || moff >= (long)reg->vector_width()) {
|
||||
if (warn_ob_select && (loff < 0 || moff >= (long)reg->vector_width())) {
|
||||
cerr << get_fileline() << ": warning: Part select "
|
||||
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
||||
<< " is out of range." << endl;
|
||||
|
|
|
|||
89
elab_net.cc
89
elab_net.cc
|
|
@ -328,39 +328,66 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
|||
return false;
|
||||
}
|
||||
|
||||
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
|
||||
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
|
||||
/* Detect reversed indices of a part select. */
|
||||
if (lidx_tmp > midx_tmp) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< sig->name() << "[" << msb << ":"
|
||||
<< lsb << "] indices reversed." << endl;
|
||||
cerr << get_fileline() << ": : Did you mean "
|
||||
<< sig->name() << "[" << lsb << ":"
|
||||
<< msb << "]?" << endl;
|
||||
long tmp = midx_tmp;
|
||||
midx_tmp = lidx_tmp;
|
||||
lidx_tmp = tmp;
|
||||
des->errors += 1;
|
||||
}
|
||||
if (prefix_indices.size()+1 < sig->packed_dims().size()) {
|
||||
// Here we have a slice that doesn't have enough indices
|
||||
// to get to a single slice. For example:
|
||||
// wire [9:0][5:1] foo
|
||||
// ... foo[4:3] ...
|
||||
// Make this work by finding the indexed slices and
|
||||
// creating a generated slice that spans the whole
|
||||
// range.
|
||||
long loff, moff;
|
||||
unsigned long lwid, mwid;
|
||||
bool lrc;
|
||||
lrc = sig->sb_to_slice(prefix_indices, lsb, loff, lwid);
|
||||
ivl_assert(*this, lrc);
|
||||
lrc = sig->sb_to_slice(prefix_indices, msb, moff, mwid);
|
||||
ivl_assert(*this, lrc);
|
||||
ivl_assert(*this, lwid == mwid);
|
||||
|
||||
/* Warn about a part select that is out of range. */
|
||||
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
|
||||
cerr << get_fileline() << ": warning: Part select "
|
||||
<< sig->name();
|
||||
if (sig->unpacked_dimensions() > 0) {
|
||||
cerr << "[]";
|
||||
if (moff > loff) {
|
||||
lidx = loff;
|
||||
midx = moff + mwid - 1;
|
||||
} else {
|
||||
lidx = moff;
|
||||
midx = loff + lwid - 1;
|
||||
}
|
||||
cerr << "[" << msb << ":" << lsb
|
||||
<< "] is out of range." << endl;
|
||||
}
|
||||
/* This is completely out side the signal so just skip it. */
|
||||
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
|
||||
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
|
||||
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
/* Detect reversed indices of a part select. */
|
||||
if (lidx_tmp > midx_tmp) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< sig->name() << "[" << msb << ":"
|
||||
<< lsb << "] indices reversed." << endl;
|
||||
cerr << get_fileline() << ": : Did you mean "
|
||||
<< sig->name() << "[" << lsb << ":"
|
||||
<< msb << "]?" << endl;
|
||||
long tmp = midx_tmp;
|
||||
midx_tmp = lidx_tmp;
|
||||
lidx_tmp = tmp;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
/* Warn about a part select that is out of range. */
|
||||
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
|
||||
cerr << get_fileline() << ": warning: Part select "
|
||||
<< sig->name();
|
||||
if (sig->unpacked_dimensions() > 0) {
|
||||
cerr << "[]";
|
||||
}
|
||||
cerr << "[" << msb << ":" << lsb
|
||||
<< "] is out of range." << endl;
|
||||
}
|
||||
/* This is completely out side the signal so just skip it. */
|
||||
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -630,7 +657,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
path_tail.index, sig->unpacked_dimensions(),
|
||||
true, sig->unpacked_count(),
|
||||
true,
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
|
|
|||
113
elab_scope.cc
113
elab_scope.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -54,6 +54,15 @@
|
|||
# include <cassert>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope)
|
||||
{
|
||||
scope->time_unit(pscope->time_unit);
|
||||
scope->time_precision(pscope->time_precision);
|
||||
scope->time_from_timescale(pscope->has_explicit_timescale());
|
||||
des->set_precision(pscope->time_precision);
|
||||
}
|
||||
|
||||
typedef map<perm_string,LexicalScope::param_expr_t>::const_iterator mparm_it_t;
|
||||
|
||||
static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
|
||||
|
|
@ -158,8 +167,7 @@ static void collect_scope_specparams_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
/*
|
||||
* Elaborate the enumeration into the given scope. If scope==0, then
|
||||
* the enumeration goes into $root instead of a scope.
|
||||
* Elaborate the enumeration into the given scope.
|
||||
*/
|
||||
static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
enum_type_t*enum_type)
|
||||
|
|
@ -184,10 +192,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
enum_type);
|
||||
|
||||
use_enum->set_line(enum_type->li);
|
||||
if (scope)
|
||||
scope->add_enumeration_set(enum_type, use_enum);
|
||||
else
|
||||
des->add_enumeration_set(enum_type, use_enum);
|
||||
scope->add_enumeration_set(enum_type, use_enum);
|
||||
|
||||
size_t name_idx = 0;
|
||||
// Find the enumeration width.
|
||||
|
|
@ -355,10 +360,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value);
|
||||
if (scope)
|
||||
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
||||
else
|
||||
rc_flag &= des->add_enumeration_name(use_enum, cur->name);
|
||||
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
||||
|
||||
if (! rc_flag) {
|
||||
cerr << use_enum->get_fileline()
|
||||
|
|
@ -388,15 +390,6 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
void elaborate_rootscope_enumerations(Design*des)
|
||||
{
|
||||
for (set<enum_type_t*>::const_iterator cur = pform_enum_sets.begin()
|
||||
; cur != pform_enum_sets.end() ; ++ cur) {
|
||||
enum_type_t*curp = *cur;
|
||||
elaborate_scope_enumeration(des, 0, curp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the pclass includes an implicit and explicit constructor, then
|
||||
* merge the implicit constructor into the explicit constructor as
|
||||
|
|
@ -500,7 +493,6 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
|||
|
||||
netclass_t*use_base_class = 0;
|
||||
if (base_class) {
|
||||
ivl_assert(*pclass, scope);
|
||||
use_base_class = scope->find_class(base_class->name);
|
||||
if (use_base_class == 0) {
|
||||
cerr << pclass->get_fileline() << ": error: "
|
||||
|
|
@ -516,13 +508,15 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
|||
use_type->save_elaborated_type = use_class;
|
||||
|
||||
// Class scopes have no parent scope, because references are
|
||||
// not allowed to escape a class method.
|
||||
// not allowed to escape a class method. But they are allowed
|
||||
// to reference the compilation unit scope.
|
||||
NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()),
|
||||
NetScope::CLASS);
|
||||
NetScope::CLASS, scope->unit());
|
||||
class_scope->set_line(pclass);
|
||||
class_scope->set_class_def(use_class);
|
||||
use_class->set_class_scope(class_scope);
|
||||
use_class->set_definition_scope(scope);
|
||||
set_scope_timescale(des, class_scope, pclass);
|
||||
|
||||
// Collect the properties, elaborate them, and add them to the
|
||||
// elaborated class definition.
|
||||
|
|
@ -576,12 +570,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
|||
cur->second->elaborate_scope(des, method_scope);
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
scope->add_class(use_class);
|
||||
|
||||
} else {
|
||||
des->add_class(use_class, pclass);
|
||||
}
|
||||
scope->add_class(use_class);
|
||||
}
|
||||
|
||||
static void elaborate_scope_classes(Design*des, NetScope*scope,
|
||||
|
|
@ -593,18 +582,6 @@ static void elaborate_scope_classes(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
void elaborate_rootscope_classes(Design*des)
|
||||
{
|
||||
if (pform_classes.empty())
|
||||
return;
|
||||
|
||||
for (map<perm_string,PClass*>::iterator cur = pform_classes.begin()
|
||||
; cur != pform_classes.end() ; ++ cur) {
|
||||
blend_class_constructors(cur->second);
|
||||
elaborate_scope_class(des, 0, cur->second);
|
||||
}
|
||||
}
|
||||
|
||||
static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,
|
||||
const Module::replace_t&replacements)
|
||||
{
|
||||
|
|
@ -654,9 +631,6 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task)
|
|||
task_scope->is_auto(task->is_auto());
|
||||
task_scope->set_line(task);
|
||||
|
||||
if (scope==0)
|
||||
des->add_root_task(task_scope, task);
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << task->get_fileline() << ": elaborate_scope_task: "
|
||||
<< "Elaborate task scope " << scope_path(task_scope) << endl;
|
||||
|
|
@ -719,9 +693,6 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task)
|
|||
task_scope->is_auto(task->is_auto());
|
||||
task_scope->set_line(task);
|
||||
|
||||
if (scope==0)
|
||||
des->add_root_task(task_scope, task);
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << task->get_fileline() << ": elaborate_scope_func: "
|
||||
<< "Elaborate task scope " << scope_path(task_scope) << endl;
|
||||
|
|
@ -777,28 +748,6 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope,
|
|||
|
||||
}
|
||||
|
||||
void elaborate_rootscope_tasks(Design*des)
|
||||
{
|
||||
for (map<perm_string,PTaskFunc*>::iterator cur = pform_tasks.begin()
|
||||
; cur != pform_tasks.end() ; ++ cur) {
|
||||
|
||||
if (PTask*task = dynamic_cast<PTask*> (cur->second)) {
|
||||
elaborate_scope_task(des, 0, task);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PFunction*func = dynamic_cast<PFunction*>(cur->second)) {
|
||||
elaborate_scope_func(des, 0, func);
|
||||
continue;
|
||||
}
|
||||
|
||||
cerr << cur->second->get_fileline() << ": internal error: "
|
||||
<< "elabortae_rootscope_tasks does not understand "
|
||||
<< "this object," << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
class generate_schemes_work_item_t : public elaborator_work_item_t {
|
||||
public:
|
||||
generate_schemes_work_item_t(Design*des__, NetScope*scope, Module*mod)
|
||||
|
|
@ -1155,7 +1104,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
container->genvar_tmp_val = genvar;
|
||||
delete step;
|
||||
delete test_ex;
|
||||
test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
test_ex = elab_and_eval(des, container, loop_test, -1, true);
|
||||
test = dynamic_cast<NetEConst*>(test_ex);
|
||||
assert(test);
|
||||
}
|
||||
|
|
@ -1714,6 +1663,10 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
|||
<< "." << endl;
|
||||
}
|
||||
|
||||
struct attrib_list_t*attrib_list;
|
||||
unsigned attrib_list_n = 0;
|
||||
attrib_list = evaluate_attributes(attributes, attrib_list_n, des, sc);
|
||||
|
||||
// Run through the module instances, and make scopes out of
|
||||
// them. Also do parameter overrides that are done on the
|
||||
// instantiation line.
|
||||
|
|
@ -1740,7 +1693,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
|||
// Create the new scope as a MODULE with my name. Note
|
||||
// that if this is a nested module, mark it thus so that
|
||||
// scope searches will continue into the parent scope.
|
||||
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE,
|
||||
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE, 0,
|
||||
bound_type_? true : false,
|
||||
mod->program_block,
|
||||
mod->is_interface);
|
||||
|
|
@ -1748,13 +1701,12 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
|||
get_lineno(), mod->get_lineno());
|
||||
my_scope->set_module_name(mod->mod_name());
|
||||
|
||||
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
|
||||
my_scope->attribute(attrib_list[adx].key, attrib_list[adx].val);
|
||||
|
||||
instances[idx] = my_scope;
|
||||
|
||||
// Set time units and precision.
|
||||
my_scope->time_unit(mod->time_unit);
|
||||
my_scope->time_precision(mod->time_precision);
|
||||
my_scope->time_from_timescale(mod->time_from_timescale);
|
||||
des->set_precision(mod->time_precision);
|
||||
set_scope_timescale(des, my_scope, mod);
|
||||
|
||||
// Look for module parameter replacements. The "replace" map
|
||||
// maps parameter name to replacement expression that is
|
||||
|
|
@ -1793,8 +1745,12 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
|||
// so the mapping into the replace list is much easier.
|
||||
if (parms_) {
|
||||
assert(overrides_ == 0);
|
||||
for (unsigned jdx = 0 ; jdx < nparms_ ; jdx += 1)
|
||||
replace[parms_[jdx].name] = parms_[jdx].parm;
|
||||
for (unsigned jdx = 0 ; jdx < nparms_ ; jdx += 1) {
|
||||
// No expression means that the parameter is not
|
||||
// replaced.
|
||||
if (parms_[jdx].parm)
|
||||
replace[parms_[jdx].name] = parms_[jdx].parm;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1806,6 +1762,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
|||
mod->elaborate_scope(des, my_scope, replace);
|
||||
|
||||
}
|
||||
delete[]attrib_list;
|
||||
|
||||
/* Stash the instance array of scopes into the parent
|
||||
scope. Later elaboration passes will use this vector to
|
||||
|
|
|
|||
84
elab_sig.cc
84
elab_sig.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -715,16 +715,23 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
|
|||
continue;
|
||||
}
|
||||
|
||||
// If the port has a default expression that can be used
|
||||
// as a value when the caller doesn't bind, then
|
||||
// elaborate that expression here. This expression
|
||||
// should evaluate down do a constant.
|
||||
// If the port has a default expression, elaborate
|
||||
// that expression here.
|
||||
if (ports_->at(idx).defe != 0) {
|
||||
tmp_def = elab_and_eval(des, scope, ports_->at(idx).defe, -1, true);
|
||||
if (tmp_def==0) {
|
||||
cerr << get_fileline() << ": error: Unable to evaluate "
|
||||
<< *ports_->at(idx).defe
|
||||
<< " as a port default (constant) expression." << endl;
|
||||
if (tmp->port_type() == NetNet::PINPUT) {
|
||||
tmp_def = elab_and_eval(des, scope, ports_->at(idx).defe,
|
||||
-1, scope->need_const_func());
|
||||
if (tmp_def == 0) {
|
||||
cerr << get_fileline()
|
||||
<< ": error: Unable to evaluate "
|
||||
<< *ports_->at(idx).defe
|
||||
<< " as a port default expression." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
} else {
|
||||
cerr << get_fileline() << ": sorry: Default arguments "
|
||||
"for subroutine output or inout ports are not "
|
||||
"yet supported." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -969,6 +976,23 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
}
|
||||
|
||||
if (port_set_ || net_set_) {
|
||||
|
||||
if (warn_implicit_dimensions
|
||||
&& port_set_ && net_set_
|
||||
&& net_.empty() && !port_.empty()) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "var/net declaration of " << basename()
|
||||
<< " inherits dimensions from port declaration." << endl;
|
||||
}
|
||||
|
||||
if (warn_implicit_dimensions
|
||||
&& port_set_ && net_set_
|
||||
&& port_.empty() && !net_.empty()) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "Port declaration of " << basename()
|
||||
<< " inherits dimensions from var/net." << endl;
|
||||
}
|
||||
|
||||
bool bad_range = false;
|
||||
vector<netrange_t> plist, nlist;
|
||||
/* If they exist get the port definition MSB and LSB */
|
||||
|
|
@ -1161,6 +1185,14 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
NetLogic*pull = 0;
|
||||
if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Generate a SUPPLY pull for the ";
|
||||
if (wtype == NetNet::SUPPLY0) cerr << "supply0";
|
||||
else cerr << "supply1";
|
||||
cerr << " net." << endl;
|
||||
}
|
||||
|
||||
NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1)
|
||||
? NetLogic::PULLUP
|
||||
: NetLogic::PULLDOWN;
|
||||
|
|
@ -1171,14 +1203,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
pull->pin(0).drive1(IVL_DR_SUPPLY);
|
||||
des->add_node(pull);
|
||||
wtype = NetNet::WIRE;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Generate a SUPPLY pull for the ";
|
||||
if (wtype == NetNet::SUPPLY0) cerr << "supply0";
|
||||
else cerr << "supply1";
|
||||
cerr << " net." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1309,27 +1333,3 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
||||
void Design::root_elaborate_sig(void)
|
||||
{
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++ cur) {
|
||||
|
||||
netclass_t*cur_class = cur->second;
|
||||
PClass*cur_pclass = class_to_pclass_[cur_class];
|
||||
|
||||
cur_class->elaborate_sig(this, cur_pclass);
|
||||
}
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << cur->second->get_fileline() << ": root_elaborate_sig: "
|
||||
<< "Elaborate_sig for root task/func " << scope_path(cur->first) << endl;
|
||||
}
|
||||
|
||||
cur->second->elaborate_sig(this, cur->first);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
29
elab_type.cc
29
elab_type.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2017 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
|
||||
|
|
@ -17,11 +17,13 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "PExpr.h"
|
||||
# include "pform_types.h"
|
||||
# include "netlist.h"
|
||||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netenum.h"
|
||||
# include "netqueue.h"
|
||||
# include "netparray.h"
|
||||
# include "netscalar.h"
|
||||
# include "netstruct.h"
|
||||
|
|
@ -76,13 +78,12 @@ static void elaborate_array_ranges(Design*des, NetScope*scope,
|
|||
*/
|
||||
ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope)
|
||||
{
|
||||
ivl_assert(*this, scope);
|
||||
Definitions*use_definitions = scope;
|
||||
if (use_definitions == 0)
|
||||
use_definitions = des;
|
||||
|
||||
map<Definitions*,ivl_type_s*>::iterator pos = cache_type_elaborate_.lower_bound(use_definitions);
|
||||
if (pos->first == use_definitions)
|
||||
return pos->second;
|
||||
if (pos != cache_type_elaborate_.end() && pos->first == use_definitions)
|
||||
return pos->second;
|
||||
|
||||
ivl_type_s*tmp = elaborate_type_raw(des, scope);
|
||||
cache_type_elaborate_.insert(pos, pair<NetScope*,ivl_type_s*>(scope, tmp));
|
||||
|
|
@ -145,13 +146,13 @@ ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*) const
|
|||
* available at the right time. At that time, the netenum_t* object is
|
||||
* stashed in the scope so that I can retrieve it here.
|
||||
*/
|
||||
ivl_type_s* enum_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
||||
ivl_type_s* enum_type_t::elaborate_type_raw(Design*, NetScope*scope) const
|
||||
{
|
||||
ivl_assert(*this, scope);
|
||||
ivl_type_s*tmp = scope->enumeration_for_key(this);
|
||||
if (tmp) return tmp;
|
||||
|
||||
tmp = des->enumeration_for_key(this);
|
||||
if (tmp == 0 && scope->unit()) {
|
||||
tmp = scope->unit()->enumeration_for_key(this);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -245,6 +246,16 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
|||
return res;
|
||||
}
|
||||
|
||||
// Special case: if the dimension is null:nil. this is a queue.
|
||||
if (cur->second==0 && dynamic_cast<PENull*>(cur->first)) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "SV queues inside classes are not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
|
||||
ivl_type_s*res = new netqueue_t(btype);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<netrange_t> dimensions;
|
||||
bool bad_range = evaluate_ranges(des, scope, dimensions, *dims);
|
||||
|
||||
|
|
|
|||
874
elaborate.cc
874
elaborate.cc
File diff suppressed because it is too large
Load Diff
22
emit.cc
22
emit.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -123,6 +123,12 @@ bool NetFF::emit_node(struct target_t*tgt) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NetLatch::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_latch(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetLiteral::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->net_literal(this);
|
||||
|
|
@ -504,26 +510,12 @@ int Design::emit(struct target_t*tgt) const
|
|||
if (tgt->start_design(this) == false)
|
||||
return -2;
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator scope = root_tasks_.begin()
|
||||
; scope != root_tasks_.end() ; ++ scope) {
|
||||
scope->first->emit_scope(tgt);
|
||||
scope->first->emit_defs(tgt);
|
||||
}
|
||||
|
||||
// enumerate package scopes
|
||||
for (map<perm_string,NetScope*>::const_iterator scope = packages_.begin()
|
||||
; scope != packages_.end() ; ++ scope) {
|
||||
scope->second->emit_scope(tgt);
|
||||
}
|
||||
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++cur) {
|
||||
const NetScope*use_scope = cur->second->class_scope();
|
||||
cur->second->emit_scope(tgt);
|
||||
tgt->class_type(use_scope, cur->second);
|
||||
cur->second->emit_defs(tgt);
|
||||
}
|
||||
|
||||
// enumerate root scopes
|
||||
for (list<NetScope*>::const_iterator scope = root_scopes_.begin()
|
||||
; scope != root_scopes_.end(); ++ scope ) {
|
||||
|
|
|
|||
393
eval_tree.cc
393
eval_tree.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2018 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
|
||||
|
|
@ -545,7 +545,7 @@ NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag, const NetExpr*le, const NetE
|
|||
bool flag = get_real_arguments(le, re, lval, rval);
|
||||
if (! flag) return 0;
|
||||
|
||||
verinum result(((lval == rval) ^ ne_flag) ?
|
||||
verinum result(((lval == rval) != ne_flag) ?
|
||||
verinum::V1 : verinum::V0, 1);
|
||||
NetEConst*res = new NetEConst(result);
|
||||
ivl_assert(*this, res);
|
||||
|
|
@ -570,11 +570,11 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*r
|
|||
const verinum::V ne_res = ne_flag? verinum::V1 : verinum::V0;
|
||||
|
||||
verinum::V res = eq_res;
|
||||
unsigned top = lv.len();
|
||||
if (rv.len() < top)
|
||||
top = rv.len();
|
||||
|
||||
for (unsigned idx = 0 ; idx < top ; idx += 1) {
|
||||
// The two expressions should already be padded to the same size.
|
||||
ivl_assert(*this, lv.len() == rv.len());
|
||||
|
||||
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) {
|
||||
|
||||
bool x_bit_present = false;
|
||||
|
||||
|
|
@ -611,60 +611,6 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*r
|
|||
}
|
||||
}
|
||||
|
||||
if (res != verinum::Vx) {
|
||||
verinum::V lpad = verinum::V0;
|
||||
verinum::V rpad = verinum::V0;
|
||||
|
||||
if (lv.has_sign() && lv.get(lv.len()-1) == verinum::V1)
|
||||
lpad = verinum::V1;
|
||||
if (rv.has_sign() && rv.get(rv.len()-1) == verinum::V1)
|
||||
rpad = verinum::V1;
|
||||
|
||||
for (unsigned idx = top ; idx < lv.len() ; idx += 1)
|
||||
switch (lv.get(idx)) {
|
||||
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
res = verinum::Vx;
|
||||
break;
|
||||
|
||||
case verinum::V0:
|
||||
if (res != verinum::Vx && rpad != verinum::V0)
|
||||
res = ne_res;
|
||||
break;
|
||||
|
||||
case verinum::V1:
|
||||
if (res != verinum::Vx && rpad != verinum::V1)
|
||||
res = ne_res;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned idx = top ; idx < rv.len() ; idx += 1)
|
||||
switch (rv.get(idx)) {
|
||||
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
res = verinum::Vx;
|
||||
break;
|
||||
|
||||
case verinum::V0:
|
||||
if (res != verinum::Vx && lpad != verinum::V0)
|
||||
res = ne_res;
|
||||
break;
|
||||
|
||||
case verinum::V1:
|
||||
if (res != verinum::Vx && lpad != verinum::V1)
|
||||
res = ne_res;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NetEConst*result = new NetEConst(verinum(res, 1));
|
||||
ivl_assert(*this, result);
|
||||
return result;
|
||||
|
|
@ -681,41 +627,15 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr
|
|||
|
||||
verinum::V res = verinum::V1;
|
||||
|
||||
// Find the smallest argument length.
|
||||
unsigned cnt = lv.len();
|
||||
if (cnt > rv.len()) cnt = rv.len();
|
||||
// The two expressions should already be padded to the same size.
|
||||
ivl_assert(*this, lv.len() == rv.len());
|
||||
|
||||
// Check the common bits.
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
||||
if (lv.get(idx) != rv.get(idx)) {
|
||||
res = verinum::V0;
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_signed = lv.has_sign() && rv.has_sign();
|
||||
|
||||
// If the left value is longer check it against the pad bit.
|
||||
if (res == verinum::V1) {
|
||||
verinum::V pad = verinum::V0;
|
||||
if (is_signed) pad = rv.get(rv.len()-1);
|
||||
for (unsigned idx = cnt ; idx < lv.len() ; idx += 1)
|
||||
if (lv.get(idx) != pad) {
|
||||
res = verinum::V0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the right value is longer check it against the pad bit.
|
||||
if (res == verinum::V1) {
|
||||
verinum::V pad = verinum::V0;
|
||||
if (is_signed) pad = lv.get(lv.len()-1);
|
||||
for (unsigned idx = cnt ; idx < rv.len() ; idx += 1) {
|
||||
if (rv.get(idx) != pad)
|
||||
res = verinum::V0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ne_flag) {
|
||||
if (res == verinum::V0) res = verinum::V1;
|
||||
else res = verinum::V0;
|
||||
|
|
@ -726,6 +646,55 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr
|
|||
return result;
|
||||
}
|
||||
|
||||
NetEConst* NetEBComp::eval_weqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const
|
||||
{
|
||||
const NetEConst*lc = dynamic_cast<const NetEConst*>(le);
|
||||
const NetEConst*rc = dynamic_cast<const NetEConst*>(re);
|
||||
if (lc == 0 || rc == 0) return 0;
|
||||
|
||||
const verinum&lv = lc->value();
|
||||
const verinum&rv = rc->value();
|
||||
|
||||
const verinum::V eq_res = ne_flag ? verinum::V0 : verinum::V1;
|
||||
const verinum::V ne_res = ne_flag ? verinum::V1 : verinum::V0;
|
||||
|
||||
verinum::V res = eq_res;
|
||||
|
||||
// The two expressions should already be padded to the same size.
|
||||
ivl_assert(*this, lv.len() == rv.len());
|
||||
|
||||
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) {
|
||||
// An X or Z in the R-value matches any L-value.
|
||||
switch (rv.get(idx)) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// An X or Z in the L-value that is not matches by an R-value X/Z returns undefined.
|
||||
switch (lv.get(idx)) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
res = verinum::Vx;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// A hard (0/1) mismatch gives a not-equal result.
|
||||
if (rv.get(idx) != lv.get(idx)) {
|
||||
res = ne_res;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NetEConst*result = new NetEConst(verinum(res, 1));
|
||||
ivl_assert(*this, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||
{
|
||||
NetEConst*res = 0;
|
||||
|
|
@ -739,6 +708,10 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
res = eval_eqeq_(false, l, r);
|
||||
break;
|
||||
|
||||
case 'w': // Wild equality (==?)
|
||||
res = eval_weqeq_(false, l, r);
|
||||
break;
|
||||
|
||||
case 'G': // >=
|
||||
res = eval_gteq_(l, r);
|
||||
break;
|
||||
|
|
@ -755,6 +728,10 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
res = eval_eqeq_(true, l, r);
|
||||
break;
|
||||
|
||||
case 'W': // Wild not-equal (!=?)
|
||||
res = eval_weqeq_(true, l, r);
|
||||
break;
|
||||
|
||||
case '<': // Less than
|
||||
res = eval_less_(l, r);
|
||||
break;
|
||||
|
|
@ -1097,6 +1074,7 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
break;
|
||||
case 'r':
|
||||
lv.has_sign(false);
|
||||
// fallthrough
|
||||
case 'R':
|
||||
val = cast_to_width(lv >> shift, wid);
|
||||
break;
|
||||
|
|
@ -1548,6 +1526,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
|
|||
|
||||
case 'A':
|
||||
invert = true;
|
||||
// fallthrough
|
||||
case '&': {
|
||||
res = verinum::V1;
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
|
|
@ -1557,6 +1536,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
|
|||
|
||||
case 'N':
|
||||
invert = true;
|
||||
// fallthrough
|
||||
case '|': {
|
||||
res = verinum::V0;
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
|
|
@ -1566,6 +1546,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
|
|||
|
||||
case 'X':
|
||||
invert = true;
|
||||
// fallthrough
|
||||
case '^': {
|
||||
/* Reduction XOR. */
|
||||
unsigned ones = 0, unknown = 0;
|
||||
|
|
@ -1617,6 +1598,7 @@ NetExpr* NetECast::eval_arguments_(const NetExpr*ex) const
|
|||
res_val = cast_to_width(res_val, expr_width());
|
||||
res = new NetEConst(res_val);
|
||||
}
|
||||
// fallthrough
|
||||
case 'v':
|
||||
if (const NetECReal*val = dynamic_cast<const NetECReal*>(ex)) {
|
||||
verinum res_val(val->value().as_double(), false);
|
||||
|
|
@ -1931,15 +1913,111 @@ NetExpr* NetESFunc::evaluate_min_max_(ID id, const NetExpr*arg0_,
|
|||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_countbits_(const NetExpr* /*arg0*/,
|
||||
const NetExpr* /*arg1*/) const
|
||||
static void no_string_arg(const NetESFunc*info, unsigned arg_num)
|
||||
{
|
||||
return 0;
|
||||
cerr << info->get_fileline() << ": error: constant function "
|
||||
<< info->name() << "() does not support a string argument ("
|
||||
<< arg_num+1 << ")." << endl;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_countones_(const NetExpr* /*arg*/) const
|
||||
NetEConst* NetESFunc::evaluate_countbits_() const
|
||||
{
|
||||
return 0;
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(parms_[0]);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find which values need to be counted. */
|
||||
bool count_0 = false;
|
||||
bool count_1 = false;
|
||||
bool count_z = false;
|
||||
bool count_x = false;
|
||||
for (unsigned arg=1; arg < parms_.size(); ++arg) {
|
||||
const NetEConst*argi = dynamic_cast<const NetEConst*>(parms_[arg]);
|
||||
if (! argi) return 0;
|
||||
verinum check_for = argi->value();
|
||||
if (check_for.is_string()) {
|
||||
no_string_arg(this, arg);
|
||||
return 0;
|
||||
}
|
||||
switch (check_for[0]) {
|
||||
case verinum::V0:
|
||||
count_0 = true;
|
||||
break;
|
||||
case verinum::V1:
|
||||
count_1 = true;
|
||||
break;
|
||||
case verinum::Vz:
|
||||
count_z = true;
|
||||
break;
|
||||
case verinum::Vx:
|
||||
count_x = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search each bit of the vector looking for the values to
|
||||
* be counted. */
|
||||
int count = 0;
|
||||
for (unsigned bit=0; bit < value.len(); ++bit) {
|
||||
switch (value[bit]) {
|
||||
case verinum::V0:
|
||||
if (count_0) ++count;
|
||||
break;
|
||||
case verinum::V1:
|
||||
if (count_1) ++count;
|
||||
break;
|
||||
case verinum::Vz:
|
||||
if (count_z) ++count;
|
||||
break;
|
||||
case verinum::Vx:
|
||||
if (count_x) ++count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
verinum tmp (count, integer_width);
|
||||
tmp.has_sign(true);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_countones_(const NetExpr* arg) const
|
||||
{
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
int count = 0;
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned bit=0; bit < value.len(); ++bit) {
|
||||
if (value[bit] == verinum::V1) ++count;
|
||||
}
|
||||
|
||||
verinum tmp (count, integer_width);
|
||||
tmp.has_sign(true);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Get the total number of dimensions for the given expression. */
|
||||
|
|
@ -1962,19 +2040,92 @@ NetEConst* NetESFunc::evaluate_dimensions_(const NetExpr*arg) const
|
|||
return new NetEConst(verinum(verinum(res), integer_width));
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* /*arg*/) const
|
||||
NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* arg) const
|
||||
{
|
||||
return 0;
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
unsigned is_unknown = 1;
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value.is_defined()) is_unknown = 0;
|
||||
|
||||
verinum tmp (is_unknown, 1U);
|
||||
tmp.has_sign(false);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* /*arg*/) const
|
||||
static bool is_onehot(verinum&value, bool zero_is_okay)
|
||||
{
|
||||
return 0;
|
||||
bool found_a_one = false;
|
||||
|
||||
for (unsigned bit=0; bit < value.len(); ++bit) {
|
||||
if (value[bit] == verinum::V1) {
|
||||
if (found_a_one) return false;
|
||||
found_a_one = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no one bit was found return true if zero is okay. */
|
||||
if (zero_is_okay) found_a_one = true;
|
||||
return found_a_one;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* /*arg*/) const
|
||||
NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* arg) const
|
||||
{
|
||||
return 0;
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum tmp (is_onehot(value, false), 1U);
|
||||
tmp.has_sign(false);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* arg) const
|
||||
{
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum tmp (is_onehot(value, true), 1U);
|
||||
tmp.has_sign(false);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Get the number of unpacked dimensions for the given expression. */
|
||||
|
|
@ -2009,6 +2160,12 @@ static bool check_dimension(const NetExpr*dim_expr, long &dim)
|
|||
static bool get_array_info(const NetExpr*arg, long dim,
|
||||
long &left, long &right, bool&defer)
|
||||
{
|
||||
if (const NetEConstParam*param = dynamic_cast<const NetEConstParam*>(arg)) {
|
||||
assert(dim == 1);
|
||||
left = param->expr_width() - 1;
|
||||
right = 0;
|
||||
return false;
|
||||
}
|
||||
/* The argument must be a signal that has enough dimensions. */
|
||||
const NetESignal*esig = dynamic_cast<const NetESignal*>(arg);
|
||||
if (esig == 0) return true;
|
||||
|
|
@ -2140,7 +2297,7 @@ NetExpr* NetESFunc::evaluate_two_arg_(ID id, const NetExpr*arg0,
|
|||
{
|
||||
switch (id) {
|
||||
case CTBITS:
|
||||
return evaluate_countbits_(arg0, arg1);
|
||||
return evaluate_countbits_();
|
||||
/* The array functions are handled together. */
|
||||
case HIGH:
|
||||
case INCR:
|
||||
|
|
@ -2211,12 +2368,12 @@ NetESFunc::ID NetESFunc::built_in_id_() const
|
|||
built_in_func["$unpacked_dimensions" ] = UPDIMS;
|
||||
}
|
||||
|
||||
/* These are available in 1800-2009 and later. */
|
||||
/* This is available in 1800-2009 and later. */
|
||||
if (funcs_need_init && (generation_flag >= GN_VER2009)) {
|
||||
built_in_func["$countones" ] = CTONES;
|
||||
}
|
||||
|
||||
/* These are available in 1800-2012 and later. */
|
||||
/* This is available in 1800-2012 and later. */
|
||||
if (funcs_need_init && (generation_flag >= GN_VER2012)) {
|
||||
built_in_func["$countbits" ] = CTBITS;
|
||||
}
|
||||
|
|
@ -2243,7 +2400,7 @@ NetESFunc::ID NetESFunc::built_in_id_() const
|
|||
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
/* Get the ID for this system function if it is can be used as a
|
||||
/* Get the ID for this system function if it can be used as a
|
||||
* constant function. */
|
||||
ID id = built_in_id_();
|
||||
if (id == NOT_BUILT_IN) return 0;
|
||||
|
|
@ -2251,8 +2408,9 @@ NetExpr* NetESFunc::eval_tree()
|
|||
switch (parms_.size()) {
|
||||
case 1:
|
||||
if (! takes_nargs_(id, 1)) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< "() does not support a single argument." << endl;
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() does not support a single argument."
|
||||
<< endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
|
|
@ -2260,8 +2418,9 @@ NetExpr* NetESFunc::eval_tree()
|
|||
|
||||
case 2:
|
||||
if (! takes_nargs_(id, 2)) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< "() does not support two arguments." << endl;
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() does not support two arguments."
|
||||
<< endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
|
|
@ -2271,15 +2430,21 @@ NetExpr* NetESFunc::eval_tree()
|
|||
default:
|
||||
/* Check to see if the function was called correctly. */
|
||||
if (! takes_nargs_(id, parms_.size())) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< "() does not support " << parms_.size()
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() does not support " << parms_.size()
|
||||
<< " arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
// HERE: Need to add support for a multi argument $countbits().
|
||||
cerr << get_fileline() << ": sorry: functions with "
|
||||
<< parms_.size() << " arguments are not supported: "
|
||||
<< name_ << "()." << endl;
|
||||
if (id == CTBITS) {
|
||||
for (unsigned bit = 0; bit < parms_.size(); ++bit) {
|
||||
eval_expr(parms_[bit]);
|
||||
}
|
||||
return evaluate_countbits_();
|
||||
} else {
|
||||
cerr << get_fileline() << ": sorry: constant functions with "
|
||||
<< parms_.size() << " arguments are not supported: "
|
||||
<< name_ << "()." << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Martin Whitaker (icarus@martin-whitaker.me.uk)
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
# include "netlist.h"
|
||||
# include "functor.h"
|
||||
# include "compiler.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
/*
|
||||
* The exposenodes functor is primarily provided for use by the vlog95
|
||||
* target. To implement some LPM objects, it needs to take a bit or part
|
||||
* of one of the LPM inputs. If that input is not connected to a real
|
||||
* net in the design, we need to create a net at that point so that
|
||||
* there is something to which we can apply a bit or part select. This
|
||||
* has the effect of splitting the synthesised structure at that point.
|
||||
* Rather than creating a new net, we just look for a temporary net
|
||||
* created by the synthesis process (there should be at least one) and
|
||||
* reset its "local" flag. We also prepend another '_' to the synthetic
|
||||
* name to avoid name collisions when we recompile the vlog95 output
|
||||
* (because NetScope::local_symbol() doesn't actually check that the
|
||||
* name it generates is unique).
|
||||
*/
|
||||
|
||||
struct exposenodes_functor : public functor_t {
|
||||
|
||||
unsigned count;
|
||||
|
||||
virtual void lpm_mux(Design*des, NetMux*obj);
|
||||
virtual void lpm_part_select(Design*des, NetPartSelect*obj);
|
||||
virtual void lpm_substitute(Design*des, NetSubstitute*obj);
|
||||
};
|
||||
|
||||
static bool expose_nexus(Nexus*nex)
|
||||
{
|
||||
NetNet*sig = 0;
|
||||
for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
|
||||
// Don't expose nodes that are attached to constants
|
||||
if (dynamic_cast<NetConst*> (cur->get_obj()))
|
||||
return false;
|
||||
if (dynamic_cast<NetLiteral*> (cur->get_obj()))
|
||||
return false;
|
||||
|
||||
NetNet*cur_sig = dynamic_cast<NetNet*> (cur->get_obj());
|
||||
if (cur_sig == 0)
|
||||
continue;
|
||||
|
||||
if (!cur_sig->local_flag())
|
||||
return false;
|
||||
|
||||
sig = cur_sig;
|
||||
}
|
||||
assert(sig);
|
||||
ostringstream res;
|
||||
res << "_" << sig->name();
|
||||
sig->rename(lex_strings.make(res.str()));
|
||||
sig->local_flag(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The vlog95 target implements a wide mux as a hierarchy of 2:1 muxes,
|
||||
* picking off one bit of the select input at each level of the hierarchy.
|
||||
*/
|
||||
void exposenodes_functor::lpm_mux(Design*, NetMux*obj)
|
||||
{
|
||||
if (obj->sel_width() == 1)
|
||||
return;
|
||||
|
||||
if (expose_nexus(obj->pin_Sel().nexus()))
|
||||
count += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A VP part select is going to select a part from its input.
|
||||
*/
|
||||
void exposenodes_functor::lpm_part_select(Design*, NetPartSelect*obj)
|
||||
{
|
||||
if (obj->dir() != NetPartSelect::VP)
|
||||
return;
|
||||
|
||||
if (expose_nexus(obj->pin(1).nexus()))
|
||||
count += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A substitute is going to select one or two parts from the wider input signal.
|
||||
*/
|
||||
void exposenodes_functor::lpm_substitute(Design*, NetSubstitute*obj)
|
||||
{
|
||||
if (expose_nexus(obj->pin(1).nexus()))
|
||||
count += 1;
|
||||
}
|
||||
|
||||
void exposenodes(Design*des)
|
||||
{
|
||||
exposenodes_functor exposenodes;
|
||||
exposenodes.count = 0;
|
||||
if (verbose_flag) {
|
||||
cout << " ... Look for intermediate nodes" << endl << flush;
|
||||
}
|
||||
des->functor(&exposenodes);
|
||||
if (verbose_flag) {
|
||||
cout << " ... Exposed " << exposenodes.count
|
||||
<< " intermediate signals." << endl << flush;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2018 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
|
||||
|
|
@ -274,7 +274,18 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
|
||||
if (op_ == 'E' || op_ == 'N') {
|
||||
NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(),
|
||||
width, op_=='E'?NetCaseCmp::EEQ:NetCaseCmp::NEQ);
|
||||
width, op_=='E' ? NetCaseCmp::EEQ : NetCaseCmp::NEQ);
|
||||
gate->set_line(*this);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
des->add_node(gate);
|
||||
return osig;
|
||||
}
|
||||
|
||||
if (op_ == 'w' || op_ == 'W') {
|
||||
NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(),
|
||||
width, op_=='w' ? NetCaseCmp::WEQ : NetCaseCmp::WNE);
|
||||
gate->set_line(*this);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
|
|
@ -335,6 +346,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
// fallthrough
|
||||
case 'e': // ==
|
||||
connect(dev->pin_AEB(), osig->pin(0));
|
||||
break;
|
||||
|
|
@ -353,6 +365,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
// fallthrough
|
||||
case 'n': // !=
|
||||
connect(dev->pin_ANEB(), osig->pin(0));
|
||||
break;
|
||||
|
|
@ -733,12 +746,18 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
}
|
||||
}
|
||||
|
||||
if (flag == false) return 0;
|
||||
if (flag == false) {
|
||||
delete[]tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_assert(*this, data_type != IVL_VT_NO_TYPE);
|
||||
|
||||
/* If this is a replication of zero just return 0. */
|
||||
if (expr_width() == 0) return 0;
|
||||
if (expr_width() == 0) {
|
||||
delete[]tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make a NetNet object to carry the output vector. */
|
||||
perm_string path = scope->local_symbol();
|
||||
|
|
@ -1341,6 +1360,7 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root)
|
|||
if (nset && (nset->size() > 0)) {
|
||||
NetEvent*ev = new NetEvent(scope->local_symbol());
|
||||
ev->set_line(*root);
|
||||
ev->local_flag(true);
|
||||
|
||||
NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(),
|
||||
ev, NetEvProbe::ANYEDGE,
|
||||
|
|
|
|||
20
functor.cc
20
functor.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2016 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
|
||||
|
|
@ -78,6 +78,10 @@ void functor_t::lpm_ff(Design*, NetFF*)
|
|||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_latch(Design*, NetLatch*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_logic(Design*, NetLogic*)
|
||||
{
|
||||
}
|
||||
|
|
@ -102,6 +106,10 @@ void functor_t::sign_extend(Design*, NetSignExtend*)
|
|||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_substitute(Design*, NetSubstitute*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_ureduce(Design*, NetUReduce*)
|
||||
{
|
||||
}
|
||||
|
|
@ -215,6 +223,11 @@ void NetFF::functor_node(Design*des, functor_t*fun)
|
|||
fun->lpm_ff(des, this);
|
||||
}
|
||||
|
||||
void NetLatch::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_latch(des, this);
|
||||
}
|
||||
|
||||
void NetLiteral::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_literal(des, this);
|
||||
|
|
@ -255,6 +268,11 @@ void NetSignExtend::functor_node(Design*des, functor_t*fun)
|
|||
fun->sign_extend(des, this);
|
||||
}
|
||||
|
||||
void NetSubstitute::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_substitute(des, this);
|
||||
}
|
||||
|
||||
void NetUReduce::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_ureduce(des, this);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_functor_H
|
||||
#define IVL_functor_H
|
||||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -75,6 +75,9 @@ struct functor_t {
|
|||
/* This method is called for each FF in the design. */
|
||||
virtual void lpm_ff(class Design*des, class NetFF*);
|
||||
|
||||
/* This method is called for each LATCH in the design. */
|
||||
virtual void lpm_latch(class Design*des, class NetLatch*);
|
||||
|
||||
/* Handle LPM combinational logic devices. */
|
||||
virtual void lpm_logic(class Design*des, class NetLogic*);
|
||||
|
||||
|
|
@ -89,6 +92,9 @@ struct functor_t {
|
|||
/* This method is called for each power. */
|
||||
virtual void lpm_pow(class Design*des, class NetPow*);
|
||||
|
||||
/* This method is called for each part substitute. */
|
||||
virtual void lpm_substitute(class Design*des, class NetSubstitute*);
|
||||
|
||||
/* This method is called for each unary reduction gate. */
|
||||
virtual void lpm_ureduce(class Design*des, class NetUReduce*);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
.TH iverilog-vpi 1 "April 17th, 2009" "" "Version %M.%m.%n %E"
|
||||
.TH iverilog-vpi 1 "Jan 29th, 2017" "" "Version %M.%n%E"
|
||||
.SH NAME
|
||||
iverilog-vpi - Compile front end for VPI modules
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B iverilog-vpi
|
||||
[\-\-name=\fIname\fP]
|
||||
[options]
|
||||
\fIsourcefile\fP...
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
|
@ -15,9 +15,9 @@ list of C or C++ source files, and generates as output a linked VPI
|
|||
module. See the \fBvvp\fP(1) man page for a description of how the
|
||||
linked module is loaded by a simulation.
|
||||
|
||||
The output is named after the first source file. For example, if the
|
||||
first source file is named \fIfoo.c\fP, the output becomes
|
||||
\fIfoo.vpi\fP.
|
||||
By default the output is named after the first source file. For
|
||||
example, if the first source file is named \fIfoo.c\fP, the output
|
||||
becomes \fIfoo.vpi\fP.
|
||||
|
||||
.SH OPTIONS
|
||||
\fIiverilog\-vpi\fP accepts the following options:
|
||||
|
|
@ -26,10 +26,15 @@ first source file is named \fIfoo.c\fP, the output becomes
|
|||
Include the named library in the link of the VPI module. This allows
|
||||
VPI modules to further reference external libraries.
|
||||
|
||||
.TP 8
|
||||
.B -L\fIdirectory\fP
|
||||
Add \fIdirectory\fP to the list of directories that will be searched
|
||||
for library files.
|
||||
|
||||
.TP 8
|
||||
.B -I\fIdirectory\fP
|
||||
Add \fIdirectory\fP to the list of directories that will be search for
|
||||
header files.
|
||||
Add \fIdirectory\fP to the list of directories that will be searched
|
||||
for header files.
|
||||
|
||||
.TP 8
|
||||
.B -D\fIdefine\fP
|
||||
|
|
@ -41,46 +46,38 @@ Normally, the output VPI module will be named after the first source
|
|||
file passed to the command. This flag sets the name (without the .vpi
|
||||
suffix) of the output vpi module.
|
||||
|
||||
.TP 8
|
||||
.B --install-dir
|
||||
This flag causes the program to print the install directory for VPI
|
||||
modules, then exit. It is a convenience for makefiles or automated
|
||||
plug-in installers.
|
||||
|
||||
.TP 8
|
||||
.B --cflags, --ldflags and --ldlibs
|
||||
These flags provide compile time information.
|
||||
|
||||
.SH "PC-ONLY OPTIONS"
|
||||
|
||||
The PC port of \fIiverilog\-vpi\fP includes two special flags needed to
|
||||
support the more intractable development environment. These flags help
|
||||
the program locate parts that it needs.
|
||||
When built as a native Windows program (using the MinGW toolchain),
|
||||
by default \fIiverilog\-vpi\fP will attempt to locate the MinGW tools
|
||||
needed to compile a VPI module on the system path (as set by the PATH
|
||||
environment variable). As an alternative, the user may specify the
|
||||
location of the MinGW tools via the following option.
|
||||
|
||||
.TP 8
|
||||
.B -mingw=\fIpath\fP
|
||||
Tell the program the root of the Mingw compiler tool suite. The
|
||||
Tell the program the root of the MinGW compiler tool suite. The
|
||||
\fBvvp\fP runtime is compiled with this compiler, and this is the
|
||||
compiler that \fIiverilog\-vpi\fP expects to use to compile your source
|
||||
code. This is normally not needed, and if you do use it, it is only
|
||||
needed once. The compiler will save the \fIpath\fP in the registry for
|
||||
use later.
|
||||
compiler that \fIiverilog\-vpi\fP expects to use to compile your
|
||||
source code. If this option accompanies a list of files, it will
|
||||
apply to the current build only. If this option is provided on its
|
||||
own, \fIiverilog\-vpi\fP will save the \fIpath\fP in the registry
|
||||
and use that path in preference to the system path for subsequent
|
||||
operations, avoiding the need to specify it on the command line
|
||||
every time.
|
||||
|
||||
.SH "INFORMATIONAL OPTIONS"
|
||||
|
||||
\fIiverilog\-vpi\fP includes additional flags to let Makefile gurus
|
||||
peek at the configuration of the \fIiverilog\fP installation. This way,
|
||||
Makefiles can be written that handle complex VPI builds natively, and
|
||||
without hard-coding values that depend on the system and installation.
|
||||
If used at all, these options must be used one at a time, and without
|
||||
any other options or directives.
|
||||
|
||||
.TP 8
|
||||
.B -ivl=\fIpath\fP
|
||||
Set for the use during compilation the root if the Icarus Verilog
|
||||
install. This is the place where you installed Icarus Verilog when you
|
||||
ran the installer. This flag is also only needed once, and the path is
|
||||
stored in the registry for future use.
|
||||
|
||||
.SH "UNIX-ONLY OPTIONS"
|
||||
|
||||
The UNIX version of \fIiverilog\-vpi\fP includes additional flags to
|
||||
let Makefile gurus peek at the configuration of the \fIiverilog\fP
|
||||
installation. This way, Makefiles can be written that handle complex VPI
|
||||
builds natively, and without hard-coding values that depend on the
|
||||
system and installation. If used at all, these options must be
|
||||
used one at a time, and without any other options or directives.
|
||||
.B --install-dir
|
||||
Print the install directory for VPI modules.
|
||||
|
||||
.TP 8
|
||||
.B --cflags
|
||||
|
|
@ -95,11 +92,6 @@ Print the linker flags (LDFLAGS) needed to link a VPI module.
|
|||
.B --ldlibs
|
||||
Print the libraries (LDLIBS) needed to link a VPI module.
|
||||
|
||||
.TP 8
|
||||
.B -m32
|
||||
On 64bit systems that support it (and support vvp32) this flag
|
||||
requests a 32bit vpi binary instead of the default 64bit binary.
|
||||
|
||||
.P
|
||||
Example GNU makefile that takes advantage of these flags:
|
||||
.IP "" 4
|
||||
|
|
@ -123,12 +115,12 @@ Steve Williams (steve@icarus.com)
|
|||
|
||||
.SH SEE ALSO
|
||||
iverilog(1), vvp(1),
|
||||
.BR "<http://www.icarus.com/eda/verilog/>",
|
||||
.BR "<http://www.mingw.org>",
|
||||
.BR "<http://iverilog.icarus.com/>",
|
||||
.BR "<http://mingw-w64.yaxm.org/>",
|
||||
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 2002\-2009 Stephen Williams
|
||||
Copyright \(co 2002\-2017 Stephen Williams
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ CCSRC=
|
|||
CXSRC=
|
||||
OBJ=
|
||||
LIB=
|
||||
LIBDIR=
|
||||
OUT=
|
||||
INCOPT=
|
||||
DEFS=
|
||||
|
|
@ -81,6 +82,9 @@ do
|
|||
-l*) LIB="$LIB $parm"
|
||||
;;
|
||||
|
||||
-L*) LIBDIR="$LIBDIR $parm"
|
||||
;;
|
||||
|
||||
-I*) INCOPT="$INCOPT $parm"
|
||||
;;
|
||||
|
||||
|
|
@ -92,6 +96,11 @@ do
|
|||
exit;
|
||||
;;
|
||||
|
||||
--ccflags)
|
||||
echo "$CXXFLAGS"
|
||||
exit;
|
||||
;;
|
||||
|
||||
--ldflags)
|
||||
echo "$LDFLAGS"
|
||||
exit;
|
||||
|
|
@ -148,4 +157,4 @@ then
|
|||
fi
|
||||
|
||||
echo "Making $OUT from $OBJ..."
|
||||
exec $LD -o $OUT $LDFLAGS $OBJ $LIB $LDLIBS
|
||||
exec $LD -o $OUT $LDFLAGS $LIBDIR $OBJ $LIB $LDLIBS
|
||||
|
|
|
|||
5
ivl.def
5
ivl.def
|
|
@ -125,6 +125,7 @@ ivl_lpm_enable
|
|||
ivl_lpm_file
|
||||
ivl_lpm_lineno
|
||||
ivl_lpm_name
|
||||
ivl_lpm_negedge
|
||||
ivl_lpm_q
|
||||
ivl_lpm_scope
|
||||
ivl_lpm_select
|
||||
|
|
@ -210,6 +211,9 @@ ivl_scope_enumerates
|
|||
ivl_scope_event
|
||||
ivl_scope_events
|
||||
ivl_scope_file
|
||||
ivl_scope_func_type
|
||||
ivl_scope_func_signed
|
||||
ivl_scope_func_width
|
||||
ivl_scope_is_auto
|
||||
ivl_scope_is_cell
|
||||
ivl_scope_lineno
|
||||
|
|
@ -290,6 +294,7 @@ ivl_stmt_lval
|
|||
ivl_stmt_lvals
|
||||
ivl_stmt_lwidth
|
||||
ivl_stmt_name
|
||||
ivl_stmt_needs_t0_trigger
|
||||
ivl_stmt_nevent
|
||||
ivl_stmt_opcode
|
||||
ivl_stmt_parm
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/*
|
||||
* Define a safer version of malloc().
|
||||
*/
|
||||
|
|
@ -82,5 +83,6 @@
|
|||
} \
|
||||
__ivl_rtn; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#endif /* IVL_ivl_alloc_H */
|
||||
|
|
|
|||
64
ivl_target.h
64
ivl_target.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_ivl_target_H
|
||||
#define IVL_ivl_target_H
|
||||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -41,6 +41,12 @@
|
|||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && defined(_MSC_VER)
|
||||
# define ENUM_UNSIGNED_INT : unsigned int
|
||||
#else
|
||||
# define ENUM_UNSIGNED_INT
|
||||
#endif
|
||||
|
||||
_BEGIN_DECL
|
||||
|
||||
/*
|
||||
|
|
@ -201,7 +207,7 @@ typedef enum ivl_dis_domain_e {
|
|||
IVL_DIS_CONTINUOUS = 2
|
||||
} ivl_dis_domain_t;
|
||||
|
||||
typedef enum ivl_drive_e {
|
||||
typedef enum ivl_drive_e ENUM_UNSIGNED_INT {
|
||||
IVL_DR_HiZ = 0,
|
||||
IVL_DR_SMALL = 1,
|
||||
IVL_DR_MEDIUM = 2,
|
||||
|
|
@ -243,7 +249,7 @@ typedef enum ivl_expr_type_e {
|
|||
IVL_EX_UNARY = 14
|
||||
} ivl_expr_type_t;
|
||||
|
||||
typedef enum ivl_select_type_e {
|
||||
typedef enum ivl_select_type_e ENUM_UNSIGNED_INT {
|
||||
IVL_SEL_OTHER = 0,
|
||||
IVL_SEL_IDX_UP = 1,
|
||||
IVL_SEL_IDX_DOWN = 2
|
||||
|
|
@ -300,8 +306,10 @@ typedef enum ivl_lpm_type_e {
|
|||
IVL_LPM_CONCAT = 16,
|
||||
IVL_LPM_CONCATZ = 36, /* Transparent concat */
|
||||
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
|
||||
IVL_LPM_CMP_EQX= 37, /* Windcard EQ (==?) */
|
||||
IVL_LPM_CMP_EQX= 37, /* Wildcard EQ (casex) */
|
||||
IVL_LPM_CMP_EQZ= 38, /* casez EQ */
|
||||
IVL_LPM_CMP_WEQ= 41,
|
||||
IVL_LPM_CMP_WNE= 42,
|
||||
IVL_LPM_CMP_EQ = 10,
|
||||
IVL_LPM_CMP_GE = 1,
|
||||
IVL_LPM_CMP_GT = 2,
|
||||
|
|
@ -309,6 +317,7 @@ typedef enum ivl_lpm_type_e {
|
|||
IVL_LPM_CMP_NEE= 19, /* Case NE (!==) */
|
||||
IVL_LPM_DIVIDE = 12,
|
||||
IVL_LPM_FF = 3,
|
||||
IVL_LPM_LATCH = 40,
|
||||
IVL_LPM_MOD = 13,
|
||||
IVL_LPM_MULT = 4,
|
||||
IVL_LPM_MUX = 5,
|
||||
|
|
@ -345,10 +354,13 @@ typedef enum ivl_path_edge_e {
|
|||
|
||||
/* Processes are initial, always, or final blocks with a statement. This is
|
||||
the type of the ivl_process_t object. */
|
||||
typedef enum ivl_process_type_e {
|
||||
IVL_PR_INITIAL = 0,
|
||||
IVL_PR_ALWAYS = 1,
|
||||
IVL_PR_FINAL = 2
|
||||
typedef enum ivl_process_type_e ENUM_UNSIGNED_INT {
|
||||
IVL_PR_INITIAL = 0,
|
||||
IVL_PR_ALWAYS = 1,
|
||||
IVL_PR_ALWAYS_COMB = 3,
|
||||
IVL_PR_ALWAYS_FF = 4,
|
||||
IVL_PR_ALWAYS_LATCH = 5,
|
||||
IVL_PR_FINAL = 2
|
||||
} ivl_process_type_t;
|
||||
|
||||
/* These are the sorts of reasons a scope may come to be. These types
|
||||
|
|
@ -431,7 +443,7 @@ typedef enum ivl_sfunc_as_task_e {
|
|||
|
||||
/* This is the type of a variable, and also used as the type for an
|
||||
expression. */
|
||||
typedef enum ivl_variable_type_e {
|
||||
typedef enum ivl_variable_type_e ENUM_UNSIGNED_INT {
|
||||
IVL_VT_VOID = 0, /* Not used */
|
||||
IVL_VT_NO_TYPE = 1, /* Place holder for missing/unknown type. */
|
||||
IVL_VT_REAL = 2,
|
||||
|
|
@ -1285,8 +1297,8 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net);
|
|||
* magnitude compare, the signedness does matter. In any case, the
|
||||
* result of the compare is always unsigned.
|
||||
*
|
||||
* The EQX and EQZ nodes are windcard compares, where xz bits (EQX) or
|
||||
* z bits (EQZ) in the data(1) operand are treated as windcards. no
|
||||
* The EQX and EQZ nodes are wildcard compares, where xz bits (EQX) or
|
||||
* z bits (EQZ) in the data(1) operand are treated as wildcards. no
|
||||
* bits in the data(0) operand are wild. This matches the
|
||||
* SystemVerilog convention for the ==? operator.
|
||||
*
|
||||
|
|
@ -1303,8 +1315,13 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net);
|
|||
* inputs and the Q. All the types must be exactly the same.
|
||||
*
|
||||
* - D-FlipFlop (IVL_LPM_FF)
|
||||
* This data is an edge sensitive register. The ivl_lpm_q output and
|
||||
* single ivl_lpm_data input are the same with, ivl_lpm_width. This
|
||||
* This device is an edge sensitive register. The ivl_lpm_q output and
|
||||
* single ivl_lpm_data input are the same width, ivl_lpm_width. This
|
||||
* device carries a vector like other LPM devices.
|
||||
*
|
||||
* - Latch (IVL_LPM_LATCH)
|
||||
* This device is an asynchronous latch. The ivl_lpm_q output and
|
||||
* single ivl_lpm_data input are the same width, ivl_lpm_width. This
|
||||
* device carries a vector like other LPM devices.
|
||||
*
|
||||
* - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY)
|
||||
|
|
@ -1418,21 +1435,22 @@ extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net);
|
|||
/* IVL_LPM_PART IVL_LPM_SUBSTITUTE */
|
||||
extern unsigned ivl_lpm_base(ivl_lpm_t net);
|
||||
/* IVL_LPM_FF */
|
||||
extern unsigned ivl_lpm_negedge(ivl_lpm_t net);
|
||||
extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net);
|
||||
/* IVL_LPM_UFUNC */
|
||||
extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
|
||||
/* IVL_LPM_FF */
|
||||
/* IVL_LPM_FF IVL_LPM_LATCH*/
|
||||
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
|
||||
/* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT
|
||||
IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB
|
||||
IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE */
|
||||
IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE IVL_LPM_LATCH */
|
||||
extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx);
|
||||
/* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB IVL_LPM_CMP_EQ
|
||||
IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */
|
||||
extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx);
|
||||
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW
|
||||
IVL_LPM_SUB IVL_LPM_UFUNC IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX
|
||||
IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE */
|
||||
IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE IVL_LPM_LATCH */
|
||||
extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net);
|
||||
extern ivl_drive_t ivl_lpm_drive0(ivl_lpm_t net);
|
||||
extern ivl_drive_t ivl_lpm_drive1(ivl_lpm_t net);
|
||||
|
|
@ -1738,6 +1756,13 @@ extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
|
|||
* ivl_scope_lineno
|
||||
* Returns the instantiation file and line for this scope.
|
||||
*
|
||||
* ivl_scope_func_type
|
||||
* ivl_scope_func_signed
|
||||
* ivl_scope_func_width
|
||||
*
|
||||
* If the scope is a function, these function can be used to get
|
||||
* the type of the return value.
|
||||
*
|
||||
* ivl_scope_is_auto
|
||||
* Is the task or function declared to be automatic?
|
||||
*
|
||||
|
|
@ -1856,6 +1881,9 @@ extern const char* ivl_scope_tname(ivl_scope_t net);
|
|||
extern int ivl_scope_time_precision(ivl_scope_t net);
|
||||
extern int ivl_scope_time_units(ivl_scope_t net);
|
||||
|
||||
extern ivl_variable_type_t ivl_scope_func_type(ivl_scope_t net);
|
||||
extern int ivl_scope_func_signed(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_func_width(ivl_scope_t net);
|
||||
|
||||
/* SIGNALS
|
||||
* Signals are named things in the Verilog source, like wires and
|
||||
|
|
@ -2077,6 +2105,7 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net);
|
|||
* handle disable statements.
|
||||
*
|
||||
* ivl_stmt_events
|
||||
* ivl_stmt_needs_t0_trigger
|
||||
* ivl_stmt_nevent
|
||||
* Statements that have event arguments (TRIGGER and WAIT) make
|
||||
* those event objects available through these methods.
|
||||
|
|
@ -2204,6 +2233,7 @@ extern ivl_expr_t ivl_stmt_delay_expr(ivl_statement_t net);
|
|||
/* IVL_ST_DELAY */
|
||||
extern uint64_t ivl_stmt_delay_val(ivl_statement_t net);
|
||||
/* IVL_ST_WAIT IVL_ST_TRIGGER */
|
||||
extern unsigned ivl_stmt_needs_t0_trigger(ivl_statement_t net);
|
||||
extern unsigned ivl_stmt_nevent(ivl_statement_t net);
|
||||
extern ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx);
|
||||
/* IVL_ST_CONTRIB */
|
||||
|
|
@ -2342,4 +2372,6 @@ typedef const char* (*target_query_f) (const char*key);
|
|||
|
||||
_END_DECL
|
||||
|
||||
#undef ENUM_UNSIGNED_INT
|
||||
|
||||
#endif /* IVL_ivl_target_H */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_ivl_target_priv_H
|
||||
#define IVL_ivl_target_priv_H
|
||||
/*
|
||||
* Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-2017 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
|
||||
|
|
@ -52,7 +52,6 @@ struct ivl_design_s {
|
|||
|
||||
// Keep arrays of root scopes.
|
||||
std::map<const NetScope*,ivl_scope_t> classes;
|
||||
std::map<const NetScope*,ivl_scope_t> root_tasks;
|
||||
std::vector<ivl_scope_t> packages;
|
||||
std::vector<ivl_scope_t> roots;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_globals_H
|
||||
#define IVL_globals_H
|
||||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2017 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
|
||||
|
|
@ -53,6 +53,9 @@ extern char dep_mode;
|
|||
|
||||
extern int verbose_flag;
|
||||
|
||||
extern int warn_redef;
|
||||
extern int warn_redef_all;
|
||||
|
||||
/* This is the entry to the lexer. */
|
||||
extern int yylex(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ keys, with their corresponding values, are:
|
|||
This is exactly the same as the "-Dname=<value>" described above.
|
||||
|
||||
I:<dir>
|
||||
This is exctly the same as "-I<dir>".
|
||||
This is exactly the same as "-I<dir>".
|
||||
|
||||
relative include:<flag>
|
||||
The <flag> can be "true" or "false". This enables "relative
|
||||
|
|
|
|||
178
ivlpp/lexor.lex
178
ivlpp/lexor.lex
|
|
@ -1,7 +1,7 @@
|
|||
%option prefix="yy"
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2017 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
|
||||
|
|
@ -39,6 +39,7 @@ static void def_finish(void);
|
|||
static void def_undefine(void);
|
||||
static void do_define(void);
|
||||
static int def_is_done(void);
|
||||
static void def_continue(void);
|
||||
static int is_defined(const char*name);
|
||||
|
||||
static int macro_needs_args(const char*name);
|
||||
|
|
@ -147,18 +148,38 @@ static void ifdef_leave(void)
|
|||
free(cur);
|
||||
}
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) do { \
|
||||
if (istack->file) { \
|
||||
size_t rc = fread(buf, 1, max_size, istack->file); \
|
||||
result = (rc == 0) ? YY_NULL : rc; \
|
||||
} else { \
|
||||
if (*istack->str == 0) \
|
||||
result = YY_NULL; \
|
||||
else { \
|
||||
buf[0] = *istack->str++; \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
#define YY_INPUT(buf,result,max_size) do { \
|
||||
if (istack->file) { \
|
||||
size_t rc = fread(buf, 1, max_size, istack->file); \
|
||||
result = (rc == 0) ? YY_NULL : rc; \
|
||||
} else { \
|
||||
/* We are expanding a macro. Handle the SV macro escape \
|
||||
sequences. There doesn't seem to be any good reason \
|
||||
not to allow them in traditional Verilog as well. */ \
|
||||
while ((istack->str[0] == '`') && \
|
||||
(istack->str[1] == '`')) { \
|
||||
istack->str += 2; \
|
||||
} \
|
||||
if (*istack->str == 0) { \
|
||||
result = YY_NULL; \
|
||||
} else if ((istack->str[0] == '`') && \
|
||||
(istack->str[1] == '"')) { \
|
||||
istack->str += 2; \
|
||||
buf[0] = '"'; \
|
||||
result = 1; \
|
||||
} else if ((istack->str[0] == '`') && \
|
||||
(istack->str[1] == '\\')&& \
|
||||
(istack->str[2] == '`') && \
|
||||
(istack->str[3] == '"')) { \
|
||||
istack->str += 4; \
|
||||
buf[0] = '\\'; \
|
||||
buf[1] = '"'; \
|
||||
result = 2; \
|
||||
} else { \
|
||||
buf[0] = *istack->str++; \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int comment_enter = 0;
|
||||
|
|
@ -241,12 +262,6 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
|||
if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
/* `" overrides the usual lexical meaning of " and `\`" indicates
|
||||
that the expansion should include the escape sequence \".
|
||||
*/
|
||||
`\" { fputc('"', yyout); }
|
||||
`\\`\" { fprintf(yyout, "\\\""); }
|
||||
|
||||
/* Strings do not contain preprocessor directives, but can expand
|
||||
* macros. If that happens, they get expanded in the context of the
|
||||
* string.
|
||||
|
|
@ -358,6 +373,8 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
|||
if (def_is_done()) {
|
||||
def_finish();
|
||||
yy_pop_state();
|
||||
} else {
|
||||
def_continue();
|
||||
}
|
||||
|
||||
istack->lineno += 1;
|
||||
|
|
@ -511,25 +528,17 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
|||
do_expand(0);
|
||||
}
|
||||
|
||||
/* Stringified version of macro expansion. If the sequence `` is
|
||||
* encountered inside a macro definition, we use the SystemVerilog
|
||||
* handling of ignoring it so that identifiers can be constructed
|
||||
* from arguments. If istack->file is NULL, we are reading text
|
||||
* produced from a macro, so use SystemVerilog's handling;
|
||||
* otherwise, use the special Icarus handling.
|
||||
*/
|
||||
/* Stringified version of macro expansion. This is an Icarus extension.
|
||||
When expanding macro text, the SV usage of `` takes precedence. */
|
||||
``[a-zA-Z_][a-zA-Z0-9_$]* {
|
||||
if (istack->file == NULL)
|
||||
fprintf(yyout, "%s", yytext+2);
|
||||
else {
|
||||
assert(do_expand_stringify_flag == 0);
|
||||
do_expand_stringify_flag = 1;
|
||||
fputc('"', yyout);
|
||||
if (macro_needs_args(yytext+2))
|
||||
yy_push_state(MA_START);
|
||||
else
|
||||
do_expand(0);
|
||||
}
|
||||
assert(istack->file);
|
||||
assert(do_expand_stringify_flag == 0);
|
||||
do_expand_stringify_flag = 1;
|
||||
fputc('"', yyout);
|
||||
if (macro_needs_args(yytext+2))
|
||||
yy_push_state(MA_START);
|
||||
else
|
||||
do_expand(0);
|
||||
}
|
||||
|
||||
<MA_START>\( { BEGIN(MA_ADD); macro_start_args(); }
|
||||
|
|
@ -568,8 +577,12 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
|||
|
||||
<MA_ADD>"(" { macro_add_to_arg(0); ma_parenthesis_level++; }
|
||||
|
||||
<MA_ADD>"," { if (ma_parenthesis_level > 0) macro_add_to_arg(0);
|
||||
else macro_finish_arg(); }
|
||||
<MA_ADD>"," {
|
||||
if (ma_parenthesis_level > 0)
|
||||
macro_add_to_arg(0);
|
||||
else
|
||||
macro_finish_arg();
|
||||
}
|
||||
|
||||
<MA_ADD>")" {
|
||||
if (ma_parenthesis_level > 0) {
|
||||
|
|
@ -729,7 +742,7 @@ static int is_defined(const char*name)
|
|||
* particular, keep the names and name lengths in a compact stretch of
|
||||
* memory. Note that we do not keep the argument names once the
|
||||
* definition is fully processed, because arguments are always
|
||||
* positional and the definition string hs replaced with position
|
||||
* positional and the definition string is replaced with position
|
||||
* tokens.
|
||||
*/
|
||||
static char* def_buf = 0;
|
||||
|
|
@ -811,7 +824,7 @@ static void def_add_arg(void)
|
|||
val[val_length] = 0;
|
||||
}
|
||||
|
||||
/* Strip white space from betwen arg and "=". */
|
||||
/* Strip white space from between arg and "=". */
|
||||
length = strlen(arg);
|
||||
while (length>0 && isspace(arg[length-1])) {
|
||||
length -= 1;
|
||||
|
|
@ -845,6 +858,25 @@ void define_macro(const char* name, const char* value, int keyword, int argc)
|
|||
{
|
||||
int idx;
|
||||
struct define_t* def;
|
||||
struct define_t* prev;
|
||||
|
||||
/* Verilog has a very nasty system of macros jumping from
|
||||
* file to file, resulting in a global macro scope. Here
|
||||
* we optionally warn about any redefinitions.
|
||||
*
|
||||
* If istack is empty, we are processing a configuration
|
||||
* or precompiled macro file, so don't want to check for
|
||||
* redefinitions - when a precompiled macro file is used,
|
||||
* it will contain copies of any predefined macros.
|
||||
*/
|
||||
if (warn_redef && istack) {
|
||||
prev = def_lookup(name);
|
||||
if (prev && (warn_redef_all || (strcmp(prev->value, value) != 0))) {
|
||||
emit_pathline(istack);
|
||||
fprintf(stderr, "warning: redefinition of macro %s from value '%s' to '%s'\n",
|
||||
name, prev->value, value);
|
||||
}
|
||||
}
|
||||
|
||||
def = malloc(sizeof(struct define_t));
|
||||
def->name = strdup(name);
|
||||
|
|
@ -950,6 +982,11 @@ static size_t magic_cnt = 0;
|
|||
#define _STR1(x) #x
|
||||
#define _STR2(x) _STR1(x)
|
||||
|
||||
static int is_id_char(char c)
|
||||
{
|
||||
return isalnum((int)c) || c == '_' || c == '$';
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an argument, but only if it is not directly preceded by something
|
||||
* that would make it part of another simple identifier ([a-zA-Z0-9_$]).
|
||||
|
|
@ -964,12 +1001,8 @@ static char *find_arg(char*ptr, char*head, char*arg)
|
|||
cp = strstr(cp, arg);
|
||||
if (!cp) break;
|
||||
|
||||
/* If we are not at the start of the string verify that this
|
||||
* match is not in the middle of another identifier.
|
||||
*/
|
||||
if (cp != head &&
|
||||
(isalnum((int)*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$' ||
|
||||
isalnum((int)*(cp+len)) || *(cp+len) == '_' || *(cp+len) == '$')) {
|
||||
/* Verify that this match is not in the middle of another identifier. */
|
||||
if ((cp != head && is_id_char(cp[-1])) || is_id_char(cp[len])) {
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1123,6 +1156,14 @@ static int def_is_done(void)
|
|||
return !define_continue_flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the define_continue_flag.
|
||||
*/
|
||||
static void def_continue(void)
|
||||
{
|
||||
define_continue_flag = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* After some number of calls to do_define, this function is called to
|
||||
* assigned value to the parsed name. If there is no value, then
|
||||
|
|
@ -1299,14 +1340,30 @@ static void macro_add_to_arg(int is_white_space)
|
|||
|
||||
static void macro_finish_arg(void)
|
||||
{
|
||||
char* tail = &def_buf[def_buf_size - def_buf_free];
|
||||
int offs;
|
||||
char* head;
|
||||
char* tail;
|
||||
|
||||
check_for_max_args();
|
||||
|
||||
offs = def_argo[def_argc-1] + def_argl[def_argc-1] + 1;
|
||||
head = &def_buf[offs];
|
||||
tail = &def_buf[def_buf_size - def_buf_free];
|
||||
|
||||
/* Eat any leading and trailing white space. */
|
||||
if ((head < tail) && (*head == ' ')) {
|
||||
offs++;
|
||||
head++;
|
||||
}
|
||||
if ((tail > head) && (*(tail-1) == ' ')) {
|
||||
def_buf_free++;
|
||||
tail--;
|
||||
}
|
||||
|
||||
*tail = 0;
|
||||
|
||||
def_argo[def_argc] = def_argo[def_argc-1] + def_argl[def_argc-1] + 1;
|
||||
def_argl[def_argc] = tail - def_argv(def_argc);
|
||||
def_argo[def_argc] = offs;
|
||||
def_argl[def_argc] = tail - head;
|
||||
|
||||
def_buf_free -= 1;
|
||||
def_argc++;
|
||||
|
|
@ -1345,11 +1402,22 @@ static void expand_using_args(void)
|
|||
int arg;
|
||||
int length;
|
||||
|
||||
if (def_argc != cur_macro->argc) {
|
||||
if (def_argc > cur_macro->argc) {
|
||||
emit_pathline(istack);
|
||||
fprintf(stderr, "error: wrong number of arguments for `%s\n", cur_macro->name);
|
||||
fprintf(stderr, "error: too many arguments for `%s\n", cur_macro->name);
|
||||
return;
|
||||
}
|
||||
while (def_argc < cur_macro->argc) {
|
||||
if (cur_macro->defaults[def_argc]) {
|
||||
def_argl[def_argc] = 0;
|
||||
def_argc += 1;
|
||||
continue;
|
||||
}
|
||||
emit_pathline(istack);
|
||||
fprintf(stderr, "error: too few arguments for `%s\n", cur_macro->name);
|
||||
return;
|
||||
}
|
||||
assert(def_argc == cur_macro->argc);
|
||||
|
||||
head = cur_macro->value;
|
||||
tail = head;
|
||||
|
|
@ -1898,11 +1966,7 @@ static int load_next_input(void)
|
|||
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
|
||||
{
|
||||
if (!table->keyword)
|
||||
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||
fprintf(out, "%s:%d:%d:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#else
|
||||
fprintf(out, "%s:%d:%zd:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#endif
|
||||
|
||||
if (table->left) do_dump_precompiled_defines(out, table->left);
|
||||
|
||||
|
|
@ -2055,7 +2119,7 @@ void destroy_lexor(void)
|
|||
{
|
||||
# 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
|
||||
# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
|
||||
yylex_destroy();
|
||||
# endif
|
||||
# endif
|
||||
|
|
|
|||
22
ivlpp/main.c
22
ivlpp/main.c
|
|
@ -1,5 +1,5 @@
|
|||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)";
|
||||
"Copyright (c) 1999-2017 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
|
||||
|
|
@ -98,6 +98,10 @@ int line_direct_flag = 0;
|
|||
unsigned error_count = 0;
|
||||
FILE *depend_file = NULL;
|
||||
|
||||
/* Should we warn about macro redefinitions? */
|
||||
int warn_redef = 0;
|
||||
int warn_redef_all = 0;
|
||||
|
||||
static int flist_read_flags(const char*path)
|
||||
{
|
||||
char line_buf[2048];
|
||||
|
|
@ -282,7 +286,7 @@ int main(int argc, char*argv[])
|
|||
include_dir[0] = 0; /* 0 is reserved for the current files path. */
|
||||
include_dir[1] = strdup(".");
|
||||
|
||||
while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vV")) != EOF) switch (opt) {
|
||||
while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vVW:")) != EOF) switch (opt) {
|
||||
|
||||
case 'F':
|
||||
flist_read_flags(optarg);
|
||||
|
|
@ -336,6 +340,15 @@ int main(int argc, char*argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
case 'W':
|
||||
if (strcmp(optarg, "redef-all") == 0) {
|
||||
warn_redef_all = 1;
|
||||
warn_redef = 1;
|
||||
} else if (strcmp(optarg, "redef-chg") == 0) {
|
||||
warn_redef = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
fprintf(stderr, "Icarus Verilog Preprocessor version "
|
||||
VERSION " (" VERSION_TAG ")\n\n");
|
||||
|
|
@ -366,7 +379,10 @@ int main(int argc, char*argv[])
|
|||
" -p<fil> - Write precompiled defines to <fil>\n"
|
||||
" -P<fil> - Read precompiled defines from <fil>\n"
|
||||
" -v - Verbose\n"
|
||||
" -V - Print version information and quit\n",
|
||||
" -V - Print version information and quit\n"
|
||||
" -W<cat> - Enable extra ivlpp warning category:\n"
|
||||
" o redef-all - all macro redefinitions\n"
|
||||
" o redef-chg - macro definition changes\n",
|
||||
argv[0]);
|
||||
return flag_errors;
|
||||
}
|
||||
|
|
|
|||
92
lexor.lex
92
lexor.lex
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -72,6 +72,7 @@ static const char* set_file_name(char*text)
|
|||
void reset_lexor();
|
||||
static void line_directive();
|
||||
static void line_directive2();
|
||||
static void reset_all();
|
||||
|
||||
verinum*make_unsized_binary(const char*txt);
|
||||
verinum*make_undef_highz_dec(const char*txt);
|
||||
|
|
@ -187,6 +188,8 @@ TU [munpf]
|
|||
"!=" { return K_NE; }
|
||||
"===" { return K_CEQ; }
|
||||
"!==" { return K_CNE; }
|
||||
"==?" { return K_WEQ; }
|
||||
"!=?" { return K_WNE; }
|
||||
"||" { return K_LOR; }
|
||||
"&&" { return K_LAND; }
|
||||
"&&&" { return K_TAND; }
|
||||
|
|
@ -310,15 +313,6 @@ TU [munpf]
|
|||
BEGIN(UDPTABLE);
|
||||
break;
|
||||
|
||||
/* Translate these to checks if we already have or are
|
||||
* outside the declaration region. */
|
||||
case K_timeunit:
|
||||
if (have_timeunit_decl) rc = K_timeunit_check;
|
||||
break;
|
||||
case K_timeprecision:
|
||||
if (have_timeprec_decl) rc = K_timeprecision_check;
|
||||
break;
|
||||
|
||||
default:
|
||||
yylval.text = 0;
|
||||
break;
|
||||
|
|
@ -428,22 +422,38 @@ TU [munpf]
|
|||
|
||||
if (strcmp(yytext,"$attribute") == 0)
|
||||
return KK_attribute;
|
||||
|
||||
if (gn_system_verilog() && strcmp(yytext,"$unit") == 0) {
|
||||
yylval.package = pform_units.back();
|
||||
return PACKAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
yylval.text = strdupnew(yytext);
|
||||
return SYSTEM_IDENTIFIER; }
|
||||
|
||||
|
||||
\'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
|
||||
return BASED_NUMBER; }
|
||||
\'[sS]?[dD][ \t]*[xzXZ?]_* { yylval.number = make_undef_highz_dec(yytext);
|
||||
return BASED_NUMBER; }
|
||||
\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
|
||||
return BASED_NUMBER; }
|
||||
\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
|
||||
return BASED_NUMBER; }
|
||||
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
|
||||
return BASED_NUMBER; }
|
||||
\'[sS]?[dD][ \t]*[0-9][0-9_]* {
|
||||
yylval.number = make_unsized_dec(yytext);
|
||||
return BASED_NUMBER;
|
||||
}
|
||||
\'[sS]?[dD][ \t]*[xzXZ?]_* {
|
||||
yylval.number = make_undef_highz_dec(yytext);
|
||||
return BASED_NUMBER;
|
||||
}
|
||||
\'[sS]?[bB][ \t]*[0-1xzXZ?][0-1xzXZ?_]* {
|
||||
yylval.number = make_unsized_binary(yytext);
|
||||
return BASED_NUMBER;
|
||||
}
|
||||
\'[sS]?[oO][ \t]*[0-7xzXZ?][0-7xzXZ?_]* {
|
||||
yylval.number = make_unsized_octal(yytext);
|
||||
return BASED_NUMBER;
|
||||
}
|
||||
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ?][0-9a-fA-FxzXZ?_]* {
|
||||
yylval.number = make_unsized_hex(yytext);
|
||||
return BASED_NUMBER;
|
||||
}
|
||||
\'[01xzXZ] {
|
||||
if (generation_flag < GN_VER2005_SV) {
|
||||
if (!gn_system_verilog()) {
|
||||
cerr << yylloc.text << ":" << yylloc.first_line << ": warning: "
|
||||
<< "Using SystemVerilog 'N bit vector. Use at least "
|
||||
<< "-g2005-sv to remove this warning." << endl;
|
||||
|
|
@ -469,7 +479,7 @@ TU [munpf]
|
|||
|
||||
/* This rule handles scaled time values for SystemVerilog. */
|
||||
[0-9][0-9_]*(\.[0-9][0-9_]*)?{TU}?s {
|
||||
if(generation_flag & (GN_VER2005_SV | GN_VER2009 | GN_VER2012)) {
|
||||
if (gn_system_verilog()) {
|
||||
yylval.text = strdupnew(yytext);
|
||||
return TIME_LITERAL;
|
||||
} else REJECT; }
|
||||
|
|
@ -556,11 +566,7 @@ TU [munpf]
|
|||
"definition." << endl;
|
||||
error_count += 1;
|
||||
} else {
|
||||
pform_set_default_nettype(NetNet::WIRE, yylloc.text,
|
||||
yylloc.first_line);
|
||||
in_celldefine = false;
|
||||
uc_drive = UCD_NONE;
|
||||
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
|
||||
reset_all();
|
||||
} }
|
||||
|
||||
/* Notice and handle the `unconnected_drive directive. */
|
||||
|
|
@ -847,7 +853,7 @@ verinum*make_unsized_binary(const char*txt)
|
|||
ptr += 1;
|
||||
}
|
||||
|
||||
assert((tolower(*ptr) == 'b') || (generation_flag >= GN_VER2005_SV));
|
||||
assert((tolower(*ptr) == 'b') || gn_system_verilog());
|
||||
if (tolower(*ptr) == 'b') {
|
||||
ptr += 1;
|
||||
} else {
|
||||
|
|
@ -862,6 +868,14 @@ verinum*make_unsized_binary(const char*txt)
|
|||
for (const char*idx = ptr ; *idx ; idx += 1)
|
||||
if (*idx != '_') size += 1;
|
||||
|
||||
if (size == 0) {
|
||||
VLerror(yylloc, "Numeric literal has no digits in it.");
|
||||
verinum*out = new verinum();
|
||||
out->has_sign(sign_flag);
|
||||
out->is_single(single_flag);
|
||||
return out;
|
||||
}
|
||||
|
||||
if ((based_size > 0) && (size > based_size)) yywarn(yylloc,
|
||||
"extra digits given for sized binary constant.");
|
||||
|
||||
|
|
@ -1579,6 +1593,18 @@ static void line_directive2()
|
|||
yylloc.first_line = lineno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all compiler directives. This will be called when a `resetall
|
||||
* directive is encountered or when a new compilation unit is started.
|
||||
*/
|
||||
static void reset_all()
|
||||
{
|
||||
pform_set_default_nettype(NetNet::WIRE, yylloc.text, yylloc.first_line);
|
||||
in_celldefine = false;
|
||||
uc_drive = UCD_NONE;
|
||||
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
|
||||
}
|
||||
|
||||
extern FILE*vl_input;
|
||||
void reset_lexor()
|
||||
{
|
||||
|
|
@ -1587,6 +1613,14 @@ void reset_lexor()
|
|||
|
||||
/* Announce the first file name. */
|
||||
yylloc.text = set_file_name(strdupnew(vl_file.c_str()));
|
||||
|
||||
if (separate_compilation) {
|
||||
reset_all();
|
||||
if (!keyword_mask_stack.empty()) {
|
||||
lexor_keyword_mask = keyword_mask_stack.back();
|
||||
keyword_mask_stack.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1596,7 +1630,7 @@ 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
|
||||
# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
|
||||
yylex_destroy();
|
||||
# endif
|
||||
# endif
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ LineInfo::LineInfo()
|
|||
{
|
||||
}
|
||||
|
||||
LineInfo::LineInfo(const LineInfo&that) :
|
||||
file_(that.file_), lineno_(that.lineno_)
|
||||
{
|
||||
}
|
||||
|
||||
LineInfo::~LineInfo()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ using namespace std;
|
|||
class LineInfo {
|
||||
public:
|
||||
LineInfo();
|
||||
LineInfo(const LineInfo&that);
|
||||
virtual ~LineInfo();
|
||||
|
||||
// Get a fully formatted file/lineno
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ static unsigned string_pool_count = 0;
|
|||
StringHeap::StringHeap()
|
||||
{
|
||||
cell_base_ = 0;
|
||||
cell_ptr_ = HEAPCELL;
|
||||
cell_count_ = 0;
|
||||
cell_size_ = 0;
|
||||
cell_ptr_ = 0;
|
||||
}
|
||||
|
||||
StringHeap::~StringHeap()
|
||||
|
|
@ -45,20 +45,24 @@ StringHeap::~StringHeap()
|
|||
const char* StringHeap::add(const char*text)
|
||||
{
|
||||
unsigned len = strlen(text);
|
||||
assert((len+1) <= HEAPCELL);
|
||||
|
||||
unsigned rem = HEAPCELL - cell_ptr_;
|
||||
unsigned rem = cell_size_ - cell_ptr_;
|
||||
if (rem < (len+1)) {
|
||||
cell_base_ = (char*)malloc(HEAPCELL);
|
||||
// release any unused memory
|
||||
if (rem > 0) {
|
||||
cell_base_ = (char*)realloc(cell_base_, cell_ptr_);
|
||||
assert(cell_base_ != 0);
|
||||
}
|
||||
// start new cell
|
||||
cell_size_ = (len+1) > DEFAULT_CELL_SIZE ? len+1 : DEFAULT_CELL_SIZE;
|
||||
cell_base_ = (char*)malloc(cell_size_);
|
||||
cell_ptr_ = 0;
|
||||
assert(cell_base_ != 0);
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
string_pool_count += 1;
|
||||
string_pool = (char **) realloc(string_pool,
|
||||
string_pool_count*sizeof(char **));
|
||||
string_pool[string_pool_count-1] = cell_base_;
|
||||
#endif
|
||||
cell_ptr_ = 0;
|
||||
cell_count_ += 1;
|
||||
assert(cell_base_ != 0);
|
||||
}
|
||||
|
||||
char*res = cell_base_ + cell_ptr_;
|
||||
|
|
@ -66,7 +70,7 @@ const char* StringHeap::add(const char*text)
|
|||
cell_ptr_ += len;
|
||||
cell_base_[cell_ptr_++] = 0;
|
||||
|
||||
assert(cell_ptr_ <= HEAPCELL);
|
||||
assert(cell_ptr_ <= cell_size_);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class perm_string {
|
|||
private:
|
||||
friend class StringHeap;
|
||||
friend class StringHeapLex;
|
||||
perm_string(const char*t) : text_(t) { };
|
||||
explicit perm_string(const char*t) : text_(t) { };
|
||||
|
||||
private:
|
||||
const char*text_;
|
||||
|
|
@ -78,11 +78,11 @@ class StringHeap {
|
|||
perm_string make(const char*);
|
||||
|
||||
private:
|
||||
enum { HEAPCELL = 0x10000 };
|
||||
static const unsigned DEFAULT_CELL_SIZE = 0x10000;
|
||||
|
||||
char*cell_base_;
|
||||
unsigned cell_size_;
|
||||
unsigned cell_ptr_;
|
||||
unsigned cell_count_;
|
||||
|
||||
private: // not implemented
|
||||
StringHeap(const StringHeap&);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ LDRELOCFLAGS = @LDRELOCFLAGS@
|
|||
|
||||
LDTARGETFLAGS = @LDTARGETFLAGS@
|
||||
|
||||
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
||||
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const @PICFLAG@
|
||||
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@
|
||||
|
||||
A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \
|
||||
|
|
@ -76,7 +76,8 @@ distclean: clean
|
|||
rm -f config.h stamp-config-h
|
||||
|
||||
cppcheck: $(O:.o=.c)
|
||||
cppcheck --enable=all -f $(INCLUDE_PATH) $^
|
||||
cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \
|
||||
--relative-paths=$(srcdir) $(INCLUDE_PATH) $^
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in
|
||||
cd ..; ./config.status --file=libveriuser/$@
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ double acc_fetch_paramval(handle object)
|
|||
fprintf(pli_trace, "acc_fetch_paramval(%s) --> \"%s\"\n",
|
||||
vpi_get_str(vpiName, object), val.value.str);
|
||||
}
|
||||
return (double) (long)val.value.str;
|
||||
return (double) (intptr_t)val.value.str;
|
||||
|
||||
default:
|
||||
vpi_printf("XXXX: parameter %s has type %d\n",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
// These are the functions that the runtime exports.
|
||||
|
||||
// The ACC functions.
|
||||
|
||||
// acc_close()
|
||||
unusedFunction:a_close.c:23
|
||||
// acc_compare_handles()
|
||||
unusedFunction:a_compare_handles.c:23
|
||||
// acc_configure()
|
||||
unusedFunction:a_configure.c:25
|
||||
|
||||
// acc_fetch_argc()
|
||||
unusedFunction:a_fetch_argc.c:27
|
||||
// acc_fetch_argv()
|
||||
unusedFunction:a_fetch_argv.c:27
|
||||
// acc_fetch_defname()
|
||||
unusedFunction:a_fetch_fullname.c:37
|
||||
// acc_fetch_direction()
|
||||
unusedFunction:a_fetch_dir.c:26
|
||||
// acc_fetch_fulltype()
|
||||
unusedFunction:a_fetch_type.c:66
|
||||
// acc_fetch_itfarg()
|
||||
unusedFunction:a_fetch_tfarg.c:27
|
||||
// acc_fetch_location()
|
||||
unusedFunction:a_fetch_location.c:23
|
||||
// acc_fetch_name()
|
||||
unusedFunction:a_fetch_fullname.c:32
|
||||
// acc_fetch_paramtype()
|
||||
unusedFunction:a_fetch_type_str.c:47
|
||||
// acc_fetch_paramval()
|
||||
unusedFunction:a_fetch_param.c:25
|
||||
// acc_fetch_range()
|
||||
unusedFunction:a_fetch_range.c:26
|
||||
// acc_fetch_size()
|
||||
unusedFunction:a_fetch_type.c:24
|
||||
// acc_fetch_tfarg()
|
||||
unusedFunction:a_fetch_tfarg.c:56
|
||||
// acc_fetch_tfarg_int()
|
||||
unusedFunction:a_fetch_tfarg.c:91
|
||||
// acc_fetch_timescale_info()
|
||||
unusedFunction:a_fetch_time.c:24
|
||||
// acc_fetch_type()
|
||||
unusedFunction:a_fetch_type.c:29
|
||||
// acc_fetch_type_str()
|
||||
unusedFunction:a_fetch_type_str.c:24
|
||||
// acc_fetch_value()
|
||||
unusedFunction:a_fetch_value.c:115
|
||||
|
||||
// acc_handle_by_name()
|
||||
unusedFunction:a_handle_by_name.c:29
|
||||
// acc_handle_hiconn()
|
||||
unusedFunction:a_handle_hiconn.c:26
|
||||
// acc_handle_object()
|
||||
unusedFunction:a_handle_object.c:26
|
||||
// acc_handle_parent()
|
||||
unusedFunction:a_handle_parent.c:24
|
||||
// acc_handle_scope()
|
||||
unusedFunction:a_handle_parent.c:34
|
||||
// acc_handle_simulated_net()
|
||||
unusedFunction:a_handle_simulated_net.c:26
|
||||
// acc_handle_tfarg()
|
||||
unusedFunction:a_handle_tfarg.c:26
|
||||
// acc_handle_tfinst()
|
||||
unusedFunction:a_handle_tfarg.c:53
|
||||
|
||||
// acc_initialize()
|
||||
unusedFunction:a_initialize.c:24
|
||||
|
||||
// acc_next_bit()
|
||||
unusedFunction:a_next_bit.c:26
|
||||
// acc_next_port()
|
||||
unusedFunction:a_next_port.c:26
|
||||
// acc_next_scope()
|
||||
unusedFunction:a_next.c:86
|
||||
// acc_next_topmod()
|
||||
unusedFunction:a_next_topmod.c:30
|
||||
|
||||
// acc_product_version()
|
||||
unusedFunction:a_product_version.c:23
|
||||
|
||||
// acc_set_scope()
|
||||
unusedFunction:a_handle_object.c:40
|
||||
|
||||
// acc_set_value()
|
||||
unusedFunction:a_set_value.c:27
|
||||
|
||||
// acc_vcl_add()
|
||||
unusedFunction:a_vcl.c:157
|
||||
// acc_vcl_delete()
|
||||
unusedFunction:a_vcl.c:196
|
||||
|
||||
// acc_version()
|
||||
unusedFunction:a_version.c:23
|
||||
|
||||
// These are the TF routines.
|
||||
|
||||
// io_printf()
|
||||
unusedFunction:io_print.c:26
|
||||
|
||||
// mc_scan_plusargs()
|
||||
unusedFunction:mc_scan_plusargs.c:27
|
||||
|
||||
// tf_asynchoff()
|
||||
unusedFunction:asynch.c:34
|
||||
// tf_asynchon()
|
||||
unusedFunction:asynch.c:28
|
||||
// tf_dofinish()
|
||||
unusedFunction:finish.c:26
|
||||
// tf_dostop()
|
||||
unusedFunction:finish.c:32
|
||||
// tf_error()
|
||||
unusedFunction:io_print.c:45
|
||||
// tf_exprinfo()
|
||||
unusedFunction:exprinfo.c:26
|
||||
// tf_getcstringp()
|
||||
unusedFunction:getcstringp.c:26
|
||||
// tf_getlongp()
|
||||
unusedFunction:getlongp.c:29
|
||||
// tf_getlongtime()
|
||||
unusedFunction:getsimtime.c:112
|
||||
// tf_getp()
|
||||
unusedFunction:getp.c:73
|
||||
// tf_getrealp()
|
||||
unusedFunction:getp.c:120
|
||||
// tf_gettime()
|
||||
unusedFunction:getsimtime.c:77
|
||||
// tf_getworkarea()
|
||||
unusedFunction:workarea.c:62
|
||||
// tf_igettimeprecision()
|
||||
unusedFunction:getsimtime.c:198
|
||||
// tf_igettimeunit()
|
||||
unusedFunction:getsimtime.c:228
|
||||
// tf_long_to_real()
|
||||
unusedFunction:math.c:47
|
||||
// tf_message()
|
||||
unusedFunction:io_print.c:56
|
||||
// tf_mipname()
|
||||
unusedFunction:spname.c:47
|
||||
// tf_multiply_long()
|
||||
unusedFunction:math.c:27
|
||||
// tf_nodeinfo()
|
||||
unusedFunction:nodeinfo.c:27
|
||||
// tf_nump()
|
||||
unusedFunction:nump.c:42
|
||||
// tf_putlongp()
|
||||
unusedFunction:putlongp.c:28
|
||||
// tf_putp()
|
||||
unusedFunction:putp.c:88
|
||||
// tf_putrealp()
|
||||
unusedFunction:putp.c:137
|
||||
// tf_real_to_long()
|
||||
unusedFunction:math.c:40
|
||||
// tf_rosynchronize()
|
||||
unusedFunction:veriusertfs.c:391
|
||||
// tf_scale_longdelay()
|
||||
unusedFunction:getsimtime.c:136
|
||||
// tf_scale_realdelay()
|
||||
unusedFunction:getsimtime.c:161
|
||||
// tf_setdelay()
|
||||
unusedFunction:delay.c:75
|
||||
// tf_setrealdelay()
|
||||
unusedFunction:veriusertfs.c:426
|
||||
// tf_setworkarea()
|
||||
unusedFunction:workarea.c:36
|
||||
// tf_spname()
|
||||
unusedFunction:spname.c:25
|
||||
// tf_strgetp()
|
||||
unusedFunction:getp.c:177
|
||||
// tf_strgettime()
|
||||
unusedFunction:getsimtime.c:85
|
||||
// tf_synchronize()
|
||||
unusedFunction:veriusertfs.c:364
|
||||
// tf_typep()
|
||||
unusedFunction:typep.c:24
|
||||
// tf_unscale_longdelay()
|
||||
unusedFunction:getsimtime.c:144
|
||||
// tf_unscale_realdelay()
|
||||
unusedFunction:getsimtime.c:171
|
||||
// tf_warning()
|
||||
unusedFunction:io_print.c:34
|
||||
|
||||
// Non-standard TF routines the Icarus provides.
|
||||
|
||||
// tf_getlongsimtime()
|
||||
unusedFunction:getsimtime.c:126
|
||||
// veriusertfs_register_table()
|
||||
unusedFunction:veriusertfs.c:76
|
||||
|
|
@ -115,7 +115,7 @@ PLI_INT32 tf_getlongtime(PLI_INT32 *high)
|
|||
}
|
||||
|
||||
/*
|
||||
* This function is not defined in the IEE standard, but is provided for
|
||||
* This function is not defined in the IEEE standard, but is provided for
|
||||
* compatibility with other simulators. On platforms that support this,
|
||||
* make it a weak symbol just in case the user has defined their own
|
||||
* function for this.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2014 Michael Ruff (mruff at chiaro.com)
|
||||
* Copyright (c) 2002-2018 Michael Ruff (mruff at chiaro.com)
|
||||
* Michael Runyan (mrunyan at chiaro.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -42,8 +42,9 @@ typedef struct t_pli_data {
|
|||
int paramvc; /* parameter number for misctf */
|
||||
} s_pli_data, *p_pli_data;
|
||||
|
||||
static PLI_INT32 compiletf(char *);
|
||||
static PLI_INT32 calltf(char *);
|
||||
static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8 *);
|
||||
static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8 *);
|
||||
static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8 *);
|
||||
static PLI_INT32 callback(p_cb_data);
|
||||
|
||||
/*
|
||||
|
|
@ -150,7 +151,7 @@ void veriusertfs_register_table(p_tfcell vtable)
|
|||
tf_data.tfname = tf->tfname;
|
||||
tf_data.compiletf = compiletf;
|
||||
tf_data.calltf = calltf;
|
||||
tf_data.sizetf = (PLI_INT32 (*)(PLI_BYTE8 *))tf->sizetf;
|
||||
tf_data.sizetf = sizetf;
|
||||
tf_data.user_data = (char *)data;
|
||||
|
||||
if (pli_trace) {
|
||||
|
|
@ -180,7 +181,7 @@ void veriusertfs_register_table(p_tfcell vtable)
|
|||
* This function calls the veriusertfs checktf and sets up all the
|
||||
* callbacks misctf requires.
|
||||
*/
|
||||
static PLI_INT32 compiletf(char *data)
|
||||
static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||
{
|
||||
p_pli_data pli;
|
||||
p_tfcell tf;
|
||||
|
|
@ -260,7 +261,7 @@ static PLI_INT32 compiletf(char *data)
|
|||
/*
|
||||
* This function is the wrapper for the veriusertfs calltf routine.
|
||||
*/
|
||||
static PLI_INT32 calltf(char *data)
|
||||
static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||
{
|
||||
int rc = 0;
|
||||
p_pli_data pli;
|
||||
|
|
@ -283,6 +284,32 @@ static PLI_INT32 calltf(char *data)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the wrapper for the veriusertfs sizetf routine.
|
||||
*/
|
||||
static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||
{
|
||||
int rc = 32;
|
||||
p_pli_data pli;
|
||||
p_tfcell tf;
|
||||
|
||||
/* cast back from opaque */
|
||||
pli = (p_pli_data)data;
|
||||
tf = pli->tf;
|
||||
|
||||
/* execute sizetf */
|
||||
if (tf->sizetf) {
|
||||
if (pli_trace) {
|
||||
fprintf(pli_trace, "Call %s->sizetf(%d, %d)\n",
|
||||
tf->tfname, tf->data, reason_sizetf);
|
||||
}
|
||||
|
||||
rc = tf->sizetf(tf->data, reason_sizetf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the wrapper for all the misctf callbacks
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2016 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
|
||||
|
|
@ -102,6 +102,17 @@ bool Nexus::drivers_constant() const
|
|||
break;
|
||||
}
|
||||
|
||||
const NetSubstitute*ps = dynamic_cast<const NetSubstitute*>(cur->get_obj());
|
||||
if (ps) {
|
||||
if (ps->pin(1).nexus()->drivers_constant() &&
|
||||
ps->pin(2).nexus()->drivers_constant() ) {
|
||||
constant_drivers += 1;
|
||||
continue;
|
||||
}
|
||||
driven_ = VAR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! dynamic_cast<const NetConst*>(cur->get_obj())) {
|
||||
driven_ = VAR;
|
||||
return false;
|
||||
|
|
@ -162,13 +173,13 @@ verinum::V Nexus::driven_value() const
|
|||
if ((sig->type() == NetNet::SUPPLY0) ||
|
||||
(sig->type() == NetNet::TRI0)) {
|
||||
// Multiple drivers are not currently supported.
|
||||
ivl_assert(*obj, val == verinum::Vz);
|
||||
ivl_assert(*sig, val == verinum::Vz);
|
||||
val = verinum::V0;
|
||||
}
|
||||
if ((sig->type() == NetNet::SUPPLY1) ||
|
||||
(sig->type() == NetNet::TRI1)) {
|
||||
// Multiple drivers are not currently supported.
|
||||
ivl_assert(*obj, val == verinum::Vz);
|
||||
ivl_assert(*sig, val == verinum::Vz);
|
||||
val = verinum::V1;
|
||||
}
|
||||
}
|
||||
|
|
@ -199,10 +210,12 @@ verinum Nexus::driven_vector() const
|
|||
const Link*cur = list_;
|
||||
|
||||
verinum val;
|
||||
verinum pval;
|
||||
unsigned width = 0;
|
||||
|
||||
for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
|
||||
const NetSubstitute*ps;
|
||||
const NetConst*obj;
|
||||
const NetNet*sig;
|
||||
if ((obj = dynamic_cast<const NetConst*>(cur->get_obj()))) {
|
||||
|
|
@ -212,6 +225,18 @@ verinum Nexus::driven_vector() const
|
|||
val = obj->value();
|
||||
width = val.len();
|
||||
|
||||
} else if ((ps = dynamic_cast<const NetSubstitute*>(cur->get_obj()))) {
|
||||
if (cur->get_pin() != 0)
|
||||
continue;
|
||||
|
||||
// Multiple drivers are not currently supported.
|
||||
ivl_assert(*ps, val.len() == 0);
|
||||
val = ps->pin(1).nexus()->driven_vector();
|
||||
pval = ps->pin(2).nexus()->driven_vector();
|
||||
for (unsigned idx = 0; idx < pval.len(); idx += 1)
|
||||
val.set(ps->base() + idx, pval.get(idx));
|
||||
width = val.len();
|
||||
|
||||
} else if ((sig = dynamic_cast<const NetNet*>(cur->get_obj()))) {
|
||||
|
||||
width = sig->vector_width();
|
||||
|
|
@ -222,13 +247,13 @@ verinum Nexus::driven_vector() const
|
|||
if ((sig->type() == NetNet::SUPPLY0) ||
|
||||
(sig->type() == NetNet::TRI0)) {
|
||||
// Multiple drivers are not currently supported.
|
||||
ivl_assert(*obj, val.len() == 0);
|
||||
ivl_assert(*sig, val.len() == 0);
|
||||
val = verinum(verinum::V0, width);
|
||||
}
|
||||
if ((sig->type() == NetNet::SUPPLY1) ||
|
||||
(sig->type() == NetNet::TRI1)) {
|
||||
// Multiple drivers are not currently supported.
|
||||
ivl_assert(*obj, val.len() == 0);
|
||||
ivl_assert(*sig, val.len() == 0);
|
||||
val = verinum(verinum::V1, width);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,36 +82,10 @@ bool load_module(const char*type)
|
|||
fflush(depend_file);
|
||||
}
|
||||
|
||||
if (ivlpp_string) {
|
||||
char*cmdline = (char*)malloc(strlen(ivlpp_string) +
|
||||
strlen(path) + 4);
|
||||
strcpy(cmdline, ivlpp_string);
|
||||
strcat(cmdline, " \"");
|
||||
strcat(cmdline, path);
|
||||
strcat(cmdline, "\"");
|
||||
if (verbose_flag)
|
||||
cerr << "Loading library file " << path << "." << endl;
|
||||
|
||||
if (verbose_flag)
|
||||
cerr << "Executing: " << cmdline << endl<< flush;
|
||||
|
||||
FILE*file = popen(cmdline, "r");
|
||||
|
||||
if (verbose_flag)
|
||||
cerr << "...parsing output from preprocessor..." << endl << flush;
|
||||
|
||||
pform_parse(path, file);
|
||||
pclose(file);
|
||||
free(cmdline);
|
||||
|
||||
} else {
|
||||
if (verbose_flag)
|
||||
cerr << "Loading library file "
|
||||
<< path << "." << endl;
|
||||
|
||||
FILE*file = fopen(path, "r");
|
||||
assert(file);
|
||||
pform_parse(path, file);
|
||||
fclose(file);
|
||||
}
|
||||
pform_parse(path);
|
||||
|
||||
if (verbose_flag)
|
||||
cerr << "... Load module complete." << endl << flush;
|
||||
|
|
@ -119,7 +93,6 @@ bool load_module(const char*type)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
130
main.cc
130
main.cc
|
|
@ -1,5 +1,5 @@
|
|||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)";
|
||||
"Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)";
|
||||
|
||||
/*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -108,6 +108,7 @@ bool gn_assertions_flag = true;
|
|||
bool gn_io_range_error_flag = true;
|
||||
bool gn_strict_ca_eval_flag = false;
|
||||
bool gn_strict_expr_width_flag = false;
|
||||
bool gn_shared_loop_index_flag = true;
|
||||
bool gn_verilog_ams_flag = false;
|
||||
|
||||
/*
|
||||
|
|
@ -139,6 +140,8 @@ void add_vpi_module(const char*name)
|
|||
map<perm_string,unsigned> missing_modules;
|
||||
map<perm_string,bool> library_file_map;
|
||||
|
||||
vector<perm_string> source_files;
|
||||
|
||||
list<const char*> library_suff;
|
||||
|
||||
list<perm_string> roots;
|
||||
|
|
@ -153,6 +156,7 @@ FILE *depend_file = NULL;
|
|||
* These are the warning enable flags.
|
||||
*/
|
||||
bool warn_implicit = false;
|
||||
bool warn_implicit_dimensions = false;
|
||||
bool warn_timescale = false;
|
||||
bool warn_portbinding = false;
|
||||
bool warn_inf_loop = false;
|
||||
|
|
@ -160,6 +164,12 @@ bool warn_ob_select = false;
|
|||
bool warn_sens_entire_vec = false;
|
||||
bool warn_sens_entire_arr = false;
|
||||
bool warn_anachronisms = false;
|
||||
bool warn_floating_nets = false;
|
||||
|
||||
/*
|
||||
* Ignore errors about missing modules
|
||||
*/
|
||||
bool ignore_missing_modules = false;
|
||||
|
||||
/*
|
||||
* Debug message class flags.
|
||||
|
|
@ -171,6 +181,11 @@ bool debug_emit = false;
|
|||
bool debug_synth2 = false;
|
||||
bool debug_optimizer = false;
|
||||
|
||||
/*
|
||||
* Compilation control flags.
|
||||
*/
|
||||
bool separate_compilation = false;
|
||||
|
||||
/*
|
||||
* Optimization control flags.
|
||||
*/
|
||||
|
|
@ -224,6 +239,7 @@ const bool CASE_SENSITIVE = true;
|
|||
bool synthesis = false;
|
||||
|
||||
extern void cprop(Design*des);
|
||||
extern void exposenodes(Design*des);
|
||||
extern void synth(Design*des);
|
||||
extern void synth2(Design*des);
|
||||
extern void syn_rules(Design*des);
|
||||
|
|
@ -234,10 +250,11 @@ static struct net_func_map {
|
|||
const char*name;
|
||||
void (*func)(Design*);
|
||||
} func_table[] = {
|
||||
{ "cprop", &cprop },
|
||||
{ "nodangle",&nodangle },
|
||||
{ "synth", &synth },
|
||||
{ "synth2", &synth2 },
|
||||
{ "cprop", &cprop },
|
||||
{ "exposenodes", &exposenodes },
|
||||
{ "nodangle", &nodangle },
|
||||
{ "synth", &synth },
|
||||
{ "synth2", &synth2 },
|
||||
{ "syn-rules", &syn_rules },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
|
@ -343,6 +360,12 @@ static void process_generation_flag(const char*gen)
|
|||
} else if (strcmp(gen,"no-strict-expr-width") == 0) {
|
||||
gn_strict_expr_width_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"shared-loop-index") == 0) {
|
||||
gn_shared_loop_index_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"no-shared-loop-index") == 0) {
|
||||
gn_shared_loop_index_flag = false;
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
|
@ -559,6 +582,9 @@ static bool set_default_timescale(const char*ts_string)
|
|||
*
|
||||
* warnings:<string>
|
||||
* Warning flag letters.
|
||||
*
|
||||
* ignore_missing_modules:<bool>
|
||||
* true to ignore errors about missing modules
|
||||
*/
|
||||
bool had_timescale = false;
|
||||
static void read_iconfig_file(const char*ipath)
|
||||
|
|
@ -675,9 +701,15 @@ static void read_iconfig_file(const char*ipath)
|
|||
} else if (strcmp(buf,"warnings") == 0) {
|
||||
/* Scan the warnings enable string for warning flags. */
|
||||
for ( ; *cp ; cp += 1) switch (*cp) {
|
||||
case 'f':
|
||||
warn_floating_nets = true;
|
||||
break;
|
||||
case 'i':
|
||||
warn_implicit = true;
|
||||
break;
|
||||
case 'd':
|
||||
warn_implicit_dimensions = true;
|
||||
break;
|
||||
case 'l':
|
||||
warn_inf_loop = true;
|
||||
break;
|
||||
|
|
@ -703,6 +735,10 @@ static void read_iconfig_file(const char*ipath)
|
|||
break;
|
||||
}
|
||||
|
||||
} else if (strcmp(buf, "ignore_missing_modules") == 0) {
|
||||
if (strcmp(cp, "true") == 0)
|
||||
ignore_missing_modules = true;
|
||||
|
||||
} else if (strcmp(buf, "-y") == 0) {
|
||||
build_library_index(cp, CASE_SENSITIVE);
|
||||
|
||||
|
|
@ -748,6 +784,38 @@ static void read_iconfig_file(const char*ipath)
|
|||
fclose(ifile);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads a list of source file names. Each name starts
|
||||
* with the first non-space character, and ends with the last non-space
|
||||
* character. Spaces in the middle are OK.
|
||||
*/
|
||||
static void read_sources_file(const char*path)
|
||||
{
|
||||
char line_buf[2048];
|
||||
|
||||
FILE*fd = fopen(path, "r");
|
||||
if (fd == 0) {
|
||||
cerr << "ERROR: Unable to read source file list: " << path << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(line_buf, sizeof line_buf, fd) != 0) {
|
||||
char*cp = line_buf + strspn(line_buf, " \t\r\b\f");
|
||||
char*tail = cp + strlen(cp);
|
||||
while (tail > cp) {
|
||||
if (! isspace((int)tail[-1]))
|
||||
break;
|
||||
tail -= 1;
|
||||
tail[0] = 0;
|
||||
}
|
||||
|
||||
if (cp < tail)
|
||||
source_files.push_back(filename_strings.make(cp));
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
extern Design* elaborate(list <perm_string> root);
|
||||
|
||||
#if defined(HAVE_TIMES)
|
||||
|
|
@ -828,17 +896,20 @@ int main(int argc, char*argv[])
|
|||
// Start the module list with the base system module.
|
||||
add_vpi_module("system");
|
||||
add_vpi_module("vhdl_sys");
|
||||
add_vpi_module("vhdl_textio");
|
||||
|
||||
flags["-o"] = strdup("a.out");
|
||||
min_typ_max_flag = TYP;
|
||||
min_typ_max_warn = 10;
|
||||
|
||||
while ((opt = getopt(argc, argv, "C:f:hN:P:p:Vv")) != EOF) switch (opt) {
|
||||
while ((opt = getopt(argc, argv, "C:F:f:hN:P:p:Vv")) != EOF) switch (opt) {
|
||||
|
||||
case 'C':
|
||||
read_iconfig_file(optarg);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
read_sources_file(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
parm_to_flagmap(optarg);
|
||||
break;
|
||||
|
|
@ -891,6 +962,7 @@ int main(int argc, char*argv[])
|
|||
"usage: ivl <options> <file>\n"
|
||||
"options:\n"
|
||||
"\t-C <name> Config file from driver.\n"
|
||||
"\t-F <file> List of source files from driver.\n"
|
||||
"\t-h Print usage information, and exit.\n"
|
||||
"\t-N <file> Dump the elaborated netlist to <file>.\n"
|
||||
"\t-P <file> Write the parsed input to <file>.\n"
|
||||
|
|
@ -906,11 +978,19 @@ int main(int argc, char*argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
int arg = optind;
|
||||
while (arg < argc) {
|
||||
perm_string path = filename_strings.make(argv[arg++]);
|
||||
source_files.push_back(path);
|
||||
}
|
||||
|
||||
if (source_files.empty()) {
|
||||
cerr << "No input files." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
separate_compilation = source_files.size() > 1;
|
||||
|
||||
if( depfile_name ) {
|
||||
depend_file = fopen(depfile_name, "a");
|
||||
if(! depend_file) {
|
||||
|
|
@ -922,16 +1002,22 @@ int main(int argc, char*argv[])
|
|||
switch (generation_flag) {
|
||||
case GN_VER2012:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1800_2012;
|
||||
// fallthrough
|
||||
case GN_VER2009:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1800_2009;
|
||||
// fallthrough
|
||||
case GN_VER2005_SV:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1800_2005;
|
||||
// fallthrough
|
||||
case GN_VER2005:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2005;
|
||||
// fallthrough
|
||||
case GN_VER2001:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
|
||||
// fallthrough
|
||||
case GN_VER2001_NOCONFIG:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001;
|
||||
// fallthrough
|
||||
case GN_VER1995:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
}
|
||||
|
|
@ -1005,8 +1091,10 @@ int main(int argc, char*argv[])
|
|||
if (flag_tmp) disable_concatz_generation = strcmp(flag_tmp,"true")==0;
|
||||
|
||||
/* Parse the input. Make the pform. */
|
||||
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
|
||||
int rc = pform_parse(argv[optind]);
|
||||
int rc = 0;
|
||||
for (unsigned idx = 0; idx < source_files.size(); idx += 1) {
|
||||
rc += pform_parse(source_files[idx]);
|
||||
}
|
||||
|
||||
if (pf_path) {
|
||||
ofstream out (pf_path);
|
||||
|
|
@ -1020,22 +1108,16 @@ int main(int argc, char*argv[])
|
|||
; cur != disciplines.end() ; ++ cur ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP $ROOT TASKS/FUNCTIONS:" << endl;
|
||||
for (map<perm_string,PTaskFunc*>::iterator cur = pform_tasks.begin()
|
||||
; cur != pform_tasks.end() ; ++ cur) {
|
||||
pform_dump(out, cur->second);
|
||||
}
|
||||
out << "PFORM DUMP $ROOT CLASSES:" << endl;
|
||||
for (map<perm_string,PClass*>::iterator cur = pform_classes.begin()
|
||||
; cur != pform_classes.end() ; ++ cur) {
|
||||
pform_dump(out, cur->second);
|
||||
out << "PFORM DUMP COMPILATION UNITS:" << endl;
|
||||
for (vector<PPackage*>::iterator pac = pform_units.begin()
|
||||
; pac != pform_units.end() ; ++ pac) {
|
||||
pform_dump(out, *pac);
|
||||
}
|
||||
out << "PFORM DUMP PACKAGES:" << endl;
|
||||
for (map<perm_string,PPackage*>::iterator pac = pform_packages.begin()
|
||||
; pac != pform_packages.end() ; ++ pac) {
|
||||
pform_dump(out, pac->second);
|
||||
}
|
||||
|
||||
out << "PFORM DUMP MODULES:" << endl;
|
||||
for (map<perm_string,Module*>::iterator mod = pform_modules.begin()
|
||||
; mod != pform_modules.end() ; ++ mod ) {
|
||||
|
|
@ -1107,7 +1189,7 @@ int main(int argc, char*argv[])
|
|||
|
||||
/* Decide if we are going to allow system functions to be called
|
||||
* as tasks. */
|
||||
if (generation_flag >= GN_VER2005_SV) {
|
||||
if (gn_system_verilog()) {
|
||||
def_sfunc_as_task = IVL_SFUNC_AS_TASK_WARNING;
|
||||
}
|
||||
|
||||
|
|
@ -1153,12 +1235,6 @@ int main(int argc, char*argv[])
|
|||
(*idx).second = 0;
|
||||
}
|
||||
|
||||
for(map<perm_string,data_type_t*>::iterator it = pform_typedefs.begin()
|
||||
; it != pform_typedefs.end() ; ++it) {
|
||||
delete (*it).second;
|
||||
(*it).second = 0;
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
if (times_flag) {
|
||||
times(cycles+2);
|
||||
|
|
|
|||
284
mingw.txt
284
mingw.txt
|
|
@ -1,282 +1,4 @@
|
|||
Please NOTE:
|
||||
Please see the Icarus Verilog Wiki for instruction on building and installing
|
||||
Icarus Verilog as a native Windows application using the MinGW tools:
|
||||
|
||||
These directions are slightly outdated and need to be updated.
|
||||
The plan is to rewrite all this using the latest MinGW at
|
||||
some time in the not too distant future (CR Aug. 2009)
|
||||
|
||||
|
||||
MINGW PORT OF ICARUS VERILOG
|
||||
|
||||
Copyright 2006 Stephen Williams <steve@icarus.com>
|
||||
|
||||
|
||||
Icarus Verilog source can be compiled with the mingw C/C++ compilers
|
||||
to get a Windows binary that does not require the POSIX compatibility
|
||||
cruft of the Cygwin.dll library. The resulting program can be run with
|
||||
or without Cygwin, so this is the preferred Windows distribution form.
|
||||
The configure scripts automatically detect that the compilers in use
|
||||
are the mingw compilers and will configure the Makefiles appropriately.
|
||||
|
||||
The mingw patch doesn't contain tools beyond the compiler, but there
|
||||
is the "msys" package that the makers of Mingw publish that has enough
|
||||
extra tools to get most everything else working. There are a few extra
|
||||
packages needed beyond mingw and msys, and the following instructions
|
||||
explain how to get them and install them.
|
||||
|
||||
* Some Preliminary Comments -- PLEASE READ ME --
|
||||
|
||||
The Windows port of Icarus Verilog is the most difficult of all the
|
||||
ports. The Windows system off the shelf is completely stripped, devoid
|
||||
of any support for software development. Everything needed to compile
|
||||
Icarus Verilog must be collected from various sources and stitched
|
||||
together by hand. Normal human beings with a basic understanding of
|
||||
software development can do this, but some patience (and access to the
|
||||
Internet) is required. You may choose to print these instructions. FOR
|
||||
BEST RESULTS, FOLLOW THESE INSTRUCTIONS CAREFULLY.
|
||||
|
||||
NOTE that if you have Cygwin installed, it is best to not use a cygwin
|
||||
window to do the build, as the Cygwin tools will intermix with the
|
||||
mingw tools such that it is hard to be sure you are using the right
|
||||
compiler. Thus, it is recommended that these steps be *not* done in a
|
||||
Cygwin window. Use an MSYS window instead, and be careful that your
|
||||
msys/mingw tools are not masked by paths that point to Cygwin binaries.
|
||||
|
||||
I have no plans to intentionally support MSVC++ compilation. Don't ask.
|
||||
|
||||
* Summary of Prerequisites
|
||||
|
||||
This is a brief list of prerequisite packages, along with the URL
|
||||
where each can be found. In most cases, the specific version is not
|
||||
critical, but these are the versions I use.
|
||||
|
||||
msys-1.0 <http://www.mingw/org>
|
||||
msysDTK-1.0 <http://www.mingw.org>
|
||||
Mingw32-5.x <http://www.mingw.org>
|
||||
... including the sub-packages binutils, gcc-core and gcc-g++
|
||||
if you are given the option.
|
||||
readline-5.0-1 <http://gnuwin32.sourceforge.net>
|
||||
bzip2-1.0.3 <http://gnuwin32.sourceforge.net>
|
||||
zlib-1.2.3 <http://gnuwin32.sourceforge.net>
|
||||
gperf-3.0.1 <http://gnuwin32.sourceforge.net>
|
||||
bison-2.1 <http://gnuwin32.sourceforge.net>
|
||||
flex-2.5.4a <http://gnuwin32.sourceforge.net>
|
||||
|
||||
The above table lists the packages required. It is convenient to
|
||||
install them in the above order. Many of these packages are also
|
||||
collected into the directory:
|
||||
|
||||
<ftp://icarus.com/pub/eda/verilog/win32-build-parts>
|
||||
|
||||
Incidentally, besides Mingw32, none of these packages are needed after
|
||||
installation of Icarus Verilog is complete. These are only needed to
|
||||
build the compiler. The Mingw32 package can be used to compile VPI
|
||||
modules if you choose.
|
||||
|
||||
* Install MSYS and msysDTK
|
||||
|
||||
The msys package is available from the mingw download site. This is
|
||||
not the compiler but a collection of *nix tools ported to Windows and
|
||||
wrapped in a convenient installer. The msys package is all the various
|
||||
basic tools (shells, file utils, etc) and the msysDTK is extra
|
||||
developer tools other than the compiler.
|
||||
|
||||
Download the msys-1.x.x.exe and msysdtc-1.x.x.exe binaries. These are
|
||||
self-installing packages. Install msys first, and then msysDTC. Most
|
||||
likely, you want to install them in c:/msys. (The msysDTK is installed
|
||||
in the same location, as it is an add-on.)
|
||||
|
||||
This install should be easy and reliable.
|
||||
|
||||
The installation will leave an "msys" icon on your desktop and in the
|
||||
mingw sub-menu of your Start menu. This icon brings up a shell window
|
||||
(a command line) that has paths all set up for executing msys and
|
||||
mingw commands. This is what you will want to use while executing
|
||||
commands below.
|
||||
|
||||
* Install Mingw32
|
||||
|
||||
The obvious step 2, then, is install the mingw compilers. These can be
|
||||
found at the web page <http://www.mingw.org>. The Mingw-5.x.x package
|
||||
is a convenient remote installer. Download this program and run
|
||||
it. The installer will ask which components you want to install. You
|
||||
need only the base C compiler and the C++ compiler. (You may install
|
||||
other languages if you wish.)
|
||||
|
||||
When I install Mingw32 (using the installer) I typically set a
|
||||
destination directory of d:\mingw or the like. You will be using
|
||||
that path later.
|
||||
|
||||
NOTES:
|
||||
If you intend to compile VPI modules for Icarus Verilog, you
|
||||
need Mingw32, even if you are using a precompiled binary. VPI
|
||||
modules only require Mingw32, and none of the other libraries.
|
||||
|
||||
Finally, as part of installing the mingw32 compilers, remember to add
|
||||
the mingw/bin directory to your path. You will need that to be able to
|
||||
find the compilers later.
|
||||
|
||||
* Install GnuWin32 Packages
|
||||
|
||||
The GnuWin32 project is a collections of open source programs and
|
||||
libraries ported to Windows. These also work well with the Mingw
|
||||
compiler, and in fact Icarus Verilog uses a few pieces from this
|
||||
collection.
|
||||
|
||||
You will need these gnuwin32 packages to compile Icarus Verilog:
|
||||
|
||||
<http://gnuwin32.sourceforge.net>
|
||||
bzip2-1.0.3.exe
|
||||
zlib-1.2.3.exe
|
||||
gperf-3.0.1.exe
|
||||
bison-2.1.exe
|
||||
flex-2.5.4a.exe
|
||||
readline-5.0-1.exe
|
||||
|
||||
I suggest creating a common directory for holding all your gnuwin32
|
||||
packages. I use C:\gnuwin32. The download page at the gnuwin32 site
|
||||
has a "setup" link for each of these packages. Click the setup to
|
||||
download the installer for each of the desired programs, then execute
|
||||
the downloaded .exe files to invoke the installer. Install into the
|
||||
c:\gunwin32 directory.
|
||||
|
||||
NOTES:
|
||||
You need the binaries and the developer files, but you do not
|
||||
need the source to these packages. The installer gives you the
|
||||
choice.
|
||||
|
||||
After you are done installing the gnuwin32 tools, you should add the
|
||||
c:\gnuwin32\bin directory (assuming you installed in c:\gnuwin32) to
|
||||
your Windows path. The msys shell will pick up your Windows path.
|
||||
|
||||
* Unpack Icarus Verilog source
|
||||
|
||||
Unpack the compressed tar file (.tar.gz) of the source with a command
|
||||
like this:
|
||||
|
||||
$ gunzip -d verilog-xxxxxxxx.tar.gz | tar xvf -
|
||||
|
||||
This will create a directory "verilog-xxxxxxxx" that contains all the
|
||||
source for Icarus Verilog. Descend into that directory, as that is
|
||||
where we will work from now on.
|
||||
|
||||
$ cd verilog-xxxxxxxx
|
||||
|
||||
NOTES:
|
||||
The exact name of the file will vary according to the
|
||||
snapshot. The 20030303 name is only an example.
|
||||
|
||||
Unpack the source into a directory that has no spaces. The
|
||||
makefiles included in the source get confused by white space in
|
||||
directory names.
|
||||
|
||||
* Preconfigure Icarus Verilog (Not normally needed)
|
||||
|
||||
Under certain cases, you may need to "preconfigure" the Icarus Verilog
|
||||
source tree. You should only need to do this if you are getting the
|
||||
Icarus Verilog source tree from git, or you are using an existing
|
||||
source tree that you've patched to cause configure.in files to change.
|
||||
|
||||
NOTE: If you are building from a fresh, bundled source tree that
|
||||
you downloaded from an FTP site, then SKIP THIS STEP. Go on to
|
||||
the "Configure Icarus Verilog" step below.
|
||||
|
||||
First, remove any autom4te.cache directories that may exist in your
|
||||
source tree. These can make a mess of autoconf runs. Then, generate
|
||||
configure scripts with this command:
|
||||
|
||||
$ sh autoconf.sh
|
||||
|
||||
This script will run the "autoconf" command (part of the msysDTK) to
|
||||
generate all the necessary "configure" scripts. This will take a few
|
||||
minutes. This should go smoothly.
|
||||
|
||||
* Configure Icarus Verilog
|
||||
|
||||
Now we are all set to configure and compile Icarus Verilog. Choose a
|
||||
destination path where you will want to install the binaries. I chose
|
||||
on my system the directory "D:\iverilog". This choice is not
|
||||
permanent, so don't get too much angst over it. Just choose a name
|
||||
without white space.
|
||||
|
||||
Now, configure the source to make the makefiles and configuration
|
||||
details. Run these commands:
|
||||
|
||||
$ CPPFLAGS="-Ic:/gnuwin32/include
|
||||
$ LDFLAGS="-Lc:/gnuwin32/lib
|
||||
$ export CPPFLAGS LDFLAGS
|
||||
$ ./configure --prefix=c:/iverilog
|
||||
|
||||
NOTES:
|
||||
The CPPFLAGS and LDFLAGS variables tell configure where
|
||||
the gnuwin32 packages are. The configure program will
|
||||
write these values into the Makefiles, so you only need to
|
||||
keep these variables long enough for the configure program
|
||||
to work.
|
||||
|
||||
Your PATH variable was set in the previous step.
|
||||
|
||||
Use forward slashes as directory characters. All the various
|
||||
tools prefer the forward slash.
|
||||
|
||||
Substitute your chosen directory for the prefix. This will cause the
|
||||
makefiles to build and the source code to configure. The configure
|
||||
program will detect that this is a mingw environment and set things up
|
||||
to build properly.
|
||||
|
||||
(For a prefix, use the drive letter notation; the mingw compiled parts
|
||||
require it, and the Cygwin tools should be able to handle it. You may
|
||||
need to check or upgrade your Cygwin installation if this causes
|
||||
problems for you.)
|
||||
|
||||
|
||||
* Compile Icarus Verilog
|
||||
|
||||
This, believe it or not, should be the easy part:
|
||||
|
||||
$ make
|
||||
|
||||
It could take a while. Now is a good time to go get some coffee or
|
||||
take a tea break.
|
||||
|
||||
|
||||
* Install Icarus Verilog
|
||||
|
||||
If the compile ran OK, then next you install Icarus Verilog in the
|
||||
directory you have chosen. When you are ready, install like this:
|
||||
|
||||
$ make install
|
||||
|
||||
This is part of what the configure program did for you. The Makefiles
|
||||
now know to put the files under the D:\iverilog directory (or whatever
|
||||
directory you chose) and away you go.
|
||||
|
||||
You may find that you need to put some of the prerequisite DLLs into
|
||||
the d:\iverilog\bin directory. These include:
|
||||
|
||||
c:\mingw\bin\mingw10.dll
|
||||
c:\gnuwin32\bin\readline.dll
|
||||
c:\gnuwin32\bin\history.dll
|
||||
c:\gnuwin32\bin\bzip2.dll
|
||||
c:\gnuwin32\bin\zlib.dll
|
||||
|
||||
If you already have these in your Windows path (i.e. your system32
|
||||
directory) then you do not need to copy them into the iverilog
|
||||
directory. However, prepackaged Icarus Verilog binaries include these
|
||||
files.
|
||||
|
||||
* Running Icarus Verilog
|
||||
|
||||
Finally, put the C:\iverilog\bin directory in your Windows path, and
|
||||
you should be able to run the iverilog and vvp commands to your
|
||||
heart's content.
|
||||
|
||||
Currently, the iverilog.exe uses the path to itself to locate the
|
||||
libraries and modules associated with itself. In other words, if you
|
||||
execute the C:\iverilog\bin\iverilog.exe program, it will locate its
|
||||
subparts in the C:\iverilog directory and subdirectories below
|
||||
that. This means you can move the Icarus Verilog installation by
|
||||
simply moving the root directory and all its contents.
|
||||
|
||||
The vvp.pdf and iverilog.pdf files document the main commands. View
|
||||
these with Acrobat reader, or any other viewer capable of displaying
|
||||
PDF format files.
|
||||
http://iverilog.wikia.com/wiki/Installation_Guide#Compiling_on_MS_Windows_.28MinGW.29
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 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
|
||||
|
|
@ -42,7 +42,10 @@ unsigned count_lval_width(const NetAssign_*idx)
|
|||
NetAssign_::NetAssign_(NetAssign_*n)
|
||||
: nest_(n), sig_(0), word_(0), base_(0), sel_type_(IVL_SEL_OTHER)
|
||||
{
|
||||
lwid_ = 0;
|
||||
more = 0;
|
||||
signed_ = false;
|
||||
turn_sig_to_wire_on_release_ = false;
|
||||
}
|
||||
|
||||
NetAssign_::NetAssign_(NetNet*s)
|
||||
|
|
@ -51,6 +54,7 @@ NetAssign_::NetAssign_(NetNet*s)
|
|||
lwid_ = sig_->vector_width();
|
||||
sig_->incr_lref();
|
||||
more = 0;
|
||||
signed_ = false;
|
||||
turn_sig_to_wire_on_release_ = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
210
net_design.cc
210
net_design.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 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
|
||||
|
|
@ -101,11 +101,11 @@ uint64_t Design::scale_to_precision(uint64_t val,
|
|||
return val;
|
||||
}
|
||||
|
||||
NetScope* Design::make_root_scope(perm_string root, bool program_block,
|
||||
bool is_interface)
|
||||
NetScope* Design::make_root_scope(perm_string root, NetScope*unit_scope,
|
||||
bool program_block, bool is_interface)
|
||||
{
|
||||
NetScope *root_scope_;
|
||||
root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE,
|
||||
root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE, unit_scope,
|
||||
false, program_block, is_interface);
|
||||
/* This relies on the fact that the basename return value is
|
||||
permallocated. */
|
||||
|
|
@ -125,31 +125,18 @@ list<NetScope*> Design::find_root_scopes() const
|
|||
return root_scopes_;
|
||||
}
|
||||
|
||||
NetScope* Design::make_package_scope(perm_string name)
|
||||
NetScope* Design::make_package_scope(perm_string name, NetScope*unit_scope,
|
||||
bool is_unit)
|
||||
{
|
||||
NetScope*scope;
|
||||
|
||||
scope = new NetScope(0, hname_t(name), NetScope::PACKAGE, false, false);
|
||||
scope = new NetScope(0, hname_t(name), NetScope::PACKAGE, unit_scope,
|
||||
false, false, false, is_unit);
|
||||
scope->set_module_name(scope->basename());
|
||||
packages_[name] = scope;
|
||||
return scope;
|
||||
}
|
||||
|
||||
void Design::add_class(netclass_t*cl, PClass*pclass)
|
||||
{
|
||||
Definitions::add_class(cl);
|
||||
class_to_pclass_[cl] = pclass;
|
||||
}
|
||||
|
||||
netclass_t* Design::find_class(perm_string name) const
|
||||
{
|
||||
map<perm_string,netclass_t*>::const_iterator cur = classes_.find(name);
|
||||
if (cur != classes_.end())
|
||||
return cur->second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetScope* Design::find_package(perm_string name) const
|
||||
{
|
||||
map<perm_string,NetScope*>::const_iterator cur = packages_.find(name);
|
||||
|
|
@ -170,17 +157,6 @@ list<NetScope*> Design::find_package_scopes() const
|
|||
return res;
|
||||
}
|
||||
|
||||
list<NetScope*> Design::find_roottask_scopes() const
|
||||
{
|
||||
list<NetScope*>res;
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
res.push_back (cur->first);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method locates a scope in the design, given its rooted
|
||||
* hierarchical name. Each component of the key is used to scan one
|
||||
|
|
@ -211,25 +187,6 @@ NetScope* Design::find_scope(const std::list<hname_t>&path) const
|
|||
}
|
||||
}
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator root = root_tasks_.begin()
|
||||
; root != root_tasks_.end() ; ++ root) {
|
||||
|
||||
NetScope*cur = root->first;
|
||||
if (path.front() != cur->fullname())
|
||||
continue;
|
||||
|
||||
std::list<hname_t> tmp = path;
|
||||
tmp.pop_front();
|
||||
|
||||
while (cur) {
|
||||
if (tmp.empty()) return cur;
|
||||
|
||||
cur = cur->child( tmp.front() );
|
||||
|
||||
tmp.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -253,6 +210,49 @@ NetScope* Design::find_scope(const hname_t&path) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool is_design_unit(NetScope*scope)
|
||||
{
|
||||
return (scope->type() == NetScope::MODULE && !scope->nested_module())
|
||||
|| (scope->type() == NetScope::PACKAGE);
|
||||
}
|
||||
|
||||
static bool is_subroutine(NetScope::TYPE type)
|
||||
{
|
||||
return type == NetScope::TASK || type == NetScope::FUNC;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method locates a scope within another scope, given its relative
|
||||
* hierarchical name. Each component of the key is used to scan one
|
||||
* more step down the tree until the name runs out or the search
|
||||
* fails.
|
||||
*/
|
||||
NetScope* Design::find_scope_(NetScope*scope, const std::list<hname_t>&path,
|
||||
NetScope::TYPE type) const
|
||||
{
|
||||
std::list<hname_t> tmp = path;
|
||||
|
||||
do {
|
||||
hname_t key = tmp.front();
|
||||
/* If we are looking for a module or we are not
|
||||
* looking at the last path component check for
|
||||
* a name match (second line). */
|
||||
if (scope->type() == NetScope::MODULE
|
||||
&& (type == NetScope::MODULE || tmp.size() > 1)
|
||||
&& scope->module_name()==key.peek_name()) {
|
||||
|
||||
/* Up references may match module name */
|
||||
|
||||
} else {
|
||||
scope = scope->child( key );
|
||||
if (scope == 0) break;
|
||||
}
|
||||
tmp.pop_front();
|
||||
} while (! tmp.empty());
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a relative lookup of a scope by name. The starting point is
|
||||
* the scope parameter within which I start looking for the scope. If
|
||||
|
|
@ -266,36 +266,62 @@ NetScope* Design::find_scope(NetScope*scope, const std::list<hname_t>&path,
|
|||
if (path.empty())
|
||||
return scope;
|
||||
|
||||
for ( ; scope ; scope = scope->parent()) {
|
||||
// Record the compilation unit scope for use later.
|
||||
NetScope*unit_scope = scope->unit();
|
||||
|
||||
std::list<hname_t> tmp = path;
|
||||
// First search upwards through the hierarchy.
|
||||
while (scope) {
|
||||
NetScope*found_scope = find_scope_(scope, path, type);
|
||||
if (found_scope)
|
||||
return found_scope;
|
||||
|
||||
NetScope*cur = scope;
|
||||
do {
|
||||
hname_t key = tmp.front();
|
||||
/* If we are looking for a module or we are not
|
||||
* looking at the last path component check for
|
||||
* a name match (second line). */
|
||||
if (cur->type() == NetScope::MODULE
|
||||
&& (type == NetScope::MODULE || tmp.size() > 1)
|
||||
&& cur->module_name()==key.peek_name()) {
|
||||
// Avoid searching the unit scope twice.
|
||||
if (scope == unit_scope)
|
||||
unit_scope = 0;
|
||||
|
||||
/* Up references may match module name */
|
||||
// Special case - see IEEE 1800-2012 section 23.8.1.
|
||||
if (unit_scope && is_design_unit(scope) && is_subroutine(type)) {
|
||||
found_scope = find_scope_(unit_scope, path, type);
|
||||
if (found_scope)
|
||||
return found_scope;
|
||||
|
||||
} else {
|
||||
cur = cur->child( key );
|
||||
if (cur == 0) break;
|
||||
}
|
||||
tmp.pop_front();
|
||||
} while (! tmp.empty());
|
||||
unit_scope = 0;
|
||||
}
|
||||
|
||||
if (cur) return cur;
|
||||
scope = scope->parent();
|
||||
}
|
||||
|
||||
// If we haven't already done so, search the compilation unit scope.
|
||||
if (unit_scope) {
|
||||
NetScope*found_scope = find_scope_(unit_scope, path, type);
|
||||
if (found_scope)
|
||||
return found_scope;
|
||||
}
|
||||
|
||||
// Last chance. Look for the name starting at the root.
|
||||
return find_scope(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method locates a scope within another scope, given its relative
|
||||
* hierarchical name. Each component of the key is used to scan one
|
||||
* more step down the tree until the name runs out or the search
|
||||
* fails.
|
||||
*/
|
||||
NetScope* Design::find_scope_(NetScope*scope, const hname_t&path,
|
||||
NetScope::TYPE type) const
|
||||
{
|
||||
/* If we are looking for a module or we are not
|
||||
* looking at the last path component check for
|
||||
* a name match (second line). */
|
||||
if ((scope->type() == NetScope::MODULE) && (type == NetScope::MODULE)
|
||||
&& (scope->module_name() == path.peek_name())) {
|
||||
/* Up references may match module name */
|
||||
return scope;
|
||||
}
|
||||
return scope->child( path );
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a relative lookup of a scope by name. The starting point is
|
||||
* the scope parameter within which I start looking for the scope. If
|
||||
|
|
@ -307,24 +333,36 @@ NetScope* Design::find_scope(NetScope*scope, const hname_t&path,
|
|||
{
|
||||
assert(scope);
|
||||
|
||||
for ( ; scope ; scope = scope->parent()) {
|
||||
// Record the compilation unit scope for use later.
|
||||
NetScope*unit_scope = scope->unit();
|
||||
|
||||
NetScope*cur = scope;
|
||||
// First search upwards through the hierarchy.
|
||||
while (scope) {
|
||||
NetScope*found_scope = find_scope_(scope, path, type);
|
||||
if (found_scope)
|
||||
return found_scope;
|
||||
|
||||
/* If we are looking for a module or we are not
|
||||
* looking at the last path component check for
|
||||
* a name match (second line). */
|
||||
if (cur->type() == NetScope::MODULE
|
||||
&& (type == NetScope::MODULE)
|
||||
&& cur->module_name()==path.peek_name()) {
|
||||
// Avoid searching the unit scope twice.
|
||||
if (scope == unit_scope)
|
||||
unit_scope = 0;
|
||||
|
||||
/* Up references may match module name */
|
||||
// Special case - see IEEE 1800-2012 section 23.8.1.
|
||||
if (unit_scope && is_design_unit(scope) && is_subroutine(type)) {
|
||||
found_scope = find_scope_(unit_scope, path, type);
|
||||
if (found_scope)
|
||||
return found_scope;
|
||||
|
||||
} else {
|
||||
cur = cur->child( path );
|
||||
unit_scope = 0;
|
||||
}
|
||||
|
||||
if (cur) return cur;
|
||||
scope = scope->parent();
|
||||
}
|
||||
|
||||
// If we haven't already done so, search the compilation unit scope.
|
||||
if (unit_scope) {
|
||||
NetScope*found_scope = find_scope_(unit_scope, path, type);
|
||||
if (found_scope)
|
||||
return found_scope;
|
||||
}
|
||||
|
||||
// Last chance. Look for the name starting at the root.
|
||||
|
|
@ -847,6 +885,7 @@ NetFuncDef* Design::find_function(NetScope*scope, const pform_name_t&name)
|
|||
// the function's signals have been elaborated. If this is
|
||||
// the case, elaborate them now.
|
||||
if (func->elab_stage() < 2) {
|
||||
func->need_const_func(true);
|
||||
const PFunction*pfunc = func->func_pform();
|
||||
assert(pfunc);
|
||||
pfunc->elaborate_sig(this, func);
|
||||
|
|
@ -866,11 +905,6 @@ NetScope* Design::find_task(NetScope*scope, const pform_name_t&name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Design::add_root_task(NetScope*tscope, PTaskFunc*tf)
|
||||
{
|
||||
root_tasks_[tscope] = tf;
|
||||
}
|
||||
|
||||
void Design::add_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
|
|
@ -889,8 +923,8 @@ void Design::add_node(NetNode*net)
|
|||
|
||||
void Design::del_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == this);
|
||||
assert(net != 0);
|
||||
assert(net->design_ == this);
|
||||
|
||||
/* Interact with the Design::functor method by manipulating the
|
||||
cur and nxt pointers that it is using. */
|
||||
|
|
|
|||
11
net_event.cc
11
net_event.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
NetEvent::NetEvent(perm_string n)
|
||||
: name_(n)
|
||||
{
|
||||
local_flag_ = false;
|
||||
scope_ = 0;
|
||||
snext_ = 0;
|
||||
probes_ = 0;
|
||||
|
|
@ -345,7 +346,7 @@ void NetEvProbe::find_similar_probes(list<NetEvProbe*>&plist)
|
|||
}
|
||||
|
||||
NetEvWait::NetEvWait(NetProc*pr)
|
||||
: statement_(pr)
|
||||
: statement_(pr), has_t0_trigger_(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -369,6 +370,7 @@ NetEvWait::~NetEvWait()
|
|||
tmp->next = tmp->next->next;
|
||||
delete tmp;
|
||||
}
|
||||
delete tgt;
|
||||
}
|
||||
events_.clear();
|
||||
}
|
||||
|
|
@ -441,3 +443,8 @@ NetProc* NetEvWait::statement()
|
|||
{
|
||||
return statement_;
|
||||
}
|
||||
|
||||
const NetProc* NetEvWait::statement() const
|
||||
{
|
||||
return statement_;
|
||||
}
|
||||
|
|
|
|||
160
net_func_eval.cc
160
net_func_eval.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2018 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -23,6 +23,10 @@
|
|||
# include <typeinfo>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#define unique_ptr auto_ptr
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
|
|
@ -88,6 +92,10 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
|
|||
// fills in the context_map with local variables held by the scope.
|
||||
scope()->evaluate_function_find_locals(loc, context_map);
|
||||
|
||||
// Execute any variable initialization statements.
|
||||
if (const NetProc*init_proc = scope()->var_init())
|
||||
init_proc->evaluate_function(loc, context_map);
|
||||
|
||||
if (debug_eval_tree && proc_==0) {
|
||||
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
||||
<< "Function " << scope_path(scope())
|
||||
|
|
@ -209,6 +217,98 @@ bool NetProc::evaluate_function(const LineInfo&,
|
|||
return false;
|
||||
}
|
||||
|
||||
void NetAssign::eval_func_lval_op_real_(const LineInfo&loc,
|
||||
verireal&lv, verireal&rv) const
|
||||
{
|
||||
switch (op_) {
|
||||
case '+':
|
||||
lv = lv + rv;
|
||||
break;
|
||||
case '-':
|
||||
lv = lv - rv;
|
||||
break;
|
||||
case '*':
|
||||
lv = lv * rv;
|
||||
break;
|
||||
case '/':
|
||||
lv = lv / rv;
|
||||
break;
|
||||
case '%':
|
||||
lv = lv % rv;
|
||||
break;
|
||||
default:
|
||||
cerr << "Illegal assignment operator: "
|
||||
<< human_readable_op(op_) << endl;
|
||||
ivl_assert(loc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void NetAssign::eval_func_lval_op_(const LineInfo&loc,
|
||||
verinum&lv, verinum&rv) const
|
||||
{
|
||||
unsigned lv_width = lv.len();
|
||||
bool lv_sign = lv.has_sign();
|
||||
switch (op_) {
|
||||
case 'l':
|
||||
case 'R':
|
||||
// The left operand is self-determined.
|
||||
break;
|
||||
case 'r':
|
||||
// The left operand is self-determined, but we need to
|
||||
// cast it to unsigned to get a logical shift.
|
||||
lv.has_sign(false);
|
||||
break;
|
||||
default:
|
||||
// The left operand must be cast to the expression type/size
|
||||
lv.has_sign(rv.has_sign());
|
||||
lv = cast_to_width(lv, rv.len());
|
||||
}
|
||||
switch (op_) {
|
||||
case '+':
|
||||
lv = lv + rv;
|
||||
break;
|
||||
case '-':
|
||||
lv = lv - rv;
|
||||
break;
|
||||
case '*':
|
||||
lv = lv * rv;
|
||||
break;
|
||||
case '/':
|
||||
lv = lv / rv;
|
||||
break;
|
||||
case '%':
|
||||
lv = lv % rv;
|
||||
break;
|
||||
case '&':
|
||||
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
||||
lv.set(idx, lv[idx] & rv[idx]);
|
||||
break;
|
||||
case '|':
|
||||
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
||||
lv.set(idx, lv[idx] | rv[idx]);
|
||||
break;
|
||||
case '^':
|
||||
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
||||
lv.set(idx, lv[idx] ^ rv[idx]);
|
||||
break;
|
||||
case 'l':
|
||||
lv = lv << rv.as_unsigned();
|
||||
break;
|
||||
case 'r':
|
||||
lv = lv >> rv.as_unsigned();
|
||||
break;
|
||||
case 'R':
|
||||
lv = lv >> rv.as_unsigned();
|
||||
break;
|
||||
default:
|
||||
cerr << "Illegal assignment operator: "
|
||||
<< human_readable_op(op_) << endl;
|
||||
ivl_assert(loc, 0);
|
||||
}
|
||||
lv = cast_to_width(lv, lv_width);
|
||||
lv.has_sign(lv_sign);
|
||||
}
|
||||
|
||||
bool NetAssign::eval_func_lval_(const LineInfo&loc,
|
||||
map<perm_string,LocalVar>&context_map,
|
||||
const NetAssign_*lval, NetExpr*rval_result) const
|
||||
|
|
@ -269,18 +369,55 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
|
|||
ivl_assert(loc, base + lval->lwidth() <= old_lval->expr_width());
|
||||
|
||||
NetEConst*lval_const = dynamic_cast<NetEConst*>(old_lval);
|
||||
ivl_assert(loc, lval_const);
|
||||
verinum lval_v = lval_const->value();
|
||||
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
|
||||
verinum rval_v = cast_to_width(rval_const->value(), lval->lwidth());
|
||||
ivl_assert(loc, rval_const);
|
||||
verinum rval_v = rval_const->value();
|
||||
|
||||
for (unsigned idx = 0 ; idx < rval_v.len() ; idx += 1)
|
||||
lval_v.set(idx+base, rval_v[idx]);
|
||||
verinum lpart(verinum::Vx, lval->lwidth());
|
||||
if (op_) {
|
||||
for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1)
|
||||
lpart.set(idx, lval_v[base+idx]);
|
||||
|
||||
eval_func_lval_op_(loc, lpart, rval_v);
|
||||
} else {
|
||||
lpart = cast_to_width(rval_v, lval->lwidth());
|
||||
}
|
||||
for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1)
|
||||
lval_v.set(idx+base, lpart[idx]);
|
||||
|
||||
delete base_result;
|
||||
delete rval_result;
|
||||
rval_result = new NetEConst(lval_v);
|
||||
} else {
|
||||
rval_result = fix_assign_value(lval->sig(), rval_result);
|
||||
if (op_ == 0) {
|
||||
rval_result = fix_assign_value(lval->sig(), rval_result);
|
||||
} else if (dynamic_cast<NetECReal*>(rval_result)) {
|
||||
NetECReal*lval_const = dynamic_cast<NetECReal*>(old_lval);
|
||||
ivl_assert(loc, lval_const);
|
||||
verireal lval_r = lval_const->value();
|
||||
NetECReal*rval_const = dynamic_cast<NetECReal*>(rval_result);
|
||||
ivl_assert(loc, rval_const);
|
||||
verireal rval_r = rval_const->value();
|
||||
|
||||
eval_func_lval_op_real_(loc, lval_r, rval_r);
|
||||
|
||||
delete rval_result;
|
||||
rval_result = new NetECReal(lval_r);
|
||||
} else {
|
||||
NetEConst*lval_const = dynamic_cast<NetEConst*>(old_lval);
|
||||
ivl_assert(loc, lval_const);
|
||||
verinum lval_v = lval_const->value();
|
||||
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
|
||||
ivl_assert(loc, rval_const);
|
||||
verinum rval_v = rval_const->value();
|
||||
|
||||
eval_func_lval_op_(loc, lval_v, rval_v);
|
||||
|
||||
delete rval_result;
|
||||
rval_result = new NetEConst(lval_v);
|
||||
}
|
||||
}
|
||||
|
||||
if (old_lval)
|
||||
|
|
@ -318,6 +455,13 @@ bool NetAssign::evaluate_function(const LineInfo&loc,
|
|||
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
|
||||
ivl_assert(*this, rval_const);
|
||||
|
||||
if (op_) {
|
||||
cerr << get_fileline() << ": sorry: Assignment operators "
|
||||
"inside a constant function are not currently "
|
||||
"supported if the LHS is a concatenation." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
verinum rval_full = rval_const->value();
|
||||
delete rval_result;
|
||||
|
||||
|
|
@ -369,6 +513,10 @@ bool NetBlock::evaluate_function(const LineInfo&loc,
|
|||
// Now collect the new locals.
|
||||
subscope_->evaluate_function_find_locals(loc, local_context_map);
|
||||
use_local_context_map = true;
|
||||
|
||||
// Execute any variable initialization statements.
|
||||
if (const NetProc*init_proc = subscope_->var_init())
|
||||
init_proc->evaluate_function(loc, local_context_map);
|
||||
}
|
||||
|
||||
// Now use the local context map if there is any local
|
||||
|
|
@ -874,7 +1022,7 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
|
|||
NetExpr* NetETernary::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,LocalVar>&context_map) const
|
||||
{
|
||||
auto_ptr<NetExpr> cval (cond_->evaluate_function(loc, context_map));
|
||||
unique_ptr<NetExpr> cval (cond_->evaluate_function(loc, context_map));
|
||||
|
||||
switch (const_logical(cval.get())) {
|
||||
|
||||
|
|
|
|||
27
net_link.cc
27
net_link.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2016 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
|
||||
|
|
@ -311,6 +311,20 @@ void Nexus::count_io(unsigned&inp, unsigned&out) const
|
|||
}
|
||||
}
|
||||
|
||||
bool Nexus::has_floating_input() const
|
||||
{
|
||||
bool found_input = false;
|
||||
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
if (cur->get_dir() == Link::OUTPUT)
|
||||
return false;
|
||||
|
||||
if (cur->get_dir() == Link::INPUT)
|
||||
found_input = true;
|
||||
}
|
||||
|
||||
return found_input;
|
||||
}
|
||||
|
||||
bool Nexus::drivers_present() const
|
||||
{
|
||||
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
|
|
@ -467,6 +481,17 @@ NetNet* Nexus::pick_any_net()
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetNode* Nexus::pick_any_node()
|
||||
{
|
||||
for (Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
NetNode*node = dynamic_cast<NetNode*>(cur->get_obj());
|
||||
if (node != 0)
|
||||
return node;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* Nexus::name() const
|
||||
{
|
||||
if (name_)
|
||||
|
|
|
|||
341
net_nex_input.cc
341
net_nex_input.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -27,29 +27,29 @@
|
|||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
NexusSet* NetExpr::nex_input(bool)
|
||||
NexusSet* NetExpr::nex_input(bool, bool) const
|
||||
{
|
||||
cerr << get_fileline()
|
||||
<< ": internal error: nex_input not implemented: "
|
||||
<< *this << endl;
|
||||
return 0;
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetProc::nex_input(bool)
|
||||
NexusSet* NetProc::nex_input(bool, bool) const
|
||||
{
|
||||
cerr << get_fileline()
|
||||
<< ": internal error: NetProc::nex_input not implemented"
|
||||
<< endl;
|
||||
return 0;
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEArrayPattern::nex_input(bool rem_out)
|
||||
NexusSet* NetEArrayPattern::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = new NexusSet;
|
||||
for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
|
||||
if (items_[idx]==0) continue;
|
||||
|
||||
NexusSet*tmp = items_[idx]->nex_input(rem_out);
|
||||
NexusSet*tmp = items_[idx]->nex_input(rem_out, search_funcs);
|
||||
if (tmp == 0) continue;
|
||||
|
||||
result->add(*tmp);
|
||||
|
|
@ -58,32 +58,32 @@ NexusSet* NetEArrayPattern::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEBinary::nex_input(bool rem_out)
|
||||
NexusSet* NetEBinary::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = left_->nex_input(rem_out);
|
||||
NexusSet*tmp = right_->nex_input(rem_out);
|
||||
NexusSet*result = left_->nex_input(rem_out, search_funcs);
|
||||
NexusSet*tmp = right_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEConcat::nex_input(bool rem_out)
|
||||
NexusSet* NetEConcat::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
if (parms_[0] == NULL) return NULL;
|
||||
NexusSet*result = parms_[0]->nex_input(rem_out);
|
||||
if (parms_[0] == NULL) return new NexusSet;
|
||||
NexusSet*result = parms_[0]->nex_input(rem_out, search_funcs);
|
||||
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_[idx] == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
return new NexusSet;
|
||||
}
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEAccess::nex_input(bool)
|
||||
NexusSet* NetEAccess::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
|
@ -91,59 +91,55 @@ NexusSet* NetEAccess::nex_input(bool)
|
|||
/*
|
||||
* A constant has not inputs, so always return an empty set.
|
||||
*/
|
||||
NexusSet* NetEConst::nex_input(bool)
|
||||
NexusSet* NetEConst::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetECReal::nex_input(bool)
|
||||
NexusSet* NetECReal::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEEvent::nex_input(bool)
|
||||
NexusSet* NetEEvent::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetELast::nex_input(bool)
|
||||
NexusSet* NetELast::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetENetenum::nex_input(bool)
|
||||
NexusSet* NetENetenum::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetENew::nex_input(bool)
|
||||
NexusSet* NetENew::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetENull::nex_input(bool)
|
||||
NexusSet* NetENull::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEProperty::nex_input(bool)
|
||||
NexusSet* NetEProperty::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEScope::nex_input(bool)
|
||||
NexusSet* NetEScope::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetESelect::nex_input(bool rem_out)
|
||||
NexusSet* NetESelect::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet();
|
||||
NexusSet*tmp = expr_->nex_input(rem_out);
|
||||
if (tmp == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
NexusSet*result = base_? base_->nex_input(rem_out, search_funcs) : new NexusSet();
|
||||
NexusSet*tmp = expr_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
/* See the comment for NetESignal below. */
|
||||
|
|
@ -157,30 +153,29 @@ NexusSet* NetESelect::nex_input(bool rem_out)
|
|||
/*
|
||||
* The $fread, etc. system functions can have NULL arguments.
|
||||
*/
|
||||
NexusSet* NetESFunc::nex_input(bool rem_out)
|
||||
NexusSet* NetESFunc::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
if (parms_.empty())
|
||||
return new NexusSet;
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
NexusSet*result;
|
||||
if (parms_[0]) result = parms_[0]->nex_input(rem_out);
|
||||
else result = new NexusSet;
|
||||
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_.empty()) return result;
|
||||
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_[idx]) {
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEShallowCopy::nex_input(bool)
|
||||
NexusSet* NetEShallowCopy::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetESignal::nex_input(bool rem_out)
|
||||
NexusSet* NetESignal::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
/*
|
||||
* This is not what I would expect for the various selects (bit,
|
||||
|
|
@ -194,7 +189,7 @@ NexusSet* NetESignal::nex_input(bool rem_out)
|
|||
/* If we have an array index add it to the sensitivity list. */
|
||||
if (word_) {
|
||||
NexusSet*tmp;
|
||||
tmp = word_->nex_input(rem_out);
|
||||
tmp = word_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
if (warn_sens_entire_arr) {
|
||||
|
|
@ -209,27 +204,44 @@ NexusSet* NetESignal::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetETernary::nex_input(bool rem_out)
|
||||
NexusSet* NetETernary::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*tmp;
|
||||
NexusSet*result = cond_->nex_input(rem_out);
|
||||
NexusSet*result = cond_->nex_input(rem_out, search_funcs);
|
||||
|
||||
tmp = true_val_->nex_input(rem_out);
|
||||
tmp = true_val_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
tmp = false_val_->nex_input(rem_out);
|
||||
tmp = false_val_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEUFunc::nex_input(bool rem_out)
|
||||
NexusSet* NetEUFunc::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = new NexusSet;
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (search_funcs) {
|
||||
NetFuncDef*func = func_->func_def();
|
||||
NexusSet*tmp = func->proc()->nex_input(rem_out, search_funcs);
|
||||
// Remove the function inputs
|
||||
NexusSet*in = new NexusSet;
|
||||
for (unsigned idx = 0 ; idx < func->port_count() ; idx += 1) {
|
||||
NetNet*net = func->port(idx);
|
||||
assert(net->pin_count() == 1);
|
||||
in->add(net->pin(0).nexus(), 0, net->vector_width());
|
||||
}
|
||||
tmp->rem(*in);
|
||||
delete in;
|
||||
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -237,21 +249,28 @@ NexusSet* NetEUFunc::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEUnary::nex_input(bool rem_out)
|
||||
NexusSet* NetEUnary::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
return expr_->nex_input(rem_out);
|
||||
return expr_->nex_input(rem_out, search_funcs);
|
||||
}
|
||||
|
||||
NexusSet* NetAssign_::nex_input(bool rem_out)
|
||||
NexusSet* NetAlloc::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetAssign_::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
assert(! nest_);
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
if (word_) {
|
||||
NexusSet*tmp = word_->nex_input(rem_out);
|
||||
NexusSet*tmp = word_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
if (base_) {
|
||||
NexusSet*tmp = base_->nex_input(rem_out);
|
||||
NexusSet*tmp = base_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -259,15 +278,21 @@ NexusSet* NetAssign_::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetAssignBase::nex_input(bool rem_out)
|
||||
NexusSet* NetAssignBase::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = rval_->nex_input(rem_out);
|
||||
NexusSet*result = new NexusSet;
|
||||
// For the deassign and release statements there is no R-value.
|
||||
if (rval_) {
|
||||
NexusSet*tmp = rval_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
/* It is possible that the lval_ can have nex_input values. In
|
||||
particular, index expressions are statement inputs as well,
|
||||
so should be addressed here. */
|
||||
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) {
|
||||
NexusSet*tmp = cur->nex_input(rem_out);
|
||||
NexusSet*tmp = cur->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -292,16 +317,15 @@ NexusSet* NetAssignBase::nex_input(bool rem_out)
|
|||
* In this example, "t" should not be in the input set because it is
|
||||
* used by the sequence as a temporary value.
|
||||
*/
|
||||
NexusSet* NetBlock::nex_input(bool rem_out)
|
||||
NexusSet* NetBlock::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
if (last_ == 0)
|
||||
return new NexusSet;
|
||||
if (last_ == 0) return new NexusSet;
|
||||
|
||||
if (type_ != SEQU) {
|
||||
if (! search_funcs && (type_ != SEQU)) {
|
||||
cerr << get_fileline() << ": internal error: Sorry, "
|
||||
<< "I don't know how to synthesize fork/join blocks."
|
||||
<< endl;
|
||||
return 0;
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NetProc*cur = last_->next_;
|
||||
|
|
@ -312,10 +336,10 @@ NexusSet* NetBlock::nex_input(bool rem_out)
|
|||
|
||||
do {
|
||||
/* Get the inputs for the current statement. */
|
||||
NexusSet*tmp = cur->nex_input(rem_out);
|
||||
NexusSet*tmp = cur->nex_input(rem_out, search_funcs);
|
||||
|
||||
/* Add the current input set to the accumulated input set. */
|
||||
if (tmp != 0) result->add(*tmp);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
/* Add the current outputs to the accumulated output set if
|
||||
|
|
@ -339,11 +363,9 @@ NexusSet* NetBlock::nex_input(bool rem_out)
|
|||
* the inputs to all the guards, and the inputs to all the guarded
|
||||
* statements.
|
||||
*/
|
||||
NexusSet* NetCase::nex_input(bool rem_out)
|
||||
NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = expr_->nex_input(rem_out);
|
||||
if (result == 0)
|
||||
return 0;
|
||||
NexusSet*result = expr_->nex_input(rem_out, search_funcs);
|
||||
|
||||
for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
|
||||
|
||||
|
|
@ -351,8 +373,7 @@ NexusSet* NetCase::nex_input(bool rem_out)
|
|||
if (items_[idx].statement == 0)
|
||||
continue;
|
||||
|
||||
NexusSet*tmp = items_[idx].statement->nex_input(rem_out);
|
||||
assert(tmp);
|
||||
NexusSet*tmp = items_[idx].statement->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
|
|
@ -360,8 +381,7 @@ NexusSet* NetCase::nex_input(bool rem_out)
|
|||
case is special and is identified by a null
|
||||
guard. The default guard obviously has no input. */
|
||||
if (items_[idx].guard) {
|
||||
tmp = items_[idx].guard->nex_input(rem_out);
|
||||
assert(tmp);
|
||||
tmp = items_[idx].guard->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -370,24 +390,18 @@ NexusSet* NetCase::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetCAssign::nex_input(bool)
|
||||
NexusSet* NetCondit::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
cerr << get_fileline() << ": internal warning: NetCAssign::nex_input()"
|
||||
<< " not implemented." << endl;
|
||||
return new NexusSet;
|
||||
}
|
||||
NexusSet*result = expr_->nex_input(rem_out, search_funcs);
|
||||
|
||||
NexusSet* NetCondit::nex_input(bool rem_out)
|
||||
{
|
||||
NexusSet*result = expr_->nex_input(rem_out);
|
||||
if (if_ != 0) {
|
||||
NexusSet*tmp = if_->nex_input(rem_out);
|
||||
NexusSet*tmp = if_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (else_ != 0) {
|
||||
NexusSet*tmp = else_->nex_input(rem_out);
|
||||
NexusSet*tmp = else_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -395,47 +409,100 @@ NexusSet* NetCondit::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetDoWhile::nex_input(bool rem_out)
|
||||
NexusSet* NetDisable::nex_input(bool, bool) const
|
||||
{
|
||||
NexusSet*result = proc_->nex_input(rem_out);
|
||||
NexusSet*tmp = cond_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetForce::nex_input(bool)
|
||||
{
|
||||
cerr << get_fileline() << ": internal warning: NetForce::nex_input()"
|
||||
<< " not implemented." << endl;
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetForLoop::nex_input(bool rem_out)
|
||||
NexusSet* NetDoWhile::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = init_expr_->nex_input(rem_out);
|
||||
NexusSet*result = cond_->nex_input(rem_out, search_funcs);
|
||||
|
||||
NexusSet*tmp = condition_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
tmp = statement_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
tmp = step_statement_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
if (proc_) {
|
||||
NexusSet*tmp = proc_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetForever::nex_input(bool rem_out)
|
||||
NexusSet* NetEvTrig::nex_input(bool, bool) const
|
||||
{
|
||||
NexusSet*result = statement_->nex_input(rem_out);
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEvWait::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
if (statement_) {
|
||||
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetForever::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
if (statement_) {
|
||||
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetForLoop::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
if (init_expr_) {
|
||||
NexusSet*tmp = init_expr_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (condition_) {
|
||||
NexusSet*tmp = condition_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (step_statement_) {
|
||||
NexusSet*tmp = step_statement_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (statement_) {
|
||||
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (gn_shared_loop_index_flag) {
|
||||
NexusSet*tmp = new NexusSet();
|
||||
for (unsigned idx = 0 ; idx < index_->pin_count() ; idx += 1)
|
||||
tmp->add(index_->pin(idx).nexus(), 0, index_->vector_width());
|
||||
|
||||
result->rem(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetFree::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NetPDelay statement is a statement of the form
|
||||
*
|
||||
|
|
@ -445,36 +512,44 @@ NexusSet* NetForever::nex_input(bool rem_out)
|
|||
* include the input set of the <expr> because it does not affect the
|
||||
* result. The statement can be omitted.
|
||||
*/
|
||||
NexusSet* NetPDelay::nex_input(bool rem_out)
|
||||
NexusSet* NetPDelay::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
if (statement_ == 0) return 0;
|
||||
NexusSet*result = statement_->nex_input(rem_out);
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
if (statement_) {
|
||||
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetRepeat::nex_input(bool rem_out)
|
||||
NexusSet* NetRepeat::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = statement_->nex_input(rem_out);
|
||||
NexusSet*tmp = expr_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
NexusSet*result = expr_->nex_input(rem_out, search_funcs);
|
||||
|
||||
if (statement_) {
|
||||
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The $display, etc. system tasks can have NULL arguments.
|
||||
*/
|
||||
NexusSet* NetSTask::nex_input(bool rem_out)
|
||||
NexusSet* NetSTask::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
if (parms_.empty())
|
||||
return new NexusSet;
|
||||
NexusSet*result = new NexusSet;
|
||||
|
||||
NexusSet*result;
|
||||
if (parms_[0]) result = parms_[0]->nex_input(rem_out);
|
||||
else result = new NexusSet;
|
||||
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_.empty()) return result;
|
||||
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_[idx]) {
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -488,16 +563,20 @@ NexusSet* NetSTask::nex_input(bool rem_out)
|
|||
* parameters to consider, because the compiler already removed them
|
||||
* and converted them to blocking assignments.
|
||||
*/
|
||||
NexusSet* NetUTask::nex_input(bool)
|
||||
NexusSet* NetUTask::nex_input(bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetWhile::nex_input(bool rem_out)
|
||||
NexusSet* NetWhile::nex_input(bool rem_out, bool search_funcs) const
|
||||
{
|
||||
NexusSet*result = proc_->nex_input(rem_out);
|
||||
NexusSet*tmp = cond_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
NexusSet*result = cond_->nex_input(rem_out, search_funcs);
|
||||
|
||||
if (proc_) {
|
||||
NexusSet*tmp = proc_->nex_input(rem_out, search_funcs);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2017 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
|
||||
|
|
@ -36,8 +36,13 @@ void NetProc::nex_output(NexusSet&)
|
|||
<< endl;
|
||||
}
|
||||
|
||||
void NetAlloc::nex_output(NexusSet&)
|
||||
{
|
||||
}
|
||||
|
||||
void NetAssign_::nex_output(NexusSet&out)
|
||||
{
|
||||
assert(! nest_);
|
||||
assert(sig_);
|
||||
unsigned use_word = 0;
|
||||
unsigned use_base = 0;
|
||||
|
|
@ -89,8 +94,7 @@ void NetAssignBase::nex_output(NexusSet&out)
|
|||
|
||||
void NetBlock::nex_output(NexusSet&out)
|
||||
{
|
||||
if (last_ == 0)
|
||||
return;
|
||||
if (last_ == 0) return;
|
||||
|
||||
NetProc*cur = last_;
|
||||
do {
|
||||
|
|
@ -104,10 +108,8 @@ void NetCase::nex_output(NexusSet&out)
|
|||
for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
|
||||
|
||||
// Empty statements clearly have no output.
|
||||
if (items_[idx].statement == 0)
|
||||
continue;
|
||||
if (items_[idx].statement == 0) continue;
|
||||
|
||||
assert(items_[idx].statement);
|
||||
items_[idx].statement->nex_output(out);
|
||||
}
|
||||
|
||||
|
|
@ -115,22 +117,31 @@ void NetCase::nex_output(NexusSet&out)
|
|||
|
||||
void NetCondit::nex_output(NexusSet&out)
|
||||
{
|
||||
if (if_ != 0)
|
||||
if_->nex_output(out);
|
||||
if (else_ != 0)
|
||||
else_->nex_output(out);
|
||||
if (if_) if_->nex_output(out);
|
||||
if (else_) else_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetDisable::nex_output(NexusSet&)
|
||||
{
|
||||
}
|
||||
|
||||
void NetDoWhile::nex_output(NexusSet&out)
|
||||
{
|
||||
if (proc_ != 0)
|
||||
proc_->nex_output(out);
|
||||
if (proc_) proc_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetEvTrig::nex_output(NexusSet&)
|
||||
{
|
||||
}
|
||||
|
||||
void NetEvWait::nex_output(NexusSet&out)
|
||||
{
|
||||
assert(statement_);
|
||||
statement_->nex_output(out);
|
||||
if (statement_) statement_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetForever::nex_output(NexusSet&out)
|
||||
{
|
||||
if (statement_) statement_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetForLoop::nex_output(NexusSet&out)
|
||||
|
|
@ -138,11 +149,20 @@ void NetForLoop::nex_output(NexusSet&out)
|
|||
if (statement_) statement_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetFree::nex_output(NexusSet&)
|
||||
{
|
||||
}
|
||||
|
||||
void NetPDelay::nex_output(NexusSet&out)
|
||||
{
|
||||
if (statement_) statement_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetRepeat::nex_output(NexusSet&out)
|
||||
{
|
||||
if (statement_) statement_->nex_output(out);
|
||||
}
|
||||
|
||||
/*
|
||||
* For the purposes of synthesis, system task calls have no output at
|
||||
* all. This is OK because most system tasks are not synthesizable in
|
||||
|
|
@ -163,6 +183,5 @@ void NetUTask::nex_output(NexusSet&)
|
|||
|
||||
void NetWhile::nex_output(NexusSet&out)
|
||||
{
|
||||
if (proc_ != 0)
|
||||
proc_->nex_output(out);
|
||||
if (proc_) proc_->nex_output(out);
|
||||
}
|
||||
|
|
|
|||
14
net_proc.cc
14
net_proc.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 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
|
||||
|
|
@ -56,6 +56,17 @@ void NetBlock::append(NetProc*cur)
|
|||
}
|
||||
}
|
||||
|
||||
void NetBlock::prepend(NetProc*cur)
|
||||
{
|
||||
if (last_ == 0) {
|
||||
last_ = cur;
|
||||
cur->next_ = cur;
|
||||
} else {
|
||||
cur->next_ = last_->next_;
|
||||
last_->next_ = cur;
|
||||
}
|
||||
}
|
||||
|
||||
const NetProc* NetBlock::proc_first() const
|
||||
{
|
||||
if (last_ == 0)
|
||||
|
|
@ -188,6 +199,7 @@ NetForever::~NetForever()
|
|||
NetForLoop::NetForLoop(NetNet*ind, NetExpr*iexpr, NetExpr*cond, NetProc*sub, NetProc*step)
|
||||
: index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step)
|
||||
{
|
||||
as_block_ = NULL;
|
||||
}
|
||||
|
||||
void NetForLoop::wrap_up()
|
||||
|
|
|
|||
120
net_scope.cc
120
net_scope.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -23,6 +24,7 @@
|
|||
# include "netlist.h"
|
||||
# include "netclass.h"
|
||||
# include "netenum.h"
|
||||
# include "netvector.h"
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
|
|
@ -110,10 +112,10 @@ void Definitions::add_class(netclass_t*net_class)
|
|||
* in question.
|
||||
*/
|
||||
|
||||
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
||||
bool program, bool interface)
|
||||
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, NetScope*in_unit,
|
||||
bool nest, bool program, bool interface, bool compilation_unit)
|
||||
: type_(t), name_(n), nested_module_(nest), program_block_(program),
|
||||
is_interface_(interface), up_(up)
|
||||
is_interface_(interface), is_unit_(compilation_unit), unit_(in_unit), up_(up)
|
||||
{
|
||||
events_ = 0;
|
||||
lcounter_ = 0;
|
||||
|
|
@ -122,6 +124,9 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
|||
calls_stask_ = false;
|
||||
in_final_ = false;
|
||||
|
||||
if (compilation_unit)
|
||||
unit_ = this;
|
||||
|
||||
if (up) {
|
||||
assert(t!=CLASS);
|
||||
need_const_func_ = up->need_const_func_;
|
||||
|
|
@ -131,6 +136,8 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
|||
time_from_timescale_ = up->time_from_timescale();
|
||||
// Need to check for duplicate names?
|
||||
up_->children_[name_] = this;
|
||||
if (unit_ == 0)
|
||||
unit_ = up_->unit_;
|
||||
} else {
|
||||
need_const_func_ = false;
|
||||
is_const_func_ = false;
|
||||
|
|
@ -139,6 +146,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
|||
time_from_timescale_ = false;
|
||||
}
|
||||
|
||||
var_init_ = 0;
|
||||
switch (t) {
|
||||
case NetScope::TASK:
|
||||
task_ = 0;
|
||||
|
|
@ -161,6 +169,8 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
|||
lineno_ = 0;
|
||||
def_lineno_ = 0;
|
||||
genvar_tmp_val = 0;
|
||||
tie_hi_ = 0;
|
||||
tie_lo_ = 0;
|
||||
}
|
||||
|
||||
NetScope::~NetScope()
|
||||
|
|
@ -205,6 +215,8 @@ const netenum_t*NetScope::find_enumeration_for_name(perm_string name)
|
|||
NetEConstEnum*tmp = cur_scope->enum_names_[name];
|
||||
if (tmp) break;
|
||||
cur_scope = cur_scope->parent();
|
||||
if (cur_scope == 0)
|
||||
cur_scope = unit_;
|
||||
}
|
||||
|
||||
assert(cur_scope);
|
||||
|
|
@ -264,19 +276,20 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix)
|
|||
assert(self != up_->children_.end());
|
||||
assert(self->second == this);
|
||||
|
||||
char tmp[32];
|
||||
int pad_pos = strlen(prefix);
|
||||
int max_pos = sizeof(tmp) - strlen(suffix) - 1;
|
||||
strncpy(tmp, prefix, sizeof(tmp));
|
||||
tmp[31] = 0;
|
||||
// This is to keep the pad attempts from being stuck in some
|
||||
// sort of infinite loop. This should not be a practical
|
||||
// limit, but an extreme one.
|
||||
const size_t max_pad_attempts = 32 + strlen(prefix);
|
||||
|
||||
string use_prefix = prefix;
|
||||
|
||||
// Try a variety of potential new names. Make sure the new
|
||||
// name is not in the parent scope. Keep looking until we are
|
||||
// sure we have a unique name, or we run out of names to try.
|
||||
while (pad_pos <= max_pos) {
|
||||
while (use_prefix.size() <= max_pad_attempts) {
|
||||
// Try this name...
|
||||
strcat(tmp + pad_pos, suffix);
|
||||
hname_t new_name(lex_strings.make(tmp));
|
||||
string tmp = use_prefix + suffix;
|
||||
hname_t new_name(lex_strings.make(tmp.c_str()), name_.peek_numbers());
|
||||
if (!up_->child(new_name)) {
|
||||
// Ah, this name is unique. Rename myself, and
|
||||
// change my name in the parent scope.
|
||||
|
|
@ -285,7 +298,9 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix)
|
|||
up_->children_[name_] = this;
|
||||
return true;
|
||||
}
|
||||
tmp[pad_pos++] = pad;
|
||||
|
||||
// Name collides, so try a different name.
|
||||
use_prefix = use_prefix + pad;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -296,16 +311,16 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix)
|
|||
*/
|
||||
bool NetScope::replace_parameter(perm_string key, PExpr*val, NetScope*scope)
|
||||
{
|
||||
bool flag = false;
|
||||
if (parameters.find(key) == parameters.end())
|
||||
return false;
|
||||
|
||||
if (parameters.find(key) != parameters.end()) {
|
||||
param_expr_t&ref = parameters[key];
|
||||
ref.val_expr = val;
|
||||
ref.val_scope = scope;
|
||||
flag = true;
|
||||
}
|
||||
param_expr_t&ref = parameters[key];
|
||||
if (ref.local_flag)
|
||||
return false;
|
||||
|
||||
return flag;
|
||||
ref.val_expr = val;
|
||||
ref.val_scope = scope;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetScope::make_parameter_unannotatable(perm_string key)
|
||||
|
|
@ -356,12 +371,7 @@ const NetExpr* NetScope::get_parameter(Design*des,
|
|||
msb = 0;
|
||||
lsb = 0;
|
||||
const NetExpr*tmp = enumeration_expr(key);
|
||||
if (tmp) return tmp;
|
||||
|
||||
tmp = des->enumeration_expr(key);
|
||||
if (tmp) return tmp;
|
||||
|
||||
return 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetScope::param_ref_t NetScope::find_parameter(perm_string key)
|
||||
|
|
@ -378,11 +388,6 @@ NetScope::param_ref_t NetScope::find_parameter(perm_string key)
|
|||
return idx;
|
||||
}
|
||||
|
||||
NetScope::TYPE NetScope::type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
void NetScope::print_type(ostream&stream) const
|
||||
{
|
||||
switch (type_) {
|
||||
|
|
@ -501,6 +506,7 @@ void NetScope::add_module_port_info( unsigned idx, perm_string name, PortType::E
|
|||
unsigned long width )
|
||||
{
|
||||
assert(type_ == MODULE);
|
||||
assert(ports_.size() > idx);
|
||||
PortInfo &info = ports_[idx];
|
||||
info.name = name;
|
||||
info.type = ptype;
|
||||
|
|
@ -648,15 +654,11 @@ netclass_t*NetScope::find_class(perm_string name)
|
|||
if (type_==CLASS && name_==hname_t(name))
|
||||
return class_def_;
|
||||
|
||||
// Look for the class that directly within this scope.
|
||||
// Look for the class directly within this scope.
|
||||
map<perm_string,netclass_t*>::const_iterator cur = classes_.find(name);
|
||||
if (cur != classes_.end())
|
||||
return cur->second;
|
||||
|
||||
// If this is a module scope, then look no further.
|
||||
if (type_==MODULE)
|
||||
return 0;
|
||||
|
||||
if (up_==0 && type_==CLASS) {
|
||||
assert(class_def_);
|
||||
|
||||
|
|
@ -664,12 +666,16 @@ netclass_t*NetScope::find_class(perm_string name)
|
|||
return def_parent->find_class(name);
|
||||
}
|
||||
|
||||
// If there is no further to look, ...
|
||||
if (up_ == 0)
|
||||
return 0;
|
||||
|
||||
// Try looking up for the class.
|
||||
return up_->find_class(name);
|
||||
if (up_!=0 && type_!=MODULE)
|
||||
return up_->find_class(name);
|
||||
|
||||
// Try the compilation unit.
|
||||
if (unit_ != 0)
|
||||
return unit_->find_class(name);
|
||||
|
||||
// Nowhere left to try...
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -741,3 +747,33 @@ perm_string NetScope::local_symbol()
|
|||
res << "_s" << (lcounter_++);
|
||||
return lex_strings.make(res.str());
|
||||
}
|
||||
|
||||
void NetScope::add_tie_hi(Design*des)
|
||||
{
|
||||
if (tie_hi_ == 0) {
|
||||
NetNet*sig = new NetNet(this, lex_strings.make("_LOGIC1"),
|
||||
NetNet::WIRE, &netvector_t::scalar_logic);
|
||||
sig->local_flag(true);
|
||||
|
||||
tie_hi_ = new NetLogic(this, local_symbol(),
|
||||
1, NetLogic::PULLUP, 1);
|
||||
des->add_node(tie_hi_);
|
||||
|
||||
connect(sig->pin(0), tie_hi_->pin(0));
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::add_tie_lo(Design*des)
|
||||
{
|
||||
if (tie_lo_ == 0) {
|
||||
NetNet*sig = new NetNet(this, lex_strings.make("_LOGIC0"),
|
||||
NetNet::WIRE, &netvector_t::scalar_logic);
|
||||
sig->local_flag(true);
|
||||
|
||||
tie_lo_ = new NetLogic(this, local_symbol(),
|
||||
1, NetLogic::PULLDOWN, 1);
|
||||
des->add_node(tie_lo_);
|
||||
|
||||
connect(sig->pin(0), tie_lo_->pin(0));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2017 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
|
||||
|
|
@ -165,7 +165,8 @@ bool netclass_t::test_for_missing_initializers() const
|
|||
NetScope*netclass_t::method_from_name(perm_string name) const
|
||||
{
|
||||
NetScope*task = class_scope_->child( hname_t(name) );
|
||||
if (task == 0) return 0;
|
||||
if ((task == 0) && super_)
|
||||
task = super_->method_from_name(name);
|
||||
return task;
|
||||
|
||||
}
|
||||
|
|
|
|||
768
netlist.cc
768
netlist.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
# include <typeinfo>
|
||||
# include <cstdlib>
|
||||
# include <climits>
|
||||
# include <cstring>
|
||||
# include "compiler.h"
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
|
|
@ -175,6 +176,7 @@ bool NetPins::pins_are_virtual(void) const
|
|||
NetPins::NetPins(unsigned npins)
|
||||
: npins_(npins)
|
||||
{
|
||||
default_dir_ = Link::PASSIVE;
|
||||
pins_ = NULL; // Wait until someone asks.
|
||||
if (disable_virtual_pins) devirtualize_pins(); // Ask. Bummer.
|
||||
}
|
||||
|
|
@ -557,7 +559,7 @@ void NetNet::calculate_slice_widths_from_packed_dims_(void)
|
|||
ivl_assert(*this, ! slice_wids_.empty());
|
||||
slice_wids_[0] = netrange_width(slice_dims_);
|
||||
vector<netrange_t>::const_iterator cur = slice_dims_.begin();
|
||||
for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1) {
|
||||
for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1, ++cur) {
|
||||
slice_wids_[idx] = slice_wids_[idx-1] / cur->width();
|
||||
}
|
||||
}
|
||||
|
|
@ -1021,11 +1023,36 @@ NetProc::~NetProc()
|
|||
NetProcTop::NetProcTop(NetScope*s, ivl_process_type_t t, NetProc*st)
|
||||
: type_(t), statement_(st), scope_(s)
|
||||
{
|
||||
synthesized_design_ = 0;
|
||||
}
|
||||
|
||||
NetProcTop::~NetProcTop()
|
||||
{
|
||||
if (!synthesized_design_) {
|
||||
delete statement_;
|
||||
return;
|
||||
}
|
||||
|
||||
NexusSet nex_set;
|
||||
statement_->nex_output(nex_set);
|
||||
|
||||
delete statement_;
|
||||
|
||||
bool flag = false;
|
||||
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
||||
|
||||
NetNet*net = nex_set[idx].lnk.nexus()->pick_any_net();
|
||||
if (net->peek_lref() > 0) {
|
||||
cerr << get_fileline() << ": warning: '" << net->name()
|
||||
<< "' is driven by more than one process." << endl;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
cerr << get_fileline() << ": sorry: Cannot synthesize signals "
|
||||
"that are driven by more than one process." << endl;
|
||||
synthesized_design_->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
NetProc* NetProcTop::statement()
|
||||
|
|
@ -1153,8 +1180,8 @@ unsigned NetReplicate::repeat() const
|
|||
* ...
|
||||
*/
|
||||
|
||||
NetFF::NetFF(NetScope*s, perm_string n, unsigned width__)
|
||||
: NetNode(s, n, 8), width_(width__)
|
||||
NetFF::NetFF(NetScope*s, perm_string n, bool negedge__, unsigned width__)
|
||||
: NetNode(s, n, 8), negedge_(negedge__), width_(width__)
|
||||
{
|
||||
pin_Clock().set_dir(Link::INPUT);
|
||||
pin_Enable().set_dir(Link::INPUT);
|
||||
|
|
@ -1170,6 +1197,11 @@ NetFF::~NetFF()
|
|||
{
|
||||
}
|
||||
|
||||
bool NetFF::is_negedge() const
|
||||
{
|
||||
return negedge_;
|
||||
}
|
||||
|
||||
unsigned NetFF::width() const
|
||||
{
|
||||
return width_;
|
||||
|
|
@ -1275,6 +1307,60 @@ const verinum& NetFF::sset_value() const
|
|||
return sset_value_;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NetLatch class represents an LPM_LATCH device. The pinout is assigned
|
||||
* like so:
|
||||
* 0 -- Enable
|
||||
* 1 -- Data
|
||||
* 2 -- Q
|
||||
*/
|
||||
|
||||
NetLatch::NetLatch(NetScope*s, perm_string n, unsigned width__)
|
||||
: NetNode(s, n, 3), width_(width__)
|
||||
{
|
||||
pin_Enable().set_dir(Link::INPUT);
|
||||
pin_Data().set_dir(Link::INPUT);
|
||||
pin_Q().set_dir(Link::OUTPUT);
|
||||
}
|
||||
|
||||
NetLatch::~NetLatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetLatch::width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
Link& NetLatch::pin_Enable()
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
const Link& NetLatch::pin_Enable() const
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
Link& NetLatch::pin_Data()
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
const Link& NetLatch::pin_Data() const
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
Link& NetLatch::pin_Q()
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
const Link& NetLatch::pin_Q() const
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w)
|
||||
: NetNode(s, n, 2), width_(w)
|
||||
|
|
@ -2683,7 +2769,7 @@ static DelayType delay_type_from_expr(const NetExpr*expr)
|
|||
* The looping structures can use the same basic code so put it here
|
||||
* instead of duplicating it for each one (repeat and while).
|
||||
*/
|
||||
static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc)
|
||||
static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc, bool print_delay)
|
||||
{
|
||||
DelayType result;
|
||||
|
||||
|
|
@ -2694,12 +2780,20 @@ static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc)
|
|||
break;
|
||||
/* We have a constant true expression so the body always runs. */
|
||||
case DEFINITE_DELAY:
|
||||
result = proc->delay_type();
|
||||
if (proc) {
|
||||
result = proc->delay_type(print_delay);
|
||||
} else {
|
||||
result = NO_DELAY;
|
||||
}
|
||||
break;
|
||||
/* We don't know if the body will run so reduce a DEFINITE_DELAY
|
||||
* to a POSSIBLE_DELAY. All other stay the same. */
|
||||
case POSSIBLE_DELAY:
|
||||
result = combine_delays(NO_DELAY, proc->delay_type());
|
||||
if (proc) {
|
||||
result = combine_delays(NO_DELAY, proc->delay_type(print_delay));
|
||||
} else {
|
||||
result = NO_DELAY;
|
||||
}
|
||||
break;
|
||||
/* This should never happen since delay_type_from_expr() only
|
||||
* returns three different values. */
|
||||
|
|
@ -2712,25 +2806,40 @@ static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc)
|
|||
}
|
||||
|
||||
/* The default object does not have any delay. */
|
||||
DelayType NetProc::delay_type() const
|
||||
DelayType NetProc::delay_type(bool /* print_delay */ ) const
|
||||
{
|
||||
return NO_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetBlock::delay_type() const
|
||||
DelayType NetBlock::delay_type(bool print_delay) const
|
||||
{
|
||||
DelayType result = NO_DELAY;
|
||||
// A join_none has no delay.
|
||||
if (type() == PARA_JOIN_NONE) return NO_DELAY;
|
||||
|
||||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
DelayType dt = cur->delay_type();
|
||||
if (dt > result) result = dt;
|
||||
if (dt == DEFINITE_DELAY) break;
|
||||
DelayType result;
|
||||
// A join_any has the minimum delay.
|
||||
if (type() == PARA_JOIN_ANY) {
|
||||
result = DEFINITE_DELAY;
|
||||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
DelayType dt = cur->delay_type(print_delay);
|
||||
if (dt < result) result = dt;
|
||||
if ((dt == NO_DELAY) && !print_delay) break;
|
||||
}
|
||||
|
||||
// A begin or join has the maximum delay.
|
||||
} else {
|
||||
result = NO_DELAY;
|
||||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
DelayType dt = cur->delay_type(print_delay);
|
||||
if (dt > result) result = dt;
|
||||
if ((dt == DEFINITE_DELAY) && !print_delay) break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetCase::delay_type() const
|
||||
DelayType NetCase::delay_type(bool print_delay) const
|
||||
{
|
||||
DelayType result = NO_DELAY;
|
||||
bool def_stmt = false;
|
||||
|
|
@ -2738,13 +2847,15 @@ DelayType NetCase::delay_type() const
|
|||
|
||||
for (unsigned idx = 0; idx < nstmts; idx += 1) {
|
||||
if (!expr(idx)) def_stmt = true;
|
||||
DelayType dt = stat(idx) ? stat(idx)->delay_type(print_delay) : NO_DELAY;
|
||||
if (idx == 0) {
|
||||
result = stat(idx)->delay_type();
|
||||
result = dt;
|
||||
} else {
|
||||
result = combine_delays(result, stat(idx)->delay_type());
|
||||
result = combine_delays(result, dt);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: If all the cases are covered (e.g. an enum) then this is not true.
|
||||
/* If we don't have a default statement we don't know for sure
|
||||
* that we have a delay. */
|
||||
if (!def_stmt) result = combine_delays(NO_DELAY, result);
|
||||
|
|
@ -2752,69 +2863,636 @@ DelayType NetCase::delay_type() const
|
|||
return result;
|
||||
}
|
||||
|
||||
DelayType NetCondit::delay_type() const
|
||||
DelayType NetCondit::delay_type(bool print_delay) const
|
||||
{
|
||||
DelayType if_type = if_ ? if_->delay_type() : NO_DELAY;
|
||||
DelayType el_type = else_? else_->delay_type() : NO_DELAY;
|
||||
DelayType if_type = if_ ? if_->delay_type(print_delay) : NO_DELAY;
|
||||
DelayType el_type = else_? else_->delay_type(print_delay) : NO_DELAY;
|
||||
return combine_delays(if_type, el_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* A do/while will execute the body at least once.
|
||||
*/
|
||||
DelayType NetDoWhile::delay_type() const
|
||||
DelayType NetDoWhile::delay_type(bool print_delay) const
|
||||
{
|
||||
return proc_->delay_type();
|
||||
if (proc_) return proc_->delay_type(print_delay);
|
||||
|
||||
return ZERO_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetEvWait::delay_type() const
|
||||
DelayType NetEvWait::delay_type(bool print_delay) const
|
||||
{
|
||||
if (print_delay) {
|
||||
cerr << get_fileline() << ": error: an event control is not allowed "
|
||||
"in an always_comb, always_ff or always_latch process."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
return DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetForever::delay_type() const
|
||||
DelayType NetForever::delay_type(bool print_delay) const
|
||||
{
|
||||
return statement_->delay_type();
|
||||
if (statement_) return statement_->delay_type(print_delay);
|
||||
|
||||
return ZERO_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetForLoop::delay_type() const
|
||||
DelayType NetForLoop::delay_type(bool print_delay) const
|
||||
{
|
||||
return get_loop_delay_type(condition_, statement_);
|
||||
return get_loop_delay_type(condition_, statement_, print_delay);
|
||||
}
|
||||
|
||||
DelayType NetPDelay::delay_type() const
|
||||
DelayType NetPDelay::delay_type(bool print_delay) const
|
||||
{
|
||||
if (print_delay) {
|
||||
cerr << get_fileline() << ": error: a blocking delay is not allowed "
|
||||
"in an always_comb, always_ff or always_latch process."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (expr_) {
|
||||
return delay_type_from_expr(expr_);
|
||||
} else {
|
||||
if (delay() > 0) {
|
||||
return DEFINITE_DELAY;
|
||||
if (statement_) {
|
||||
return combine_delays(delay_type_from_expr(expr_),
|
||||
statement_->delay_type(print_delay));
|
||||
} else {
|
||||
if (statement_) {
|
||||
return statement_->delay_type();
|
||||
} else {
|
||||
return NO_DELAY;
|
||||
}
|
||||
return delay_type_from_expr(expr_);
|
||||
}
|
||||
}
|
||||
|
||||
if (delay() > 0) return DEFINITE_DELAY;
|
||||
|
||||
if (statement_) {
|
||||
return combine_delays(ZERO_DELAY,
|
||||
statement_->delay_type(print_delay));
|
||||
} else {
|
||||
return ZERO_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
DelayType NetRepeat::delay_type(bool print_delay) const
|
||||
{
|
||||
return get_loop_delay_type(expr_, statement_, print_delay);
|
||||
}
|
||||
|
||||
DelayType NetTaskDef::delay_type(bool print_delay) const
|
||||
{
|
||||
if (proc_) {
|
||||
return proc_->delay_type(print_delay);
|
||||
} else {
|
||||
return NO_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
DelayType NetUTask::delay_type(bool print_delay) const
|
||||
{
|
||||
return task()->task_def()->delay_type(print_delay);
|
||||
}
|
||||
|
||||
static bool do_expr_event_match(const NetExpr*expr, const NetEvWait*evwt)
|
||||
{
|
||||
// The event wait should only have a single event.
|
||||
if (evwt->nevents() != 1) return false;
|
||||
// The event should have a single probe.
|
||||
const NetEvent *evt = evwt->event(0);
|
||||
if (evt->nprobe() != 1) return false;
|
||||
// The probe should be for any edge.
|
||||
const NetEvProbe *prb = evt->probe(0);
|
||||
if (prb->edge() != NetEvProbe::ANYEDGE) return false;
|
||||
// Create a NexusSet from the event probe signals.
|
||||
NexusSet *ns_evwt = new NexusSet;
|
||||
for (unsigned idx =0; idx < prb->pin_count(); idx += 1) {
|
||||
if (! prb->pin(idx).is_linked()) {
|
||||
delete ns_evwt;
|
||||
return false;
|
||||
}
|
||||
// Casting away const is safe since this nexus set is only being read.
|
||||
ns_evwt->add(const_cast<Nexus*> (prb->pin(idx).nexus()),
|
||||
0, prb->pin(idx).nexus()->vector_width());
|
||||
}
|
||||
// Get the NexusSet for the expression.
|
||||
NexusSet *ns_expr = expr->nex_input();
|
||||
// Make sure the event and expression NexusSets match exactly.
|
||||
if (ns_evwt->size() != ns_expr->size()) {
|
||||
delete ns_evwt;
|
||||
delete ns_expr;
|
||||
return false;
|
||||
}
|
||||
ns_expr->rem(*ns_evwt);
|
||||
delete ns_evwt;
|
||||
if (ns_expr->size() != 0) {
|
||||
delete ns_expr;
|
||||
return false;
|
||||
}
|
||||
delete ns_expr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool while_is_wait(const NetExpr*expr, const NetProc*stmt)
|
||||
{
|
||||
if (const NetEvWait*evwt = dynamic_cast<const NetEvWait*>(stmt)) {
|
||||
if (evwt->statement()) return false;
|
||||
const NetEBComp*cond = dynamic_cast<const NetEBComp*>(expr);
|
||||
if (! cond) return false;
|
||||
if (cond->op() != 'N') return false;
|
||||
const NetEConst*cval = dynamic_cast<const NetEConst*>(cond->right());
|
||||
if (! cval) return false;
|
||||
const verinum val = cval->value();
|
||||
if (val.len() != 1) return false;
|
||||
if (val.get(0) != verinum::V1) return false;
|
||||
if (! do_expr_event_match(cond->left(), evwt)) return false;
|
||||
if (evwt->get_lineno() != cond->get_lineno()) return false;
|
||||
if (evwt->get_file() != cond->get_file()) return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DelayType NetWhile::delay_type(bool print_delay) const
|
||||
{
|
||||
// If the wait was a constant value the compiler already removed it
|
||||
// so we know we can only have a possible delay.
|
||||
if (while_is_wait(cond_, proc_)) {
|
||||
if (print_delay) {
|
||||
cerr << get_fileline() << ": error: a wait statement is "
|
||||
"not allowed in an "
|
||||
"always_comb, always_ff or always_latch process."
|
||||
<< endl;
|
||||
}
|
||||
return POSSIBLE_DELAY;
|
||||
}
|
||||
return get_loop_delay_type(cond_, proc_, print_delay);
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the check_synth() functions. They are used to print
|
||||
* a warning if the item is not synthesizable.
|
||||
*/
|
||||
static const char * get_process_type_as_string(ivl_process_type_t pr_type)
|
||||
{
|
||||
switch (pr_type) {
|
||||
case IVL_PR_ALWAYS_COMB:
|
||||
return "in an always_comb process.";
|
||||
break;
|
||||
case IVL_PR_ALWAYS_FF:
|
||||
return "in an always_ff process.";
|
||||
break;
|
||||
case IVL_PR_ALWAYS_LATCH:
|
||||
return "in an always_latch process.";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_synth_warning(const NetProc *net_proc, const char *name,
|
||||
ivl_process_type_t pr_type)
|
||||
{
|
||||
cerr << net_proc->get_fileline() << ": warning: " << name
|
||||
<< " statement cannot be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
|
||||
static void check_if_logic_l_value(const NetAssignBase *base,
|
||||
ivl_process_type_t pr_type)
|
||||
{
|
||||
if (base->l_val_count() != 1) return;
|
||||
|
||||
const NetAssign_*lval = base->l_val(0);
|
||||
if (! lval) return;
|
||||
|
||||
NetNet*sig = lval->sig();
|
||||
if (! sig) return;
|
||||
|
||||
if ((sig->data_type() != IVL_VT_BOOL) &&
|
||||
(sig->data_type() != IVL_VT_LOGIC)) {
|
||||
cerr << base->get_fileline() << ": warning: Assinging to a "
|
||||
"non-integral variable ("<< sig->name()
|
||||
<< ") cannot be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* By default elements can be synthesized or ignored. */
|
||||
bool NetProc::check_synth(ivl_process_type_t /* pr_type */,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: User function calls still need to be checked (NetEUFunc).
|
||||
// : Non-constant system functions need a warning (NetESFunc).
|
||||
// : Constant functions should already be elaborated.
|
||||
|
||||
/* By default assign elements can be synthesized. */
|
||||
bool NetAssignBase::check_synth(ivl_process_type_t /* pr_type */,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetAssign::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
check_if_logic_l_value(this, pr_type);
|
||||
|
||||
// FIXME: Check that ff/latch only use this for internal signals.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetAssignNB::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
bool result = false;
|
||||
if (pr_type == IVL_PR_ALWAYS_COMB) {
|
||||
cerr << get_fileline() << ": warning: A non-blocking assignment "
|
||||
"should not be used in an always_comb process." << endl;
|
||||
}
|
||||
|
||||
if (event_) {
|
||||
cerr << get_fileline() << ": error: A non-blocking assignment "
|
||||
"cannot be synthesized with an event control "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
result = true;
|
||||
}
|
||||
|
||||
check_if_logic_l_value(this, pr_type);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetBlock::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
// Only a begin/end can be synthesized.
|
||||
if (type() != SEQU) {
|
||||
cerr << get_fileline() << ": error: A fork/";
|
||||
switch (type()) {
|
||||
case PARA:
|
||||
cerr << "join";
|
||||
break;
|
||||
case PARA_JOIN_ANY:
|
||||
cerr << "join_any";
|
||||
break;
|
||||
case PARA_JOIN_NONE:
|
||||
cerr << "join_none";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
cerr << " statement cannot be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
result = true;
|
||||
}
|
||||
|
||||
const NetScope*save_scope = scope;
|
||||
if (subscope()) scope = subscope();
|
||||
if (scope != save_scope) {
|
||||
result |= scope->check_synth(pr_type, scope);
|
||||
}
|
||||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
result |= cur->check_synth(pr_type, scope);
|
||||
}
|
||||
scope = save_scope;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetCase::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
for (unsigned idx = 0; idx < nitems(); idx += 1) {
|
||||
if (stat(idx)) result |= stat(idx)->check_synth(pr_type, scope);
|
||||
}
|
||||
// FIXME: Check for ff/latch/comb structures.
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetCAssign::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
print_synth_warning(this, "A procedural assign", pr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetCondit::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
if (if_) result |= if_->check_synth(pr_type, scope);
|
||||
if (else_) result |= else_->check_synth(pr_type, scope);
|
||||
// FIXME: Check for ff/latch/comb structures.
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetDeassign::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
print_synth_warning(this, "A procedural deassign", pr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetDisable::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
while (scope) {
|
||||
if (scope != target_) scope = scope->parent();
|
||||
else break;
|
||||
}
|
||||
|
||||
|
||||
if (! scope) {
|
||||
cerr << get_fileline() << ": warning: A disable statement can "
|
||||
"only be synthesized when disabling an enclosing block "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetDoWhile::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
print_synth_warning(this, "A do/while", pr_type);
|
||||
if (proc_) result |= proc_->check_synth(pr_type, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetEvTrig::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
print_synth_warning(this, "An event trigger", pr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The delay check above has already marked this as an error.
|
||||
bool NetEvWait::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
if (statement_) result |= statement_->check_synth(pr_type, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetForce::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
print_synth_warning(this, "A force", pr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetForever::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
print_synth_warning(this, "A forever", pr_type);
|
||||
if (statement_) result |= statement_->check_synth(pr_type, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* A bunch of private routines to verify that a for loop has the correct
|
||||
* structure for synthesis.
|
||||
*/
|
||||
static void print_for_idx_warning(const NetProc*proc, const char*check,
|
||||
ivl_process_type_t pr_type, NetNet*idx)
|
||||
{
|
||||
cerr << proc->get_fileline() << ": warning: A for statement must use "
|
||||
"the index (" << idx->name() << ") in the " << check
|
||||
<< " expression to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
|
||||
static void check_for_const_synth(const NetExpr*expr, const NetProc*proc,
|
||||
const char*str, ivl_process_type_t pr_type)
|
||||
{
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
cerr << proc-> get_fileline() << ": warning: A for "
|
||||
"statement must " << str
|
||||
<< " value to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_for_bin_synth(const NetExpr*left,const NetExpr*right,
|
||||
const char*str, const char*check,
|
||||
const NetProc*proc,
|
||||
ivl_process_type_t pr_type, NetNet*index)
|
||||
{
|
||||
const NetESignal*lsig = dynamic_cast<const NetESignal*>(left);
|
||||
const NetESignal*rsig = dynamic_cast<const NetESignal*>(right);
|
||||
|
||||
if (lsig && (lsig->sig() == index)) {
|
||||
check_for_const_synth(right, proc, str, pr_type);
|
||||
} else if (rsig && (rsig->sig() == index)) {
|
||||
check_for_const_synth(left, proc, str, pr_type);
|
||||
} else {
|
||||
print_for_idx_warning(proc, check, pr_type, index);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_for_step_warning(const NetProc*proc,
|
||||
ivl_process_type_t pr_type)
|
||||
{
|
||||
cerr << proc->get_fileline() << ": warning: A for statement step must "
|
||||
"be a simple assignment statement to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
|
||||
static void print_for_step_warning(const NetProc*proc,
|
||||
ivl_process_type_t pr_type, NetNet*idx)
|
||||
{
|
||||
cerr << proc->get_fileline() << ": warning: A for statement step must "
|
||||
"be an assignment to the index variable ("
|
||||
<< idx->name() << ") to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
|
||||
static void check_for_bstep_synth(const NetExpr*expr, const NetProc*proc,
|
||||
ivl_process_type_t pr_type, NetNet*index)
|
||||
{
|
||||
if (const NetECast*tmp = dynamic_cast<const NetECast*>(expr)) {
|
||||
expr = tmp->expr();
|
||||
}
|
||||
|
||||
if (const NetEBAdd*tmp = dynamic_cast<const NetEBAdd*>(expr)) {
|
||||
check_for_bin_synth(tmp->left(), tmp->right(),
|
||||
"change by a constant", "step", proc, pr_type,
|
||||
index);
|
||||
} else {
|
||||
cerr << proc->get_fileline() << ": warning: A for statement "
|
||||
"step must be a simple binary +/- "
|
||||
"to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_for_step_synth(const NetAssign*assign, const NetProc*proc,
|
||||
ivl_process_type_t pr_type, NetNet*index)
|
||||
{
|
||||
if (assign->l_val_count() != 1) {
|
||||
print_for_step_warning(proc, pr_type);
|
||||
} else if (assign->l_val(0)->sig() != index) {
|
||||
print_for_step_warning(proc, pr_type, index);
|
||||
} else {
|
||||
switch (assign->assign_operator()) {
|
||||
case '+':
|
||||
case '-':
|
||||
check_for_const_synth(assign->rval(), proc,
|
||||
"have a constant step", pr_type);
|
||||
break;
|
||||
case 0:
|
||||
check_for_bstep_synth(assign->rval(), proc, pr_type, index);
|
||||
break;
|
||||
default:
|
||||
cerr << proc->get_fileline() << ": warning: A for statement "
|
||||
"step does not support operator '"
|
||||
<< assign->assign_operator()
|
||||
<< "' it must be +/- to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelayType NetRepeat::delay_type() const
|
||||
bool NetForLoop::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
return get_loop_delay_type(expr_, statement_);
|
||||
bool result = false;
|
||||
|
||||
// FIXME: What about an enum (NetEConstEnum)?
|
||||
if (! dynamic_cast<const NetEConst*>(init_expr_)) {
|
||||
cerr << get_fileline() << ": warning: A for statement must "
|
||||
"have a constant initial value to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
|
||||
// FIXME: Do the following also need to be supported in the condition?
|
||||
// It would seem like they are hard to use to find the bounds.
|
||||
// From NetEBinary
|
||||
// What about NetEBits sig & constant, etc.
|
||||
// From NetEUnary
|
||||
// What about NetEUBits ! sig or ! (sig == constat)
|
||||
// What about NetEUReduce &signal
|
||||
if (const NetESignal*tmp = dynamic_cast<const NetESignal*>(condition_)) {
|
||||
if (tmp->sig() != index_) {
|
||||
print_for_idx_warning(this, "condition", pr_type, index_);
|
||||
}
|
||||
} else if (const NetEBComp*cmp = dynamic_cast<const NetEBComp*>(condition_)) {
|
||||
check_for_bin_synth(cmp->left(), cmp->right(),
|
||||
"compare against a constant", "condition",
|
||||
this, pr_type, index_);
|
||||
} else {
|
||||
print_for_idx_warning(this, "condition", pr_type, index_);
|
||||
}
|
||||
|
||||
if (const NetAssign*tmp = dynamic_cast<const NetAssign*>(step_statement_)) {
|
||||
check_for_step_synth(tmp, this, pr_type, index_);
|
||||
} else {
|
||||
print_for_step_warning(this, pr_type);
|
||||
}
|
||||
|
||||
if (statement_) result |= statement_->check_synth(pr_type, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetTaskDef::delay_type() const
|
||||
// The delay check above has already marked this as an error.
|
||||
bool NetPDelay::check_synth(ivl_process_type_t /* pr_type */,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
return proc_->delay_type();
|
||||
return false;
|
||||
}
|
||||
|
||||
DelayType NetUTask::delay_type() const
|
||||
bool NetRelease::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
return task()->task_def()->delay_type();
|
||||
print_synth_warning(this, "A release", pr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
DelayType NetWhile::delay_type() const
|
||||
bool NetRepeat::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
return get_loop_delay_type(cond_, proc_);
|
||||
bool result = false;
|
||||
print_synth_warning(this, "A repeat", pr_type);
|
||||
if (statement_) result |= statement_->check_synth(pr_type, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetScope::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */) const
|
||||
{
|
||||
bool result = false;
|
||||
// Skip local events/signals
|
||||
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
|
||||
if (cur->local_flag()) continue;
|
||||
cerr << cur->get_fileline() << ": warning: An event ("
|
||||
<< cur->name() << ") cannot be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
for (signals_map_iter_t cur = signals_map_.begin();
|
||||
cur != signals_map_.end() ; ++ cur) {
|
||||
const NetNet*sig = cur->second;
|
||||
if ((sig->data_type() != IVL_VT_BOOL) &&
|
||||
(sig->data_type() != IVL_VT_LOGIC)) {
|
||||
cerr << sig->get_fileline() << ": warning: A non-integral "
|
||||
"variable (" << sig->name() << ") cannot be "
|
||||
"synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetSTask::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */) const
|
||||
{
|
||||
if (strcmp(name(), "$ivl_darray_method$delete") == 0) {
|
||||
cerr << get_fileline() << ": warning: Dynamic array "
|
||||
"delete method cannot be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
} else {
|
||||
cerr << get_fileline() << ": warning: System task ("
|
||||
<< name() << ") cannot be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetTaskDef::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */) const
|
||||
{
|
||||
bool result = false;
|
||||
const NetScope *tscope = this->scope();
|
||||
result |= tscope->check_synth(pr_type, tscope);
|
||||
if (! tscope->is_auto()) {
|
||||
cerr << tscope->get_def_file() << ":"
|
||||
<< tscope->get_def_lineno()
|
||||
<< ": warning: user task (" << tscope->basename()
|
||||
<< ") must be automatic to be synthesized "
|
||||
<< get_process_type_as_string(pr_type) << endl;
|
||||
}
|
||||
if (proc_) result |= proc_->check_synth(pr_type, tscope);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NetUTask::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
return task()->task_def()->check_synth(pr_type, scope);
|
||||
}
|
||||
|
||||
bool NetWhile::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
{
|
||||
bool result = false;
|
||||
// A wait is already maked as an error in the delay check above.
|
||||
if (! while_is_wait(cond_, proc_)) {
|
||||
print_synth_warning(this, "A while", pr_type);
|
||||
if (proc_) result |= proc_->check_synth(pr_type, scope);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
138
netmisc.cc
138
netmisc.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2017 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
|
||||
|
|
@ -203,7 +203,7 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
|
|||
}
|
||||
|
||||
verinum val_v (val, expr->expr_width());
|
||||
val_v.has_sign(true);
|
||||
val_v.has_sign(expr->has_sign());
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
|
@ -236,7 +236,7 @@ static NetExpr* make_add_expr(const LineInfo*loc, NetExpr*expr1, NetExpr*expr2)
|
|||
static NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
{
|
||||
verinum val_v (val, expr->expr_width());
|
||||
val_v.has_sign(true);
|
||||
val_v.has_sign(expr->has_sign());
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
|
@ -249,7 +249,26 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
|
|||
}
|
||||
|
||||
/*
|
||||
* Multiple an existing expression by a signed positive number.
|
||||
* Subtract a signed constant from an existing expression.
|
||||
*/
|
||||
static NetExpr* make_sub_expr(NetExpr*expr, long val)
|
||||
{
|
||||
verinum val_v (val, expr->expr_width());
|
||||
val_v.has_sign(expr->has_sign());
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBAdd*res = new NetEBAdd('-', expr, val_c, expr->expr_width(),
|
||||
expr->has_sign());
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Multiply an existing expression by a signed positive number.
|
||||
* This does a lossless multiply, so the arguments will need to be
|
||||
* sized to match the output size.
|
||||
*/
|
||||
|
|
@ -258,7 +277,7 @@ static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val)
|
|||
const unsigned val_wid = ceil(log2((double)val)) ;
|
||||
unsigned use_wid = expr->expr_width() + val_wid;
|
||||
verinum val_v (val, use_wid);
|
||||
val_v.has_sign(true);
|
||||
val_v.has_sign(expr->has_sign());
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
|
@ -434,17 +453,41 @@ NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
|
|||
-- pcur;
|
||||
}
|
||||
|
||||
long sb;
|
||||
if (pcur->get_msb() >= pcur->get_lsb())
|
||||
sb = pcur->get_lsb();
|
||||
else
|
||||
sb = pcur->get_msb();
|
||||
|
||||
long sb = min(pcur->get_lsb(), pcur->get_msb());
|
||||
long loff;
|
||||
reg->sb_to_slice(indices, sb, loff, lwid);
|
||||
|
||||
base = make_mult_expr(base, lwid);
|
||||
base = make_add_expr(base, loff);
|
||||
unsigned min_wid = base->expr_width();
|
||||
if ((sb < 0) && !base->has_sign()) min_wid += 1;
|
||||
if (min_wid < num_bits(pcur->get_lsb())) min_wid = pcur->get_lsb();
|
||||
if (min_wid < num_bits(pcur->get_msb())) min_wid = pcur->get_msb();
|
||||
base = pad_to_width(base, min_wid, *base);
|
||||
if ((sb < 0) && !base->has_sign()) {
|
||||
NetESelect *tmp = new NetESelect(base, 0 , min_wid);
|
||||
tmp->set_line(*base);
|
||||
tmp->cast_signed(true);
|
||||
base = tmp;
|
||||
}
|
||||
|
||||
if (pcur->get_msb() >= pcur->get_lsb()) {
|
||||
if (pcur->get_lsb() != 0)
|
||||
base = make_sub_expr(base, pcur->get_lsb());
|
||||
base = make_mult_expr(base, lwid);
|
||||
min_wid = base->expr_width();
|
||||
if (min_wid < num_bits(loff)) min_wid = num_bits(loff);
|
||||
if (loff != 0) min_wid += 1;
|
||||
base = pad_to_width(base, min_wid, *base);
|
||||
base = make_add_expr(base, loff);
|
||||
} else {
|
||||
if (pcur->get_msb() != 0)
|
||||
base = make_sub_expr(base, pcur->get_msb());
|
||||
base = make_mult_expr(base, lwid);
|
||||
min_wid = base->expr_width();
|
||||
if (min_wid < num_bits(loff)) min_wid = num_bits(loff);
|
||||
if (loff != 0) min_wid += 1;
|
||||
base = pad_to_width(base, min_wid, *base);
|
||||
base = make_sub_expr(loff, base);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
|
|
@ -480,8 +523,6 @@ void indices_to_expressions(Design*des, NetScope*scope,
|
|||
const list<index_component_t>&src, unsigned count,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// Total words in target array
|
||||
unsigned need_addr,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices, list<long>&indices_const)
|
||||
|
|
@ -692,7 +733,7 @@ NetExpr* make_canonical_index(Design*des, NetScope*scope,
|
|||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc,
|
||||
src, src.size(),
|
||||
need_const, stype->static_dimensions().size(),
|
||||
need_const,
|
||||
flags,
|
||||
indices_expr, indices_const);
|
||||
|
||||
|
|
@ -804,9 +845,10 @@ NetExpr* condition_reduce(NetExpr*expr)
|
|||
}
|
||||
|
||||
static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
bool force_expand,
|
||||
ivl_variable_type_t cast_type)
|
||||
int context_width, bool need_const,
|
||||
bool annotatable, bool force_expand,
|
||||
ivl_variable_type_t cast_type,
|
||||
bool force_unsigned)
|
||||
{
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
if ((context_width == -2) && !gn_strict_expr_width_flag)
|
||||
|
|
@ -826,6 +868,11 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
|||
if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width))
|
||||
expr_width = pos_context_width;
|
||||
|
||||
// If this is the RHS of a compressed assignment, the LHS also
|
||||
// affects the expression type (signed/unsigned).
|
||||
if (force_unsigned)
|
||||
pe->cast_signed(false);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": elab_and_eval: test_width of "
|
||||
<< *pe << endl;
|
||||
|
|
@ -893,7 +940,7 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
|||
}
|
||||
}
|
||||
|
||||
// If the context_width sent is is actually the minimim width,
|
||||
// If the context_width sent is is actually the minimum width,
|
||||
// then raise the context_width to be big enough for the
|
||||
// lossless expression.
|
||||
if (force_expand && context_width > 0) {
|
||||
|
|
@ -912,15 +959,16 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
|||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
ivl_variable_type_t cast_type, bool force_unsigned)
|
||||
{
|
||||
return do_elab_and_eval(des, scope, pe, context_width,
|
||||
need_const, annotatable, false, cast_type);
|
||||
need_const, annotatable, false,
|
||||
cast_type, force_unsigned);
|
||||
}
|
||||
|
||||
/*
|
||||
* This variant of elab_and_eval does the expression losslessly, no
|
||||
* matter what the generation of verilog. This is in support of
|
||||
* matter what the generation of Verilog. This is in support of
|
||||
* certain special contexts, notably index expressions.
|
||||
*/
|
||||
NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe,
|
||||
|
|
@ -928,7 +976,8 @@ NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe,
|
|||
ivl_variable_type_t cast_type)
|
||||
{
|
||||
return do_elab_and_eval(des, scope, pe, context_width,
|
||||
need_const, annotatable, true, cast_type);
|
||||
need_const, annotatable, true,
|
||||
cast_type, false);
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
|
|
@ -1211,6 +1260,8 @@ const char *human_readable_op(const char op, bool unary)
|
|||
if (unary) type = "~|"; // NOR
|
||||
else type = "!=="; // Case inequality
|
||||
break;
|
||||
case 'w': type = "==?"; break; // Wild equality
|
||||
case 'W': type = "!=?"; break; // Wild inequality
|
||||
|
||||
case 'l': type = "<<(<)"; break; // Left shifts
|
||||
case 'r': type = ">>"; break; // Logical right shift
|
||||
|
|
@ -1406,7 +1457,7 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
|
|||
return false;
|
||||
}
|
||||
|
||||
prefix_indices .push_back(tmp);
|
||||
prefix_indices.push_back(tmp);
|
||||
delete texpr;
|
||||
}
|
||||
|
||||
|
|
@ -1428,7 +1479,7 @@ NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
|||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc, indices,
|
||||
net->packed_dimensions(),
|
||||
false, net->unpacked_count(), flags, exprs, exprs_const);
|
||||
false, flags, exprs, exprs_const);
|
||||
ivl_assert(*loc, exprs.size() == net->packed_dimensions());
|
||||
|
||||
// Special Case: there is only 1 packed dimension, so the
|
||||
|
|
@ -1616,3 +1667,38 @@ NetScope* find_method_containing_scope(const LineInfo&, NetScope*scope)
|
|||
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print a warning if we find a mixture of default and explicit timescale
|
||||
* based delays in the design, since this is likely an error.
|
||||
*/
|
||||
void check_for_inconsistent_delays(NetScope*scope)
|
||||
{
|
||||
static bool used_implicit_timescale = false;
|
||||
static bool used_explicit_timescale = false;
|
||||
static bool display_ts_dly_warning = true;
|
||||
|
||||
if (scope->time_from_timescale())
|
||||
used_explicit_timescale = true;
|
||||
else
|
||||
used_implicit_timescale = true;
|
||||
|
||||
if (display_ts_dly_warning &&
|
||||
used_explicit_timescale &&
|
||||
used_implicit_timescale) {
|
||||
if (gn_system_verilog()) {
|
||||
cerr << "warning: Found both default and explicit "
|
||||
"timescale based delays. Use" << endl;
|
||||
cerr << " : -Wtimescale to find the design "
|
||||
"element(s) with no explicit" << endl;
|
||||
cerr << " : timescale." << endl;
|
||||
} else {
|
||||
cerr << "warning: Found both default and "
|
||||
"`timescale based delays. Use" << endl;
|
||||
cerr << " : -Wtimescale to find the "
|
||||
"module(s) with no `timescale." << endl;
|
||||
}
|
||||
display_ts_dly_warning = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
52
netmisc.h
52
netmisc.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_netmisc_H
|
||||
#define IVL_netmisc_H
|
||||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2017 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
|
||||
|
|
@ -60,12 +60,32 @@ inline NetScope* symbol_search(const LineInfo*li,
|
|||
}
|
||||
|
||||
/*
|
||||
* This function transforms an expression by padding the high bits
|
||||
* with V0 until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide
|
||||
* enough.
|
||||
* This function transforms an expression by either zero or sign extending
|
||||
* the high bits until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide enough.
|
||||
* The extension method and the returned expression type is determined by
|
||||
* signed_flag.
|
||||
*/
|
||||
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info);
|
||||
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
|
||||
const LineInfo&info);
|
||||
/*
|
||||
* This version determines the extension method from the base expression type.
|
||||
*/
|
||||
inline NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
|
||||
{
|
||||
return pad_to_width(expr, wid, expr->has_sign(), info);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function transforms an expression by either zero or sign extending
|
||||
* or discarding the high bits until the expression has the desired width.
|
||||
* This may mean not transforming the expression at all, if it is already
|
||||
* the correct width. The extension method (if needed) and the returned
|
||||
* expression type is determined by signed_flag.
|
||||
*/
|
||||
extern NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
|
||||
const LineInfo&info);
|
||||
|
||||
extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w,
|
||||
const LineInfo&info);
|
||||
|
||||
|
|
@ -155,7 +175,7 @@ extern NetExpr*normalize_variable_slice_base(const list<long>&indices, NetExpr *
|
|||
* index values in the form [<>][<>]....
|
||||
*/
|
||||
template <class TYPE> struct __IndicesManip {
|
||||
inline __IndicesManip(const std::list<TYPE>&v) : val(v) { }
|
||||
explicit inline __IndicesManip(const std::list<TYPE>&v) : val(v) { }
|
||||
const std::list<TYPE>&val;
|
||||
};
|
||||
template <class TYPE> inline __IndicesManip<TYPE> as_indices(const std::list<TYPE>&indices)
|
||||
|
|
@ -181,8 +201,6 @@ extern void indices_to_expressions(Design*des, NetScope*scope,
|
|||
const list<index_component_t>&src, unsigned count,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// Total array size, for sizing expressions
|
||||
unsigned need_addr,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices,list<long>&indices_const);
|
||||
|
|
@ -260,7 +278,8 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
|||
PExpr*pe, int context_width,
|
||||
bool need_const =false,
|
||||
bool annotatable =false,
|
||||
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
|
||||
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE,
|
||||
bool force_unsigned =false);
|
||||
|
||||
extern NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope,
|
||||
PExpr*pe, int context_width,
|
||||
|
|
@ -299,7 +318,8 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
|
|||
ivl_type_t lv_net_type,
|
||||
ivl_variable_type_t lv_type,
|
||||
unsigned lv_width, PExpr*expr,
|
||||
bool need_const =false);
|
||||
bool need_const =false,
|
||||
bool force_unsigned =false);
|
||||
|
||||
extern bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
std::vector<netrange_t>&llist,
|
||||
|
|
@ -358,10 +378,6 @@ const char *human_readable_op(const char op, bool unary = false);
|
|||
enum const_bool { C_NON, C_0, C_1, C_X };
|
||||
const_bool const_logical(const NetExpr*expr);
|
||||
|
||||
extern bool dly_used_no_timescale;
|
||||
extern bool dly_used_timescale;
|
||||
extern bool display_ts_dly_warning;
|
||||
|
||||
/*
|
||||
* When scaling a real value to a time we need to do some standard
|
||||
* processing.
|
||||
|
|
@ -389,4 +405,10 @@ extern void assign_unpacked_with_bufz(Design*des, NetScope*scope,
|
|||
|
||||
extern NetPartSelect* detect_partselect_lval(Link&pin);
|
||||
|
||||
/*
|
||||
* Print a warning if we find a mixture of default and explicit timescale
|
||||
* based delays in the design, since this is likely an error.
|
||||
*/
|
||||
extern void check_for_inconsistent_delays(NetScope*scope);
|
||||
|
||||
#endif /* IVL_netmisc_H */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -141,19 +141,18 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
|
|||
|
||||
// Now similarly go through the prefix numbers, working
|
||||
// through the dimensions until we run out. Accumulate a
|
||||
// growing slice width (acc_wid) that is used to caculate the
|
||||
// growing slice width (acc_wid) that is used to calculate the
|
||||
// growing offset (acc_off).
|
||||
list<long>::const_iterator icur = prefix.end();
|
||||
do {
|
||||
-- icur;
|
||||
acc_wid *= pcur->width();
|
||||
-- pcur;
|
||||
if (pcur->get_msb() >= pcur->get_lsb())
|
||||
acc_off += (*icur - pcur->get_lsb()) * acc_wid;
|
||||
else
|
||||
acc_off += (pcur->get_lsb() - *icur) * acc_wid;
|
||||
|
||||
-- pcur;
|
||||
|
||||
} while (icur != prefix.begin());
|
||||
|
||||
// Got our final offset.
|
||||
|
|
|
|||
53
nodangle.cc
53
nodangle.cc
|
|
@ -122,10 +122,63 @@ void nodangle_f::event(Design*, NetEvent*ev)
|
|||
}
|
||||
}
|
||||
|
||||
static bool floating_net_tested(NetNet*sig)
|
||||
{
|
||||
static set<NetNet*> tested_set;
|
||||
|
||||
pair< set<NetNet*>::iterator, bool > cur = tested_set.insert(sig);
|
||||
return !cur.second;
|
||||
}
|
||||
|
||||
static void check_is_floating(NetNet*sig)
|
||||
{
|
||||
// Some signal types are implicitly driven if nothing else.
|
||||
if (sig->type() == NetNet::SUPPLY0) return;
|
||||
if (sig->type() == NetNet::SUPPLY1) return;
|
||||
if (sig->type() == NetNet::TRI0) return;
|
||||
if (sig->type() == NetNet::TRI1) return;
|
||||
if (sig->type() == NetNet::IMPLICIT_REG) return;
|
||||
if (sig->type() == NetNet::REG) return ;
|
||||
|
||||
// Assignments drive a signal.
|
||||
if (sig->peek_lref() > 0) return;
|
||||
|
||||
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
|
||||
if (sig->pin(idx).get_dir() == Link::OUTPUT)
|
||||
continue;
|
||||
|
||||
if (sig->pin(idx).nexus()->drivers_present())
|
||||
continue;
|
||||
|
||||
if (sig->port_type() == PortType::NOT_A_PORT && sig->pin_count()==1) {
|
||||
cerr << sig->get_fileline() << ": warning: "
|
||||
<< "Signal " << scope_path(sig->scope())
|
||||
<< "." << sig->name()
|
||||
<< " has no drivers." << endl;
|
||||
} else if (sig->port_type()==PortType::NOT_A_PORT) {
|
||||
cerr << sig->get_fileline() << ": warning: "
|
||||
<< "Signal " << scope_path(sig->scope())
|
||||
<< "." << sig->name()
|
||||
<< "[" << idx << "]"
|
||||
<< " has no drivers." << endl;
|
||||
} else {
|
||||
cerr << sig->get_fileline() << ": warning: "
|
||||
<< "Port " << sig->name()
|
||||
<< " of " << scope_path(sig->scope())
|
||||
<< " has no drivers." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nodangle_f::signal(Design*, NetNet*sig)
|
||||
{
|
||||
if (scomplete) return;
|
||||
|
||||
if (warn_floating_nets && !sig->local_flag() && !floating_net_tested(sig)) {
|
||||
check_is_floating(sig);
|
||||
}
|
||||
|
||||
/* Cannot delete signals referenced in an expression
|
||||
or an l-value. */
|
||||
if (sig->get_refs() > 0)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2016 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
|
||||
|
|
@ -24,21 +24,20 @@
|
|||
# include "netmisc.h"
|
||||
|
||||
|
||||
/*
|
||||
* This function transforms an expression by padding the high bits
|
||||
* with V0 until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide
|
||||
* enough.
|
||||
*/
|
||||
NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
|
||||
NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
|
||||
const LineInfo&info)
|
||||
{
|
||||
if (wid <= expr->expr_width())
|
||||
if (wid <= expr->expr_width()) {
|
||||
expr->cast_signed(signed_flag);
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* If the expression is a const, then replace it with a wider
|
||||
const. This is a more efficient result. */
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
verinum oval = pad_to_width(tmp->value(), wid);
|
||||
verinum oval = tmp->value();
|
||||
oval.has_sign(signed_flag);
|
||||
oval = pad_to_width(oval, wid);
|
||||
tmp = new NetEConst(oval);
|
||||
tmp->set_line(info);
|
||||
delete expr;
|
||||
|
|
@ -46,8 +45,30 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
|
|||
}
|
||||
|
||||
NetESelect*tmp = new NetESelect(expr, 0, wid);
|
||||
tmp->cast_signed(signed_flag);
|
||||
tmp->set_line(info);
|
||||
tmp->cast_signed(expr->has_sign());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
|
||||
const LineInfo&info)
|
||||
{
|
||||
/* If the expression is a const, then replace it with a new
|
||||
const. This is a more efficient result. */
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
tmp->cast_signed(signed_flag);
|
||||
if (wid != tmp->expr_width()) {
|
||||
tmp = new NetEConst(verinum(tmp->value(), wid));
|
||||
tmp->set_line(info);
|
||||
delete expr;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESelect*tmp = new NetESelect(expr, 0, wid);
|
||||
tmp->cast_signed(signed_flag);
|
||||
tmp->set_line(info);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
|
|||
23
parse_api.h
23
parse_api.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_parse_api_H
|
||||
#define IVL_parse_api_H
|
||||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2017 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
|
||||
|
|
@ -42,28 +42,21 @@ struct enum_type_t;
|
|||
*/
|
||||
extern std::map<perm_string,Module*> pform_modules;
|
||||
extern std::map<perm_string,PUdp*> pform_primitives;
|
||||
extern std::map<perm_string,data_type_t*> pform_typedefs;
|
||||
extern std::set<enum_type_t*> pform_enum_sets;
|
||||
extern std::map<perm_string,PTaskFunc*> pform_tasks;
|
||||
extern std::map<perm_string,PClass*> pform_classes;
|
||||
extern std::vector<PPackage*> pform_units;
|
||||
extern std::map<perm_string,PPackage*> pform_packages;
|
||||
|
||||
extern void pform_dump(std::ostream&out, const PClass*pac);
|
||||
extern void pform_dump(std::ostream&out, const PPackage*pac);
|
||||
extern void pform_dump(std::ostream&out, const PTaskFunc*tf);
|
||||
|
||||
extern void elaborate_rootscope_enumerations(Design*des);
|
||||
extern void elaborate_rootscope_classes(Design*des);
|
||||
extern void elaborate_rootscope_tasks(Design*des);
|
||||
|
||||
/*
|
||||
* This code actually invokes the parser to make modules. The first
|
||||
* parameter is the name of the file that is to be parsed. The
|
||||
* optional second parameter is the opened descriptor for the file. If
|
||||
* the descriptor is 0 (or skipped) then the function will attempt to
|
||||
* open the file on its own.
|
||||
* This code actually invokes the parser to make modules. If the path
|
||||
* parameter is "-", the parser reads from stdin, otherwise it attempts
|
||||
* to open and read the specified file. When reading from a file, if
|
||||
* the ivlpp_string variable is not set to null, the file will be piped
|
||||
* through the command specified by ivlpp_string before being parsed.
|
||||
*/
|
||||
extern int pform_parse(const char*path, FILE*file =0);
|
||||
extern int pform_parse(const char*path);
|
||||
|
||||
extern string vl_file;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_parse_misc_H
|
||||
#define IVL_parse_misc_H
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -71,12 +71,6 @@ extern unsigned long based_size;
|
|||
extern bool in_celldefine;
|
||||
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
|
||||
extern UCDriveType uc_drive;
|
||||
/*
|
||||
* Flags to control if we are declaring or checking a timeunit or
|
||||
* timeprecision statement.
|
||||
*/
|
||||
extern bool have_timeunit_decl;
|
||||
extern bool have_timeprec_decl;
|
||||
|
||||
/*
|
||||
* The parser signals back to the lexor that the next identifier
|
||||
|
|
|
|||
89
pform.h
89
pform.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_pform_H
|
||||
#define IVL_pform_H
|
||||
/*
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -104,7 +104,7 @@ struct net_decl_assign_t {
|
|||
|
||||
/* The lgate is gate instantiation information. */
|
||||
struct lgate {
|
||||
inline lgate(int =0)
|
||||
explicit inline lgate(int =0)
|
||||
: parms(0), parms_by_name(0), file(NULL), lineno(0)
|
||||
{ }
|
||||
|
||||
|
|
@ -147,7 +147,11 @@ extern bool pform_in_interface(void);
|
|||
*/
|
||||
extern PWire* pform_get_wire_in_scope(perm_string name);
|
||||
|
||||
extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type);
|
||||
extern PWire* pform_get_make_wire_in_scope(const struct vlltype&li,
|
||||
perm_string name,
|
||||
NetNet::Type net_type,
|
||||
NetNet::PortType port_type,
|
||||
ivl_variable_type_t vt_type);
|
||||
|
||||
/*
|
||||
* The parser uses startmodule and endmodule together to build up a
|
||||
|
|
@ -163,18 +167,26 @@ extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_ty
|
|||
*/
|
||||
extern void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||
bool program_block, bool is_interface,
|
||||
LexicalScope::lifetime_t lifetime,
|
||||
list<named_pexpr_t>*attr);
|
||||
extern void pform_check_timeunit_prec();
|
||||
extern void pform_module_set_ports(vector<Module::port_t*>*);
|
||||
extern void pform_set_scope_timescale(const struct vlltype&loc);
|
||||
|
||||
/* This function is used to support the port definition in a
|
||||
port_definition_list. In this case, we have everything needed to
|
||||
define the port, all in one place. */
|
||||
/* These functions are used when we have a complete port definition, either
|
||||
in an ansi style or non-ansi style declaration. In this case, we have
|
||||
everything needed to define the port, all in one place. */
|
||||
extern void pform_module_define_port(const struct vlltype&li,
|
||||
perm_string name,
|
||||
NetNet::PortType,
|
||||
NetNet::Type type,
|
||||
data_type_t*vtype,
|
||||
list<named_pexpr_t>*attr,
|
||||
bool keep_attr =false);
|
||||
extern void pform_module_define_port(const struct vlltype&li,
|
||||
list<pform_port_t>*ports,
|
||||
NetNet::PortType,
|
||||
NetNet::Type type,
|
||||
data_type_t*vtype,
|
||||
list<named_pexpr_t>*attr);
|
||||
|
||||
extern Module::port_t* pform_module_port_reference(perm_string name,
|
||||
|
|
@ -186,7 +198,8 @@ extern void pform_endmodule(const char*, bool inside_celldefine,
|
|||
extern void pform_start_class_declaration(const struct vlltype&loc,
|
||||
class_type_t*type,
|
||||
data_type_t*base_type,
|
||||
std::list<PExpr*>*base_exprs);
|
||||
std::list<PExpr*>*base_exprs,
|
||||
LexicalScope::lifetime_t lifetime);
|
||||
extern void pform_class_property(const struct vlltype&loc,
|
||||
property_qualifier_t pq,
|
||||
data_type_t*data_type,
|
||||
|
|
@ -211,7 +224,8 @@ extern void pform_make_udp(perm_string name,
|
|||
* Package related functions.
|
||||
*/
|
||||
extern void pform_start_package_declaration(const struct vlltype&loc,
|
||||
const char*type);
|
||||
const char*type,
|
||||
LexicalScope::lifetime_t lifetime);
|
||||
extern void pform_end_package_declaration(const struct vlltype&loc);
|
||||
extern void pform_package_import(const struct vlltype&loc,
|
||||
PPackage*pkg, const char*ident);
|
||||
|
|
@ -246,13 +260,20 @@ extern void pform_pop_scope();
|
|||
*/
|
||||
extern LexicalScope* pform_peek_scope();
|
||||
|
||||
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name);
|
||||
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
|
||||
LexicalScope::lifetime_t lifetime);
|
||||
|
||||
extern PFunction*pform_push_constructor_scope(const struct vlltype&loc);
|
||||
extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name);
|
||||
|
||||
extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name,
|
||||
LexicalScope::lifetime_t lifetime);
|
||||
|
||||
extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name,
|
||||
bool is_auto);
|
||||
LexicalScope::lifetime_t lifetime);
|
||||
|
||||
extern PFunction*pform_push_function_scope(const struct vlltype&loc, const char*name,
|
||||
bool is_auto);
|
||||
LexicalScope::lifetime_t lifetime);
|
||||
|
||||
extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
|
||||
|
||||
extern void pform_put_behavior_in_scope(AProcess*proc);
|
||||
|
|
@ -351,17 +372,17 @@ extern void pform_makewire(const struct vlltype&li,
|
|||
list<perm_string>*names,
|
||||
list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_make_reginit(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr);
|
||||
extern void pform_make_var_init(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr);
|
||||
|
||||
/* Look up the names of the wires, and set the port type,
|
||||
i.e. input, output or inout. If the wire does not exist, create
|
||||
it. The second form takes a single name. */
|
||||
/* This function is used when we have an incomplete port definition in
|
||||
a non-ansi style declaration. Look up the names of the wires, and set
|
||||
the port type, i.e. input, output or inout, and, if specified, the
|
||||
range and signedness. If the wire does not exist, create it. */
|
||||
extern void pform_set_port_type(const struct vlltype&li,
|
||||
list<perm_string>*names,
|
||||
list<pform_range_t>*range,
|
||||
bool signed_flag,
|
||||
list<pform_port_t>*ports,
|
||||
NetNet::PortType,
|
||||
data_type_t*dt,
|
||||
list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_reg_idx(perm_string name,
|
||||
|
|
@ -369,11 +390,11 @@ extern void pform_set_reg_idx(perm_string name,
|
|||
|
||||
extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
extern void pform_set_struct_type(const struct vlltype&li, struct_type_t*struct_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_string_type(const string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
extern void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_class_type(class_type_t*class_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*addr);
|
||||
extern void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*addr);
|
||||
|
||||
|
||||
/* pform_set_attrib and pform_set_type_attrib exist to support the
|
||||
|
|
@ -407,6 +428,13 @@ extern void pform_set_specparam(const struct vlltype&loc,
|
|||
PExpr*expr);
|
||||
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
|
||||
|
||||
extern void pform_set_param_from_type(const struct vlltype&loc,
|
||||
const data_type_t *data_type,
|
||||
const char *name,
|
||||
list<pform_range_t> *¶m_range,
|
||||
bool ¶m_signed,
|
||||
ivl_variable_type_t ¶m_type);
|
||||
|
||||
/*
|
||||
* Functions related to specify blocks.
|
||||
*/
|
||||
|
|
@ -454,7 +482,8 @@ extern void pform_makegates(const struct vlltype&loc,
|
|||
extern void pform_make_modgates(const struct vlltype&loc,
|
||||
perm_string type,
|
||||
struct parmvalue_t*overrides,
|
||||
svector<lgate>*gates);
|
||||
svector<lgate>*gates,
|
||||
list<named_pexpr_t>*attr);
|
||||
|
||||
/* Make a continuous assignment node, with optional bit- or part- select. */
|
||||
extern void pform_make_pgassign_list(list<PExpr*>*alist,
|
||||
|
|
@ -542,8 +571,12 @@ extern void parm_to_defparam_list(const string¶m);
|
|||
*/
|
||||
extern bool get_time_unit(const char*cp, int &unit);
|
||||
extern int pform_get_timeunit();
|
||||
extern void pform_set_timeunit(const char*txt, bool in_module, bool only_check);
|
||||
extern void pform_set_timeprecision(const char*txt, bool in_module,
|
||||
bool only_check);
|
||||
extern void pform_set_timeunit(const char*txt, bool initial_decl);
|
||||
extern void pform_set_timeprec(const char*txt, bool initial_decl);
|
||||
/*
|
||||
* Flags to determine whether this is an initial declaration.
|
||||
*/
|
||||
extern bool allow_timeunit_decl;
|
||||
extern bool allow_timeprec_decl;
|
||||
|
||||
#endif /* IVL_pform_H */
|
||||
|
|
|
|||
|
|
@ -22,18 +22,18 @@
|
|||
# include "parse_misc.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static void pform_set_class_type(class_type_t*class_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
static void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS);
|
||||
PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS);
|
||||
assert(net);
|
||||
net->set_data_type(class_type);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
void pform_set_class_type(class_type_t*class_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ cur) {
|
||||
pform_set_class_type(class_type, *cur, net_type, attr);
|
||||
pform_set_class_type(li, class_type, *cur, net_type, attr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 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
|
||||
|
|
@ -121,6 +121,15 @@ std::ostream& operator << (std::ostream&out, ivl_process_type_t pt)
|
|||
case IVL_PR_ALWAYS:
|
||||
out << "always";
|
||||
break;
|
||||
case IVL_PR_ALWAYS_COMB:
|
||||
out << "always_comb";
|
||||
break;
|
||||
case IVL_PR_ALWAYS_FF:
|
||||
out << "always_ff";
|
||||
break;
|
||||
case IVL_PR_ALWAYS_LATCH:
|
||||
out << "always_latch";
|
||||
break;
|
||||
case IVL_PR_FINAL:
|
||||
out << "final";
|
||||
break;
|
||||
|
|
@ -318,7 +327,7 @@ void PECallFunction::dump(ostream &out) const
|
|||
|
||||
void PECastSize::dump(ostream &out) const
|
||||
{
|
||||
out << size_ << "'(";
|
||||
out << *size_ << "'(";
|
||||
base_->dump(out);
|
||||
out << ")";
|
||||
}
|
||||
|
|
@ -627,10 +636,10 @@ void PGBuiltin::dump(ostream&out, unsigned ind) const
|
|||
out << "bufif1 ";
|
||||
break;
|
||||
case PGBuiltin::NOTIF0:
|
||||
out << "bufif0 ";
|
||||
out << "notif0 ";
|
||||
break;
|
||||
case PGBuiltin::NOTIF1:
|
||||
out << "bufif1 ";
|
||||
out << "notif1 ";
|
||||
break;
|
||||
case PGBuiltin::NAND:
|
||||
out << "nand ";
|
||||
|
|
@ -729,6 +738,7 @@ void PGModule::dump(ostream&out, unsigned ind) const
|
|||
dump_pins(out);
|
||||
}
|
||||
out << ");" << endl;
|
||||
dump_attributes_map(out, attributes, 8);
|
||||
}
|
||||
|
||||
void Statement::dump(ostream&out, unsigned ind) const
|
||||
|
|
@ -789,6 +799,8 @@ void PBlock::dump(ostream&out, unsigned ind) const
|
|||
dump_events_(out, ind+2);
|
||||
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
dump_var_inits_(out, ind+2);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
|
||||
|
|
@ -841,7 +853,7 @@ void PCase::dump(ostream&out, unsigned ind) const
|
|||
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
||||
PCase::Item*cur = (*items_)[idx];
|
||||
|
||||
if (cur->expr.size()) {
|
||||
if (! cur->expr.empty()) {
|
||||
out << setw(ind+2) << "" << "default:";
|
||||
|
||||
} else {
|
||||
|
|
@ -926,7 +938,10 @@ void PDisable::dump(ostream&out, unsigned ind) const
|
|||
void PDoWhile::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "do" << endl;
|
||||
statement_->dump(out, ind+3);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind+3) << "" << "/* NOOP */" << endl;
|
||||
out << setw(ind) << "" << "while (" << *cond_ << ");" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -989,13 +1004,19 @@ void PForeach::dump(ostream&fd, unsigned ind) const
|
|||
}
|
||||
|
||||
fd << "] /* " << get_fileline() << " */" << endl;
|
||||
statement_->dump(fd, ind+3);
|
||||
if (statement_)
|
||||
statement_->dump(fd, ind+3);
|
||||
else
|
||||
fd << setw(ind+3) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PForever::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "forever /* " << get_fileline() << " */" << endl;
|
||||
statement_->dump(out, ind+3);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind+3) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PForStatement::dump(ostream&out, unsigned ind) const
|
||||
|
|
@ -1003,7 +1024,10 @@ void PForStatement::dump(ostream&out, unsigned ind) const
|
|||
out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_
|
||||
<< "; " << *cond_ << "; <for_step>)" << endl;
|
||||
step_->dump(out, ind+6);
|
||||
statement_->dump(out, ind+3);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind+3) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PFunction::dump(ostream&out, unsigned ind) const
|
||||
|
|
@ -1030,6 +1054,8 @@ void PFunction::dump(ostream&out, unsigned ind) const
|
|||
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
dump_var_inits_(out, ind+2);
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
|
|
@ -1045,7 +1071,10 @@ void PRelease::dump(ostream&out, unsigned ind) const
|
|||
void PRepeat::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "repeat (" << *expr_ << ")" << endl;
|
||||
statement_->dump(out, ind+3);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind+3) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PReturn::dump(ostream&fd, unsigned ind) const
|
||||
|
|
@ -1072,6 +1101,8 @@ void PTask::dump(ostream&out, unsigned ind) const
|
|||
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
dump_var_inits_(out, ind+2);
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
|
|
@ -1126,7 +1157,10 @@ void PTrigger::dump(ostream&out, unsigned ind) const
|
|||
void PWhile::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "while (" << *cond_ << ")" << endl;
|
||||
statement_->dump(out, ind+3);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind+3) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PProcess::dump(ostream&out, unsigned ind) const
|
||||
|
|
@ -1136,7 +1170,10 @@ void PProcess::dump(ostream&out, unsigned ind) const
|
|||
|
||||
dump_attributes_map(out, attributes, ind+2);
|
||||
|
||||
statement_->dump(out, ind+2);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
out << setw(ind+2) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void AProcess::dump(ostream&out, unsigned ind) const
|
||||
|
|
@ -1148,6 +1185,11 @@ void AProcess::dump(ostream&out, unsigned ind) const
|
|||
case IVL_PR_ALWAYS:
|
||||
out << setw(ind) << "" << "analog";
|
||||
break;
|
||||
case IVL_PR_ALWAYS_COMB:
|
||||
case IVL_PR_ALWAYS_FF:
|
||||
case IVL_PR_ALWAYS_LATCH:
|
||||
assert(0);
|
||||
break;
|
||||
case IVL_PR_FINAL:
|
||||
out << setw(ind) << "" << "analog final";
|
||||
break;
|
||||
|
|
@ -1157,7 +1199,10 @@ void AProcess::dump(ostream&out, unsigned ind) const
|
|||
|
||||
dump_attributes_map(out, attributes, ind+2);
|
||||
|
||||
statement_->dump(out, ind+2);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
out << setw(ind+2) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PSpecPath::dump(std::ostream&out, unsigned ind) const
|
||||
|
|
@ -1269,6 +1314,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const
|
|||
(*idx)->dump(out, indent+2);
|
||||
}
|
||||
|
||||
dump_var_inits_(out, indent+2);
|
||||
|
||||
for (list<PProcess*>::const_iterator idx = behaviors.begin()
|
||||
; idx != behaviors.end() ; ++ idx ) {
|
||||
(*idx)->dump(out, indent+2);
|
||||
|
|
@ -1408,6 +1455,14 @@ void LexicalScope::dump_wires_(ostream&out, unsigned indent) const
|
|||
}
|
||||
}
|
||||
|
||||
void LexicalScope::dump_var_inits_(ostream&out, unsigned indent) const
|
||||
{
|
||||
// Iterate through and display all the register initializations.
|
||||
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
|
||||
var_inits[idx]->dump(out, indent);
|
||||
}
|
||||
}
|
||||
|
||||
void PScopeExtra::dump_classes_(ostream&out, unsigned indent) const
|
||||
{
|
||||
// Dump the task definitions.
|
||||
|
|
@ -1564,6 +1619,7 @@ void Module::dump(ostream&out) const
|
|||
(*gate)->dump(out);
|
||||
}
|
||||
|
||||
dump_var_inits_(out, 4);
|
||||
|
||||
for (list<PProcess*>::const_iterator behav = behaviors.begin()
|
||||
; behav != behaviors.end() ; ++ behav ) {
|
||||
|
|
@ -1664,8 +1720,10 @@ void PPackage::pform_dump(std::ostream&out) const
|
|||
dump_localparams_(out, 4);
|
||||
dump_parameters_(out, 4);
|
||||
dump_enumerations_(out, 4);
|
||||
dump_wires_(out, 4);
|
||||
dump_tasks_(out, 4);
|
||||
dump_funcs_(out, 4);
|
||||
dump_var_inits_(out, 4);
|
||||
out << "endpackage" << endl;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -35,12 +35,13 @@ map<perm_string,PPackage*> pform_packages;
|
|||
|
||||
static PPackage*pform_cur_package = 0;
|
||||
|
||||
void pform_start_package_declaration(const struct vlltype&loc, const char*name)
|
||||
void pform_start_package_declaration(const struct vlltype&loc, const char*name,
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
ivl_assert(loc, pform_cur_package == 0);
|
||||
|
||||
perm_string use_name = lex_strings.make(name);
|
||||
PPackage*pkg_scope = pform_push_package_scope(loc, use_name);
|
||||
PPackage*pkg_scope = pform_push_package_scope(loc, use_name, lifetime);
|
||||
FILE_NAME(pkg_scope, loc);
|
||||
pform_cur_package = pkg_scope;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2016 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
|
||||
|
|
@ -36,9 +36,13 @@ static PClass*pform_cur_class = 0;
|
|||
* if present, are the "exprs" that would be passed to a chained
|
||||
* constructor.
|
||||
*/
|
||||
void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, data_type_t*base_type, list<PExpr*>*base_exprs)
|
||||
void pform_start_class_declaration(const struct vlltype&loc,
|
||||
class_type_t*type,
|
||||
data_type_t*base_type,
|
||||
list<PExpr*>*base_exprs,
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
PClass*class_scope = pform_push_class_scope(loc, type->name);
|
||||
PClass*class_scope = pform_push_class_scope(loc, type->name, lifetime);
|
||||
class_scope->type = type;
|
||||
assert(pform_cur_class == 0);
|
||||
pform_cur_class = class_scope;
|
||||
|
|
@ -75,6 +79,7 @@ void pform_class_property(const struct vlltype&loc,
|
|||
if (! curp->index.empty()) {
|
||||
list<pform_range_t>*pd = new list<pform_range_t> (curp->index);
|
||||
use_type = new uarray_type_t(use_type, pd);
|
||||
FILE_NAME(use_type, loc);
|
||||
}
|
||||
|
||||
pform_cur_class->type->properties[curp->name]
|
||||
|
|
@ -127,7 +132,7 @@ void pform_set_constructor_return(PFunction*net)
|
|||
PFunction*pform_push_constructor_scope(const struct vlltype&loc)
|
||||
{
|
||||
assert(pform_cur_class);
|
||||
PFunction*func = pform_push_function_scope(loc, "new", true);
|
||||
PFunction*func = pform_push_function_scope(loc, "new", LexicalScope::AUTOMATIC);
|
||||
return func;
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +143,7 @@ void pform_end_class_declaration(const struct vlltype&loc)
|
|||
// If there were initializer statements, then collect them
|
||||
// into an implicit constructor function.
|
||||
if (! pform_cur_class->type->initialize.empty()) {
|
||||
PFunction*func = pform_push_function_scope(loc, "new@", true);
|
||||
PFunction*func = pform_push_function_scope(loc, "new@", LexicalScope::AUTOMATIC);
|
||||
func->set_ports(0);
|
||||
pform_set_constructor_return(func);
|
||||
pform_set_this_class(loc, func);
|
||||
|
|
|
|||
|
|
@ -21,18 +21,17 @@
|
|||
# include "parse_misc.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static void pform_set_string_type(const string_type_t*, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
static void pform_set_string_type(const struct vlltype&li, const string_type_t*, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING);
|
||||
PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING);
|
||||
assert(net);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
void pform_set_string_type(const string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ cur) {
|
||||
pform_set_string_type(string_type, *cur, net_type, attr);
|
||||
pform_set_string_type(li, string_type, *cur, net_type, attr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,32 +62,32 @@ ivl_variable_type_t struct_type_t::figure_packed_base_type(void) const
|
|||
* out the base type of the packed variable. Elaboration, later on,
|
||||
* well figure out the rest.
|
||||
*/
|
||||
static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
static void pform_set_packed_struct(const struct vlltype&li, struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
ivl_variable_type_t base_type = struct_type->figure_packed_base_type();
|
||||
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
|
||||
PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, base_type);
|
||||
assert(net);
|
||||
net->set_data_type(struct_type);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
static void pform_set_struct_type(const struct vlltype&li, struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
if (struct_type->packed_flag) {
|
||||
pform_set_packed_struct(struct_type, name, net_type, attr);
|
||||
pform_set_packed_struct(li, struct_type, name, net_type, attr);
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, can only handle packed structs.
|
||||
ivl_assert(*struct_type, 0);
|
||||
// For now, can only handle packed structs. The parser generates
|
||||
// a "sorry" message, so no need to do anything here.
|
||||
}
|
||||
|
||||
void pform_set_struct_type(struct_type_t*struct_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
void pform_set_struct_type(const struct vlltype&li, struct_type_t*struct_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ cur) {
|
||||
pform_set_struct_type(struct_type, *cur, net_type, attr);
|
||||
pform_set_struct_type(li, struct_type, *cur, net_type, attr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ static void pform_makewire(const struct vlltype&li,
|
|||
{
|
||||
ivl_variable_type_t base_type = struct_type->figure_packed_base_type();
|
||||
|
||||
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type);
|
||||
PWire*cur = pform_get_make_wire_in_scope(li, name, NetNet::WIRE, ptype, base_type);
|
||||
assert(cur);
|
||||
FILE_NAME(cur, li);
|
||||
cur->set_data_type(struct_type);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_pform_types_H
|
||||
#define IVL_pform_types_H
|
||||
/*
|
||||
* Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2007-2018 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
|
||||
|
|
@ -33,6 +33,10 @@
|
|||
# include <map>
|
||||
# include <memory>
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#define unique_ptr auto_ptr
|
||||
#endif
|
||||
|
||||
/*
|
||||
* parse-form types.
|
||||
*/
|
||||
|
|
@ -50,7 +54,7 @@ typedef named<verinum> named_number_t;
|
|||
typedef named<PExpr*> named_pexpr_t;
|
||||
|
||||
/*
|
||||
* The pform_range_t holds variable diimensions for type
|
||||
* The pform_range_t holds variable dimensions for type
|
||||
* declarations. The two expressions are interpreted as the first and
|
||||
* last values of the range. For example:
|
||||
*
|
||||
|
|
@ -72,6 +76,21 @@ typedef named<PExpr*> named_pexpr_t;
|
|||
*/
|
||||
typedef std::pair<PExpr*,PExpr*> pform_range_t;
|
||||
|
||||
/*
|
||||
* The pform_port_t holds the name and optional unpacked dimensions
|
||||
* and initialization expression for a single port in a list of port
|
||||
* declarations.
|
||||
*/
|
||||
struct pform_port_t {
|
||||
pform_port_t(perm_string n, list<pform_range_t>*ud, PExpr*e)
|
||||
: name(n), udims(ud), expr(e) { }
|
||||
~pform_port_t() { }
|
||||
|
||||
perm_string name;
|
||||
list<pform_range_t>*udims;
|
||||
PExpr*expr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Semantic NOTES:
|
||||
* - The SEL_BIT is a single expression. This might me a bit select
|
||||
|
|
@ -102,7 +121,7 @@ struct name_component_t {
|
|||
struct decl_assignment_t {
|
||||
perm_string name;
|
||||
std::list<pform_range_t>index;
|
||||
std::auto_ptr<PExpr> expr;
|
||||
std::unique_ptr<PExpr> expr;
|
||||
};
|
||||
|
||||
struct pform_tf_port_t {
|
||||
|
|
@ -155,14 +174,14 @@ struct enum_type_t : public data_type_t {
|
|||
ivl_variable_type_t base_type;
|
||||
bool signed_flag;
|
||||
bool integer_flag; // True if "integer" was used
|
||||
std::auto_ptr< list<pform_range_t> > range;
|
||||
std::auto_ptr< list<named_pexpr_t> > names;
|
||||
std::unique_ptr< list<pform_range_t> > range;
|
||||
std::unique_ptr< list<named_pexpr_t> > names;
|
||||
LineInfo li;
|
||||
};
|
||||
|
||||
struct struct_member_t : public LineInfo {
|
||||
std::auto_ptr<data_type_t> type;
|
||||
std::auto_ptr< list<decl_assignment_t*> > names;
|
||||
std::unique_ptr<data_type_t> type;
|
||||
std::unique_ptr< list<decl_assignment_t*> > names;
|
||||
void pform_dump(std::ostream&out, unsigned indent) const;
|
||||
};
|
||||
|
||||
|
|
@ -173,7 +192,7 @@ struct struct_type_t : public data_type_t {
|
|||
|
||||
bool packed_flag;
|
||||
bool union_flag;
|
||||
std::auto_ptr< list<struct_member_t*> > members;
|
||||
std::unique_ptr< list<struct_member_t*> > members;
|
||||
};
|
||||
|
||||
struct atom2_type_t : public data_type_t {
|
||||
|
|
@ -219,7 +238,7 @@ struct vector_type_t : public data_type_t {
|
|||
bool reg_flag; // True if "reg" was used
|
||||
bool integer_flag; // True if "integer" was used
|
||||
bool implicit_flag; // True if this type is implicitly logic/reg
|
||||
std::auto_ptr< list<pform_range_t> > pdims;
|
||||
std::unique_ptr< list<pform_range_t> > pdims;
|
||||
};
|
||||
|
||||
struct array_base_t : public data_type_t {
|
||||
|
|
@ -228,7 +247,7 @@ struct array_base_t : public data_type_t {
|
|||
: base_type(btype), dims(pd) { }
|
||||
|
||||
data_type_t*base_type;
|
||||
std::auto_ptr< list<pform_range_t> > dims;
|
||||
std::unique_ptr< list<pform_range_t> > dims;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -361,4 +380,8 @@ extern std::ostream& operator<< (std::ostream&out, const pform_name_t&);
|
|||
extern std::ostream& operator<< (std::ostream&out, const name_component_t&that);
|
||||
extern std::ostream& operator<< (std::ostream&out, const index_component_t&that);
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#undef unique_ptr
|
||||
#endif
|
||||
|
||||
#endif /* IVL_pform_types_H */
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# the number for a snapshot and the path to a temporary directory.
|
||||
# for example:
|
||||
#
|
||||
# sh scripts/MAKE_RELEASE.sh 0.9.1 ~/tmp
|
||||
# sh scripts/MAKE_RELEASE.sh 10.1 ~/tmp
|
||||
#
|
||||
# The above assumes that there is a tag "v0_9_1" at the point
|
||||
# to be released. (The tag has the "v", but the argument to this
|
||||
|
|
@ -13,13 +13,17 @@
|
|||
# and finally creates a file called verilog-0.9.1.tar.gz that
|
||||
# contains the release ready to go.
|
||||
#
|
||||
# The complete steps to make a release x.y.z generally are:
|
||||
# The complete steps to make a release x.y generally are:
|
||||
#
|
||||
# git tag -a v0_9_1
|
||||
# Edit version_base.h to suit.
|
||||
#
|
||||
# Edit verilog.spec to suit.
|
||||
#
|
||||
# git tag -a v10_1
|
||||
# (Make the tag in the local git repository.)
|
||||
#
|
||||
# sh scripts/MAKE_RELEASE.sh 0.9.1 ~/tmp
|
||||
# (Make the snapshot bundle verilog-0.9.1.tar.gz)
|
||||
# sh scripts/MAKE_RELEASE.sh 10.1 ~/tmp
|
||||
# (Make the snapshot bundle verilog-10.1.tar.gz)
|
||||
#
|
||||
# git push --tags
|
||||
# (Publish the tag to the repository.)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ iwidth:32
|
|||
sys_func:vpi/system.sft
|
||||
sys_func:vpi/v2005_math.sft
|
||||
sys_func:vpi/va_math.sft
|
||||
warnings:ailnpstv
|
||||
warnings:adfilnpstv
|
||||
debug:eval_tree
|
||||
debug:elaborate
|
||||
debug:emit
|
||||
|
|
|
|||
|
|
@ -72,6 +72,13 @@ EXTERN_C_START
|
|||
/********* Many-to-One ***********/
|
||||
#define vpiMember 742
|
||||
|
||||
/********* task/function properties **********/
|
||||
#define vpiOtherFunc 6
|
||||
|
||||
/* Icarus-specific function type to use string as the return type */
|
||||
#define vpiStringFunc 10
|
||||
#define vpiSysFuncString vpiSysFuncString
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif /* SV_VPI_USER_H */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_svector_H
|
||||
#define IVL_svector_H
|
||||
/*
|
||||
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2017 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
|
||||
|
|
@ -39,7 +39,7 @@ template <class TYPE> class svector {
|
|||
|
||||
explicit svector(unsigned size) : nitems_(size), items_(new TYPE[size])
|
||||
{ for (unsigned idx = 0 ; idx < size ; idx += 1)
|
||||
items_[idx] = 0;
|
||||
items_[idx] = TYPE(0);
|
||||
}
|
||||
|
||||
svector(const svector<TYPE>&that)
|
||||
|
|
@ -57,7 +57,7 @@ template <class TYPE> class svector {
|
|||
items_[l.nitems_+idx] = r[idx];
|
||||
}
|
||||
|
||||
svector(const svector<TYPE>&l, TYPE r)
|
||||
svector(const svector<TYPE>&l, TYPE&r)
|
||||
: nitems_(l.nitems_ + 1), items_(new TYPE[nitems_])
|
||||
{ for (unsigned idx = 0 ; idx < l.nitems_ ; idx += 1)
|
||||
items_[idx] = l[idx];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -66,6 +66,7 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
bool prefix_scope = false;
|
||||
bool recurse_flag = false;
|
||||
|
||||
assert(li);
|
||||
ivl_assert(*li, ! path.empty());
|
||||
name_component_t path_tail = path.back();
|
||||
path.pop_back();
|
||||
|
|
@ -94,7 +95,7 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
scope = recurse.scope;
|
||||
prefix_scope = true;
|
||||
|
||||
if (scope->is_auto() && li) {
|
||||
if (scope->is_auto()) {
|
||||
cerr << li->get_fileline() << ": error: Hierarchical "
|
||||
"reference to automatically allocated item "
|
||||
"`" << path_tail.name << "' in path `" << path << "'" << endl;
|
||||
|
|
@ -142,14 +143,21 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
// Don't scan up past a module boundary.
|
||||
if (scope->type()==NetScope::MODULE && !scope->nested_module())
|
||||
break;
|
||||
// Don't scan up if we are searching within a prefixed scope.
|
||||
if (prefix_scope)
|
||||
break;
|
||||
|
||||
scope = scope->parent();
|
||||
// Don't scan up past a module boundary.
|
||||
if (scope->type()==NetScope::MODULE && !scope->nested_module())
|
||||
scope = 0;
|
||||
else
|
||||
scope = scope->parent();
|
||||
|
||||
// Last chance - try the compilation unit.
|
||||
if (scope == 0 && start_scope != 0) {
|
||||
scope = start_scope->unit();
|
||||
start_scope = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Last chance: this is a single name, so it might be the name
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue