mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-23 14:27:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
453c546589 | ||
|
|
4914f83ae3 | ||
|
|
b7b22660e5 | ||
|
|
a6eb59192e | ||
|
|
dbcb7e5fb6 | ||
|
|
2546631874 | ||
|
|
8e54e31bd8 | ||
|
|
9a81d5dd65 | ||
|
|
564c7404a6 | ||
|
|
a01b7054fc | ||
|
|
e834302875 | ||
|
|
7f418af98a | ||
|
|
5b5c0f5c69 | ||
|
|
892f5f84c4 | ||
|
|
cb4c98bd4e | ||
|
|
49066f1601 | ||
|
|
5a9a4c4f94 | ||
|
|
6ebe707091 | ||
|
|
9b5906b000 | ||
|
|
27cac593e3 | ||
|
|
7399f3744b | ||
|
|
d46e7ace70 | ||
|
|
bda6e0ae3f | ||
|
|
bd721c1483 | ||
|
|
41c6a0e0fe | ||
|
|
37b98bbe67 | ||
|
|
f62d738813 | ||
|
|
19444dd2fa | ||
|
|
bd4d73d9ae | ||
|
|
edfe398e26 | ||
|
|
acae85d1a4 | ||
|
|
95444b474d | ||
|
|
3581da23e3 | ||
|
|
10448bf94b | ||
|
|
10e7eb55ce | ||
|
|
062fc43fab | ||
|
|
869513a1ec | ||
|
|
ac2f5f0740 | ||
|
|
4cb9ae0aa2 | ||
|
|
8e77900b9c | ||
|
|
400428a2b6 | ||
|
|
de63c0cedb | ||
|
|
10fc8048ac | ||
|
|
c5df4cfcad | ||
|
|
f2a711b8f1 | ||
|
|
dc6fc7ee77 | ||
|
|
16c18eda2e | ||
|
|
5474f9d5ac | ||
|
|
d5be428e45 | ||
|
|
c831ce0aae | ||
|
|
ab6ae797b3 | ||
|
|
52b136d8a8 | ||
|
|
703363feaf | ||
|
|
e79d226082 | ||
|
|
7df0f0c659 | ||
|
|
24731227b4 | ||
|
|
0f28b03dd3 | ||
|
|
02e220097d | ||
|
|
fc62c91496 | ||
|
|
6dce878638 | ||
|
|
480fb0b418 | ||
|
|
dab896c463 | ||
|
|
94861872e5 | ||
|
|
cc3e9d791a | ||
|
|
03764a400d | ||
|
|
99f66e2781 | ||
|
|
a74c3a1207 | ||
|
|
dec9a8b527 | ||
|
|
1b0843c94c | ||
|
|
bb2e270087 | ||
|
|
a18fe22d32 | ||
|
|
1f7588d3a4 | ||
|
|
09c7c439a1 | ||
|
|
a907200fb9 | ||
|
|
bccb7e7def | ||
|
|
6b11df1999 | ||
|
|
95d3579509 | ||
|
|
a3a8669c6f | ||
|
|
885e25120a | ||
|
|
7b372c3a0c | ||
|
|
3d14281e0d | ||
|
|
2564554178 | ||
|
|
8cd697fd24 | ||
|
|
306d2fb53b | ||
|
|
52b497f74c | ||
|
|
ce7f28202a | ||
|
|
49bea6a01a | ||
|
|
8ab100c1c7 | ||
|
|
177ae7c220 | ||
|
|
b04d5a9068 | ||
|
|
b8c8f03037 | ||
|
|
38013f7a34 | ||
|
|
561638a31f | ||
|
|
bb91512e75 | ||
|
|
09ff851483 | ||
|
|
19d8f43e9b | ||
|
|
ce88deaa97 | ||
|
|
1a8b19baf2 | ||
|
|
b3cf533b3c | ||
|
|
ba3856ebb0 | ||
|
|
c06e2790a7 | ||
|
|
6e460a6a3f | ||
|
|
dbc536c4fb | ||
|
|
5e41c86d01 | ||
|
|
572124e1e9 | ||
|
|
37ecdb4cfb | ||
|
|
a11dc8b472 | ||
|
|
e7852f8f9c | ||
|
|
9449c46865 | ||
|
|
8a780ece56 | ||
|
|
8bb4777789 | ||
|
|
3b705d95a6 | ||
|
|
f9559853f1 | ||
|
|
cda95c1554 | ||
|
|
4066031add | ||
|
|
d6d50e9b68 | ||
|
|
0ffbb2b1de | ||
|
|
9b55a3d67f | ||
|
|
07623bef2e | ||
|
|
73d688c313 | ||
|
|
6155986d1c | ||
|
|
face462cc2 | ||
|
|
a5f6329500 | ||
|
|
3e13594816 | ||
|
|
99138eafb1 | ||
|
|
86968e3752 | ||
|
|
27a46f4afe | ||
|
|
d770199550 | ||
|
|
06f6a72770 | ||
|
|
30257e0914 | ||
|
|
b2281b0e65 | ||
|
|
161cebb178 | ||
|
|
b46d8b8389 | ||
|
|
2689ebacfe | ||
|
|
5bbb054173 | ||
|
|
7d2eeb0137 | ||
|
|
4aef636559 | ||
|
|
72fc3d712d | ||
|
|
3f75f6b155 | ||
|
|
9be3fc3a56 | ||
|
|
aa2260f4fa | ||
|
|
6974613bff | ||
|
|
8bd4e9d481 | ||
|
|
04ae07f03c | ||
|
|
d9be5318f9 | ||
|
|
88cd5534c4 | ||
|
|
3b577340ad | ||
|
|
583a31c121 | ||
|
|
a391c3ae28 | ||
|
|
b551a783e8 | ||
|
|
33db07ab8d | ||
|
|
e2aae72880 | ||
|
|
ec9897af5a | ||
|
|
2771abf86a | ||
|
|
b0461787c8 | ||
|
|
6f41576930 | ||
|
|
cc7516eab3 | ||
|
|
1a5ae96540 | ||
|
|
1ea8a13bf8 | ||
|
|
490884cf7b | ||
|
|
ca1d7ccffe | ||
|
|
faf9bfe158 | ||
|
|
086ce04cf5 | ||
|
|
7b7231c417 | ||
|
|
d7b919f6d0 | ||
|
|
9b34a96cb9 | ||
|
|
90cf0e5794 | ||
|
|
818379b9bc | ||
|
|
9fbb7f84e6 | ||
|
|
ed7d6c1002 | ||
|
|
a4306dbac1 | ||
|
|
a682e13d82 | ||
|
|
643e0a984e | ||
|
|
63d2059b85 | ||
|
|
d9e09ceb59 | ||
|
|
6d0ab9978f | ||
|
|
e25cdf86ac | ||
|
|
13bff8c50d | ||
|
|
b1b017251a | ||
|
|
e13a52637a | ||
|
|
4803f0d12b | ||
|
|
be44289fc0 | ||
|
|
e682166253 | ||
|
|
e2a1f21896 | ||
|
|
cb73accd84 | ||
|
|
a66361a4f2 | ||
|
|
1159de0482 | ||
|
|
ac5d4114ad | ||
|
|
85f796fda2 | ||
|
|
8612ec5452 | ||
|
|
870a351944 |
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -257,6 +257,7 @@ parse.cc: $(srcdir)/parse.y
|
||||
$(YACC) --verbose -t -p VL -d -o $@ $<
|
||||
parse.h: parse.cc
|
||||
mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@
|
||||
touch $@
|
||||
|
||||
syn-rules.cc: $(srcdir)/syn-rules.y
|
||||
$(YACC) --verbose -t -p syn_ -o $@ $<
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2010 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2016 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -35,9 +35,6 @@ Module::Module(LexicalScope*parent, perm_string n)
|
||||
program_block = false;
|
||||
uc_drive = UCD_NONE;
|
||||
timescale_warn_done = false;
|
||||
time_unit = 0;
|
||||
time_precision = 0;
|
||||
time_from_timescale = false;
|
||||
}
|
||||
|
||||
Module::~Module()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef IVL_Module_H
|
||||
#define IVL_Module_H
|
||||
/*
|
||||
* Copyright (c) 1998-2015 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2016 Stephen Williams ([email protected])
|
||||
*
|
||||
* 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,10 +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
|
||||
|
||||
+2
-19
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008,2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008,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
|
||||
@@ -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,26 @@ PWire* LexicalScope::wires_find(perm_string name)
|
||||
return (*cur).second;
|
||||
}
|
||||
|
||||
PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent)
|
||||
: PScope(n, parent)
|
||||
PScope::PScope(perm_string n, LexicalScope*parent)
|
||||
: LexicalScope(parent), name_(n)
|
||||
{
|
||||
time_unit = 0;
|
||||
time_precision = 0;
|
||||
time_from_timescale = false;
|
||||
}
|
||||
|
||||
PScopeExtra::PScopeExtra(perm_string n)
|
||||
: PScope(n)
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef IVL_PScope_H
|
||||
#define IVL_PScope_H
|
||||
/*
|
||||
* Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-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,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,17 @@ 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 default is
|
||||
set by the `timescale directive or, in SystemVerilog,
|
||||
by timeunit and timeprecision statements. */
|
||||
int time_unit, time_precision;
|
||||
bool time_from_timescale;
|
||||
|
||||
protected:
|
||||
bool elaborate_sig_wires_(Design*des, NetScope*scope) const;
|
||||
|
||||
@@ -168,14 +187,13 @@ 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. */
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
THE ICARUS VERILOG COMPILATION SYSTEM
|
||||
Copyright 2000-2004 Stephen Williams
|
||||
Copyright 2000-2019 Stephen Williams
|
||||
|
||||
|
||||
1.0 What is ICARUS Verilog?
|
||||
@@ -46,8 +46,10 @@ on a UNIX-like system:
|
||||
to work. MSVC++ 5 and 6 are known to definitely *not* work.
|
||||
|
||||
- bison and flex
|
||||
It has been reported that bison 2.3 on MacOS generates broken
|
||||
code, but bison 3.0.4 works.
|
||||
|
||||
- gperf 2.7
|
||||
- gperf 3.0 or later
|
||||
The lexical analyzer doesn't recognize keywords directly,
|
||||
but instead matches symbols and looks them up in a hash
|
||||
table in order to get the proper lexical code. The gperf
|
||||
@@ -56,7 +58,7 @@ on a UNIX-like system:
|
||||
A version problem with this program is the most common cause
|
||||
of difficulty. See the Icarus Verilog FAQ.
|
||||
|
||||
- readline 4.2
|
||||
- readline 4.2 or later
|
||||
On Linux systems, this usually means the readline-devel
|
||||
rpm. In any case, it is the development headers of readline
|
||||
that are needed.
|
||||
@@ -67,7 +69,7 @@ on a UNIX-like system:
|
||||
If you are building from git, you will also need software to generate
|
||||
the configure scripts.
|
||||
|
||||
- autoconf 2.53
|
||||
- autoconf 2.53 or later
|
||||
This generates configure scripts from configure.in. The 2.53
|
||||
or later versions are known to work, autoconf 2.13 is
|
||||
reported to *not* work.
|
||||
|
||||
@@ -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())
|
||||
|
||||
+4
-1
@@ -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.
|
||||
|
||||
Vendored
+1
-1
@@ -225,7 +225,7 @@ 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
|
||||
*-*-mingw32)
|
||||
*-pc-mingw32)
|
||||
LDFLAGS+=" -Wl,--undefined=___strtod,--wrap,strtod,--defsym,___wrap_strtod=___strtod"
|
||||
;;
|
||||
esac
|
||||
|
||||
+19
-15
@@ -1,7 +1,7 @@
|
||||
#ifndef IVL_compiler_H
|
||||
#define IVL_compiler_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
|
||||
@@ -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;
|
||||
|
||||
@@ -138,7 +142,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 +187,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)
|
||||
|
||||
+2
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef IVL_config_H /* -*- c++ -*- */
|
||||
#define IVL_config_H
|
||||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2001-2015 Stephen Williams ([email protected])
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -242,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+5
-4
@@ -4,7 +4,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2001-2017 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -22,8 +22,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "cfparse.h"
|
||||
# include "cfparse_misc.h"
|
||||
# include "cfparse.h"
|
||||
# include "globals.h"
|
||||
# include <string.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
+34
-7
@@ -1,14 +1,15 @@
|
||||
.TH iverilog 1 "Aug 7th, 2015" "" "Version %M.%m.%n %E"
|
||||
.TH iverilog 1 "Oct 2nd, 2016" "" "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>]
|
||||
[\-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 or disable (default) 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.
|
||||
@@ -246,7 +264,7 @@ that contain Verilog source files. During elaboration, the compiler
|
||||
notices the instantiation of undefined module types. If the user
|
||||
specifies library search directories, the compiler will search the
|
||||
directory for files with the name of the missing module type. If it
|
||||
finds such a file, it loads it as a Verilog source file, they tries
|
||||
finds such a file, it loads it as a Verilog source file, then tries
|
||||
again to elaborate the module.
|
||||
|
||||
Library module files should contain only a single module, but this is
|
||||
@@ -402,6 +420,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,
|
||||
@@ -532,7 +559,7 @@ Tips on using, debugging, and developing the compiler can be found at
|
||||
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 2002\-2015 Stephen Williams
|
||||
Copyright \(co 2002\-2016 Stephen Williams
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
|
||||
+28
-14
@@ -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
|
||||
@@ -44,7 +44,7 @@ const char HELP[] =
|
||||
" [-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 = "no-shared-loop-index";
|
||||
const char*gen_verilog_ams = "no-verilog-ams";
|
||||
|
||||
/* Boolean: true means use a default include dir, false means don't */
|
||||
@@ -496,6 +497,7 @@ 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("portbind");
|
||||
process_warning_switch("select-range");
|
||||
process_warning_switch("timescale");
|
||||
@@ -506,6 +508,9 @@ static void process_warning_switch(const char*name)
|
||||
} 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,"portbind") == 0) {
|
||||
if (! strchr(warning_flags, 'p'))
|
||||
strcat(warning_flags, "p");
|
||||
@@ -538,6 +543,12 @@ static void process_warning_switch(const char*name)
|
||||
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-portbind") == 0) {
|
||||
char*cp = strchr(warning_flags, 'p');
|
||||
if (cp) while (*cp) {
|
||||
@@ -720,6 +731,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 +762,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;
|
||||
}
|
||||
@@ -910,7 +928,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:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) {
|
||||
|
||||
switch (opt) {
|
||||
case 'B':
|
||||
@@ -965,6 +983,10 @@ int main(int argc, char **argv)
|
||||
process_include_dir(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
process_file_name(optarg, 1);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (process_depfile(optarg) != 0)
|
||||
return -1;
|
||||
@@ -1047,19 +1069,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-2015 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" : "");
|
||||
@@ -1107,6 +1120,7 @@ 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);
|
||||
|
||||
+105
-86
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -675,10 +675,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 +713,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 +1029,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;
|
||||
@@ -1414,23 +1407,7 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
|
||||
<< " 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 +1446,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;
|
||||
@@ -1606,10 +1590,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 +1647,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2281,10 +2259,7 @@ 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 "
|
||||
@@ -2521,22 +2496,60 @@ 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_);
|
||||
|
||||
// When changing size, a cast behaves exactly like an assignment,
|
||||
// so the result size affects the final expression width.
|
||||
unsigned cast_width = base_->expr_width();
|
||||
if (cast_width < expr_width_)
|
||||
cast_width = expr_width_;
|
||||
|
||||
NetExpr*sub = base_->elaborate_expr(des, scope, cast_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)
|
||||
@@ -2582,7 +2595,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();
|
||||
@@ -2640,17 +2653,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&)
|
||||
@@ -2748,6 +2759,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)"
|
||||
@@ -2842,17 +2854,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) {
|
||||
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;
|
||||
@@ -3443,29 +3454,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()));
|
||||
|
||||
@@ -3769,10 +3792,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)
|
||||
@@ -3808,10 +3828,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
|
||||
@@ -3911,9 +3928,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) {
|
||||
@@ -4492,7 +4507,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_);
|
||||
@@ -5011,6 +5026,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
|
||||
@@ -5327,9 +5344,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);
|
||||
@@ -5580,6 +5596,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: "
|
||||
@@ -5686,7 +5706,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) {
|
||||
@@ -6082,7 +6101,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
|
||||
@@ -6100,7 +6119,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 '~':
|
||||
|
||||
+38
-24
@@ -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
|
||||
@@ -138,6 +138,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 +290,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 +402,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
/* No select expressions. */
|
||||
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
lv->set_signed(reg->get_signed());
|
||||
|
||||
return lv;
|
||||
}
|
||||
@@ -687,20 +691,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;
|
||||
}
|
||||
@@ -797,12 +805,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) {
|
||||
@@ -868,10 +874,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);
|
||||
@@ -934,11 +943,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;
|
||||
@@ -1192,7 +1201,12 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
||||
if (!name_tail.index.empty())
|
||||
use_sel = name_tail.index.back().sel;
|
||||
|
||||
ivl_assert(*this, use_sel == index_component_t::SEL_NONE || use_sel == index_component_t::SEL_BIT);
|
||||
if (use_sel != index_component_t::SEL_NONE && use_sel != index_component_t::SEL_BIT) {
|
||||
cerr << get_fileline() << ": sorry: Assignments to part selects of "
|
||||
"a struct member are not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! name_tail.index.empty()) {
|
||||
|
||||
|
||||
+57
-30
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+26
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2015 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->time_from_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,
|
||||
@@ -500,8 +509,10 @@ 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 (scope)
|
||||
use_base_class = scope->find_class(base_class->name);
|
||||
if (use_base_class == 0)
|
||||
use_base_class = des->find_class(base_class->name);
|
||||
if (use_base_class == 0) {
|
||||
cerr << pclass->get_fileline() << ": error: "
|
||||
<< "Base class " << base_class->name
|
||||
@@ -523,6 +534,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*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.
|
||||
@@ -595,13 +607,9 @@ 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);
|
||||
for (size_t idx = 0 ; idx < pform_classes.size() ; idx += 1) {
|
||||
blend_class_constructors(pform_classes[idx]);
|
||||
elaborate_scope_class(des, 0, pform_classes[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,8 +662,10 @@ 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)
|
||||
if (scope==0) {
|
||||
set_scope_timescale(des, task_scope, task);
|
||||
des->add_root_task(task_scope, task);
|
||||
}
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << task->get_fileline() << ": elaborate_scope_task: "
|
||||
@@ -719,8 +729,10 @@ 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)
|
||||
if (scope==0) {
|
||||
set_scope_timescale(des, task_scope, task);
|
||||
des->add_root_task(task_scope, task);
|
||||
}
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << task->get_fileline() << ": elaborate_scope_func: "
|
||||
@@ -793,7 +805,7 @@ void elaborate_rootscope_tasks(Design*des)
|
||||
}
|
||||
|
||||
cerr << cur->second->get_fileline() << ": internal error: "
|
||||
<< "elabortae_rootscope_tasks does not understand "
|
||||
<< "elaborate_rootscope_tasks does not understand "
|
||||
<< "this object," << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
@@ -1750,11 +1762,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
|
||||
|
||||
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
|
||||
|
||||
+31
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -757,6 +757,11 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
|
||||
<< "Function arguments must be input ports." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
if (tmp->unpacked_dimensions() != 0) {
|
||||
cerr << get_fileline() << ": sorry: Subroutine ports with "
|
||||
"unpacked dimensions are not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,6 +981,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 */
|
||||
@@ -1168,6 +1190,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;
|
||||
@@ -1178,14 +1208,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
-1
@@ -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
|
||||
@@ -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"
|
||||
@@ -245,6 +247,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);
|
||||
|
||||
|
||||
+240
-74
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2015 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
|
||||
@@ -36,6 +36,7 @@
|
||||
# include "PEvent.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PPackage.h"
|
||||
# include "PScope.h"
|
||||
# include "PSpec.h"
|
||||
# include "netlist.h"
|
||||
# include "netenum.h"
|
||||
@@ -50,6 +51,9 @@
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
// Implemented in elab_scope.cc
|
||||
extern void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope);
|
||||
|
||||
void PGate::elaborate(Design*, NetScope*) const
|
||||
{
|
||||
cerr << "internal error: what kind of gate? " <<
|
||||
@@ -787,7 +791,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
|
||||
if (check_delay_count(des)) return;
|
||||
NetExpr* rise_time, *fall_time, *decay_time;
|
||||
eval_delays(des, scope, rise_time, fall_time, decay_time);
|
||||
eval_delays(des, scope, rise_time, fall_time, decay_time, true);
|
||||
|
||||
struct attrib_list_t*attrib_list;
|
||||
unsigned attrib_list_n = 0;
|
||||
@@ -1421,6 +1425,16 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||
<< prts[0]->name() << " is coerced to inout." << endl;
|
||||
}
|
||||
|
||||
if (!prts.empty() && (prts[0]->port_type() == NetNet::POUTPUT)
|
||||
&& (prts[0]->type() != NetNet::REG)
|
||||
&& prts[0]->pin(0).nexus()->has_floating_input()
|
||||
&& pins[idx]->is_collapsible_net(des, scope)) {
|
||||
prts[0]->port_type(NetNet::PINOUT);
|
||||
|
||||
cerr << pins[idx]->get_fileline() << ": warning: output port "
|
||||
<< prts[0]->name() << " is coerced to inout." << endl;
|
||||
}
|
||||
|
||||
// Elaborate the expression that connects to the
|
||||
// module[s] port. sig is the thing outside the module
|
||||
// that connects to the port.
|
||||
@@ -2000,7 +2014,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
||||
PDelays tmp_del;
|
||||
tmp_del.set_delays(overrides_, false);
|
||||
tmp_del.eval_delays(des, scope, rise_expr, fall_expr,
|
||||
decay_expr);
|
||||
decay_expr, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2240,7 +2254,8 @@ void PGModule::elaborate_scope(Design*des, NetScope*sc) const
|
||||
// Not a module or primitive that I know about yet, so try to
|
||||
// load a library module file (which parses some new Verilog
|
||||
// code) and try again.
|
||||
if (load_module(type_)) {
|
||||
int parser_errors = 0;
|
||||
if (load_module(type_, parser_errors)) {
|
||||
|
||||
// Try again to find the module type
|
||||
mod = pform_modules.find(type_);
|
||||
@@ -2255,6 +2270,10 @@ void PGModule::elaborate_scope(Design*des, NetScope*sc) const
|
||||
return;
|
||||
}
|
||||
|
||||
if (parser_errors) {
|
||||
cerr << get_fileline() << ": error: Failed to parse library file." << endl;
|
||||
des->errors += parser_errors + 1;
|
||||
}
|
||||
|
||||
// Not a module or primitive that I know about or can find by
|
||||
// any means, so give up.
|
||||
@@ -2325,7 +2344,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
||||
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
||||
ivl_type_t lv_net_type,
|
||||
ivl_variable_type_t lv_type,
|
||||
unsigned lv_width) const
|
||||
unsigned lv_width,
|
||||
bool force_unsigned) const
|
||||
{
|
||||
ivl_assert(*this, rval_);
|
||||
|
||||
@@ -2334,7 +2354,7 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
||||
// should look into fixing calls to this method to pass a
|
||||
// net_type instead of the separate lv_width/lv_type values.
|
||||
NetExpr*rv = elaborate_rval_expr(des, scope, lv_net_type, lv_type, lv_width,
|
||||
rval(), is_constant_);
|
||||
rval(), is_constant_, force_unsigned);
|
||||
|
||||
if (!is_constant_ || !rv) return rv;
|
||||
|
||||
@@ -2359,19 +2379,7 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
||||
{
|
||||
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
|
||||
@@ -2452,10 +2460,35 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
|
||||
NetAssign_*lv = elaborate_lval(des, scope);
|
||||
if (lv == 0) return 0;
|
||||
|
||||
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), count_lval_width(lv));
|
||||
// Compressed assignments should behave identically to the
|
||||
// equivalent uncompressed assignments. This means we need
|
||||
// to take the type of the LHS into account when determining
|
||||
// the type of the RHS expression.
|
||||
bool force_unsigned;
|
||||
switch (op_) {
|
||||
case 'l':
|
||||
case 'r':
|
||||
case 'R':
|
||||
// The right-hand operand of shift operations is
|
||||
// self-determined.
|
||||
force_unsigned = false;
|
||||
break;
|
||||
default:
|
||||
force_unsigned = !lv->get_signed();
|
||||
break;
|
||||
}
|
||||
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(),
|
||||
count_lval_width(lv), force_unsigned);
|
||||
if (rv == 0) return 0;
|
||||
|
||||
NetAssign*cur = new NetAssign(lv, op_, rv);
|
||||
// The ivl_target API doesn't support signalling the type
|
||||
// of a lval, so convert arithmetic shifts into logical
|
||||
// shifts now if the lval is unsigned.
|
||||
char op = op_;
|
||||
if ((op == 'R') && !lv->get_signed())
|
||||
op = 'r';
|
||||
|
||||
NetAssign*cur = new NetAssign(lv, op, rv);
|
||||
cur->set_line(*this);
|
||||
|
||||
return cur;
|
||||
@@ -2677,11 +2710,16 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||
return bl;
|
||||
}
|
||||
|
||||
if (lv->enumeration() &&
|
||||
! lv->enumeration()->matches(rv->enumeration())) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Enumeration type mismatch in assignment." << endl;
|
||||
des->errors += 1;
|
||||
if (lv->enumeration()) {
|
||||
if (! rv->enumeration()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
"This assignment requires an explicit cast." << endl;
|
||||
des->errors += 1;
|
||||
} else if (! lv->enumeration()->matches(rv->enumeration())) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
"Enumeration type mismatch in assignment." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
NetAssign*cur = new NetAssign(lv, rv);
|
||||
@@ -2868,14 +2906,27 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(nscope);
|
||||
|
||||
elaborate_behaviors_(des, nscope);
|
||||
}
|
||||
|
||||
NetBlock*cur = new NetBlock(type, nscope);
|
||||
|
||||
if (nscope) {
|
||||
// Handle any variable initialization statements in this scope.
|
||||
// For automatic scopes these statements need to be executed
|
||||
// each time the block is entered, so add them to the main
|
||||
// block. For static scopes, put them in a separate process
|
||||
// that will be executed at the start of simulation.
|
||||
if (nscope->is_auto()) {
|
||||
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
|
||||
NetProc*tmp = var_inits[idx]->elaborate(des, nscope);
|
||||
if (tmp) cur->append(tmp);
|
||||
}
|
||||
} else {
|
||||
elaborate_var_inits_(des, nscope);
|
||||
}
|
||||
}
|
||||
|
||||
if (nscope == 0)
|
||||
nscope = scope;
|
||||
|
||||
@@ -3778,7 +3829,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
|
||||
expression that can be a target to a procedural
|
||||
assignment, including a memory word. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
|
||||
|
||||
size_t parms_idx = use_this? idx-1 : idx;
|
||||
|
||||
NetNet*port = def->port(idx);
|
||||
|
||||
@@ -3794,12 +3847,12 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
|
||||
message. Note that the elaborate_lval method already
|
||||
printed a detailed message for the latter case. */
|
||||
NetAssign_*lv = 0;
|
||||
if (idx < parms_.size() && parms_[idx]) {
|
||||
lv = parms_[idx]->elaborate_lval(des, scope, false, false);
|
||||
if (parms_idx < parms_.size() && parms_[parms_idx]) {
|
||||
lv = parms_[parms_idx]->elaborate_lval(des, scope, false, false);
|
||||
if (lv == 0) {
|
||||
cerr << parms_[idx]->get_fileline() << ": error: "
|
||||
cerr << parms_[parms_idx]->get_fileline() << ": error: "
|
||||
<< "I give up on task port " << (idx+1)
|
||||
<< " expression: " << *parms_[idx] << endl;
|
||||
<< " expression: " << *parms_[parms_idx] << endl;
|
||||
}
|
||||
} else if (port->port_type() == NetNet::POUTPUT) {
|
||||
// Output ports were skipped earlier, so
|
||||
@@ -4039,9 +4092,18 @@ NetProc* PDisable::elaborate(Design*des, NetScope*scope) const
|
||||
*/
|
||||
NetProc* PDoWhile::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
|
||||
tmp->set_line(*this);
|
||||
NetDoWhile*loop = new NetDoWhile(tmp, statement_->elaborate(des, scope));
|
||||
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
|
||||
NetProc*sub;
|
||||
if (statement_)
|
||||
sub = statement_->elaborate(des, scope);
|
||||
else
|
||||
sub = new NetBlock(NetBlock::SEQU, 0);
|
||||
if (ce == 0 || sub == 0) {
|
||||
delete ce;
|
||||
delete sub;
|
||||
return 0;
|
||||
}
|
||||
NetDoWhile*loop = new NetDoWhile(ce, sub);
|
||||
loop->set_line(*this);
|
||||
return loop;
|
||||
}
|
||||
@@ -4572,7 +4634,11 @@ NetProc* PEventStatement::elaborate(Design*des, NetScope*scope) const
|
||||
*/
|
||||
NetProc* PForever::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetProc*stat = statement_->elaborate(des, scope);
|
||||
NetProc*stat;
|
||||
if (statement_)
|
||||
stat = statement_->elaborate(des, scope);
|
||||
else
|
||||
stat = new NetBlock(NetBlock::SEQU, 0);
|
||||
if (stat == 0) return 0;
|
||||
|
||||
NetForever*proc = new NetForever(stat);
|
||||
@@ -4733,14 +4799,18 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||
<< " packed dimensions." << endl;
|
||||
}
|
||||
|
||||
std::vector<netrange_t>dims = array_sig->unpacked_dims();
|
||||
if (array_sig->packed_dimensions() > 0) {
|
||||
dims.insert(dims.end(), array_sig->packed_dims().begin(), array_sig->packed_dims().end());
|
||||
}
|
||||
|
||||
// Classic arrays are processed this way.
|
||||
if (array_sig->data_type()==IVL_VT_BOOL)
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
return elaborate_static_array_(des, scope, dims);
|
||||
if (array_sig->data_type()==IVL_VT_LOGIC)
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
return elaborate_static_array_(des, scope, dims);
|
||||
if (array_sig->unpacked_dimensions() >= index_vars_.size())
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
|
||||
return elaborate_static_array_(des, scope, dims);
|
||||
|
||||
// At this point, we know that the array is dynamic so we
|
||||
// handle that slightly differently, using run-time tests.
|
||||
@@ -4778,7 +4848,11 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||
|
||||
/* Elaborate the statement that is contained in the foreach
|
||||
loop. */
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
NetProc*sub;
|
||||
if (statement_)
|
||||
sub = statement_->elaborate(des, scope);
|
||||
else
|
||||
sub = new NetBlock(NetBlock::SEQU, 0);
|
||||
|
||||
/* Make a step statement: idx += 1 */
|
||||
NetAssign_*idx_lv = new NetAssign_(idx_sig);
|
||||
@@ -4807,9 +4881,13 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
ivl_assert(*this, index_vars_.size() > 0);
|
||||
ivl_assert(*this, dims.size() == index_vars_.size());
|
||||
ivl_assert(*this, dims.size() >= index_vars_.size());
|
||||
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
NetProc*sub;
|
||||
if (statement_)
|
||||
sub = statement_->elaborate(des, scope);
|
||||
else
|
||||
sub = new NetBlock(NetBlock::SEQU, 0);
|
||||
NetForLoop*stmt = 0;
|
||||
|
||||
for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) {
|
||||
@@ -4903,7 +4981,11 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
||||
loop. If there is an error, this will return 0 and I should
|
||||
skip the append. No need to worry, the error has been
|
||||
reported so it's OK that the netlist is bogus. */
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
NetProc*sub;
|
||||
if (statement_)
|
||||
sub = statement_->elaborate(des, scope);
|
||||
else
|
||||
sub = new NetBlock(NetBlock::SEQU, 0);
|
||||
|
||||
/* Now elaborate the for_step statement. I really should do
|
||||
some error checking here to make sure the step statement
|
||||
@@ -4972,7 +5054,6 @@ void PFunction::elaborate(Design*des, NetScope*scope) const
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(def);
|
||||
|
||||
ivl_assert(*this, statement_);
|
||||
@@ -4985,6 +5066,31 @@ void PFunction::elaborate(Design*des, NetScope*scope) const
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle any variable initialization statements in this scope.
|
||||
// For automatic functions, these statements need to be executed
|
||||
// each time the function is called, so insert them at the start
|
||||
// of the elaborated definition. For static functions, put them
|
||||
// in a separate process that will be executed before the start
|
||||
// of simulation.
|
||||
if (is_auto_) {
|
||||
// Get the NetBlock of the statement. If it is not a
|
||||
// NetBlock then create one to wrap the initialization
|
||||
// statements and the original statement.
|
||||
NetBlock*blk = dynamic_cast<NetBlock*> (st);
|
||||
if ((blk == 0) && (var_inits.size() > 0)) {
|
||||
blk = new NetBlock(NetBlock::SEQU, scope);
|
||||
blk->set_line(*this);
|
||||
blk->append(st);
|
||||
st = blk;
|
||||
}
|
||||
for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) {
|
||||
NetProc*tmp = var_inits[idx-1]->elaborate(des, scope);
|
||||
if (tmp) blk->prepend(tmp);
|
||||
}
|
||||
} else {
|
||||
elaborate_var_inits_(des, scope);
|
||||
}
|
||||
|
||||
def->set_proc(st);
|
||||
}
|
||||
|
||||
@@ -5025,7 +5131,11 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
|
||||
if (expr->expr_type() == IVL_VT_REAL)
|
||||
expr = cast_to_int4(expr, 64);
|
||||
|
||||
NetProc*stat = statement_->elaborate(des, scope);
|
||||
NetProc*stat;
|
||||
if (statement_)
|
||||
stat = statement_->elaborate(des, scope);
|
||||
else
|
||||
stat = new NetBlock(NetBlock::SEQU, 0);
|
||||
if (stat == 0) return 0;
|
||||
|
||||
// If the expression is a constant, handle certain special
|
||||
@@ -5143,11 +5253,6 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const
|
||||
|
||||
void PTask::elaborate(Design*des, NetScope*task) const
|
||||
{
|
||||
// Elaborate any processes that are part of this scope that
|
||||
// aren't the definition itself. This can happen, for example,
|
||||
// with variable initialization statements in this scope.
|
||||
elaborate_behaviors_(des, task);
|
||||
|
||||
NetTaskDef*def = task->task_def();
|
||||
assert(def);
|
||||
|
||||
@@ -5166,6 +5271,31 @@ void PTask::elaborate(Design*des, NetScope*task) const
|
||||
}
|
||||
}
|
||||
|
||||
// Handle any variable initialization statements in this scope.
|
||||
// For automatic tasks , these statements need to be executed
|
||||
// each time the task is called, so insert them at the start
|
||||
// of the elaborated definition. For static tasks, put them
|
||||
// in a separate process that will be executed before the start
|
||||
// of simulation.
|
||||
if (is_auto_) {
|
||||
// Get the NetBlock of the statement. If it is not a
|
||||
// NetBlock then create one to wrap the initialization
|
||||
// statements and the original statement.
|
||||
NetBlock*blk = dynamic_cast<NetBlock*> (st);
|
||||
if ((blk == 0) && (var_inits.size() > 0)) {
|
||||
blk = new NetBlock(NetBlock::SEQU, task);
|
||||
blk->set_line(*this);
|
||||
blk->append(st);
|
||||
st = blk;
|
||||
}
|
||||
for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) {
|
||||
NetProc*tmp = var_inits[idx-1]->elaborate(des, task);
|
||||
if (tmp) blk->prepend(tmp);
|
||||
}
|
||||
} else {
|
||||
elaborate_var_inits_(des, task);
|
||||
}
|
||||
|
||||
def->set_proc(st);
|
||||
}
|
||||
|
||||
@@ -5205,7 +5335,11 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
|
||||
NetProc* PWhile::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
NetProc*sub;
|
||||
if (statement_)
|
||||
sub = statement_->elaborate(des, scope);
|
||||
else
|
||||
sub = new NetBlock(NetBlock::SEQU, 0);
|
||||
if (ce == 0 || sub == 0) {
|
||||
delete ce;
|
||||
delete sub;
|
||||
@@ -5297,19 +5431,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
ndelays = delays.size();
|
||||
if (ndelays > 12) ndelays = 12;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Elaborate the delay values themselves. Remember to scale
|
||||
them for the timescale/precision of the scope. */
|
||||
@@ -5618,6 +5740,10 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
||||
(*gt)->elaborate(des, scope);
|
||||
}
|
||||
|
||||
// Elaborate the variable initialization statements, making a
|
||||
// single initial process out of them.
|
||||
result_flag &= elaborate_var_inits_(des, scope);
|
||||
|
||||
// Elaborate the behaviors, making processes out of them. This
|
||||
// involves scanning the PProcess* list, creating a NetProcTop
|
||||
// for each process.
|
||||
@@ -5695,6 +5821,9 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
|
||||
"generate " << scheme_type
|
||||
<< " elaborating in scope " << scope_path(container)
|
||||
<< "." << endl;
|
||||
cerr << get_fileline() << ": PGenerate::elaborate: "
|
||||
"generate scope_name=" << scope_name
|
||||
<< ", id_number=" << id_number << endl;
|
||||
}
|
||||
|
||||
// Handle the special case that this is a CASE scheme. In this
|
||||
@@ -5729,6 +5858,7 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
|
||||
// scheme defined in the Verilog-2005 standard.
|
||||
const char*name = scope_name.str();
|
||||
if (name[0] == '$') {
|
||||
|
||||
if (!scope->auto_name("genblk", '0', name + 4)) {
|
||||
cerr << get_fileline() << ": warning: Couldn't build"
|
||||
<< " unique name for unnamed generate block"
|
||||
@@ -5804,6 +5934,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
|
||||
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; ++ cur )
|
||||
(*cur)->elaborate(des, scope);
|
||||
|
||||
elaborate_var_inits_(des, scope);
|
||||
|
||||
typedef list<PProcess*>::const_iterator proc_it_t;
|
||||
for (proc_it_t cur = behaviors.begin(); cur != behaviors.end(); ++ cur )
|
||||
(*cur)->elaborate(des, scope);
|
||||
@@ -5839,6 +5971,44 @@ bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const
|
||||
return result_flag;
|
||||
}
|
||||
|
||||
bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (var_inits.size() == 0)
|
||||
return true;
|
||||
|
||||
NetProc*proc = 0;
|
||||
if (var_inits.size() == 1) {
|
||||
proc = var_inits[0]->elaborate(des, scope);
|
||||
} else {
|
||||
NetBlock*blk = new NetBlock(NetBlock::SEQU, 0);
|
||||
bool flag = true;
|
||||
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
|
||||
NetProc*tmp = var_inits[idx]->elaborate(des, scope);
|
||||
if (tmp)
|
||||
blk->append(tmp);
|
||||
else
|
||||
flag = false;
|
||||
}
|
||||
if (flag) proc = blk;
|
||||
}
|
||||
if (proc == 0)
|
||||
return false;
|
||||
|
||||
NetProcTop*top = new NetProcTop(scope, IVL_PR_INITIAL, proc);
|
||||
if (const LineInfo*li = dynamic_cast<const LineInfo*>(this)) {
|
||||
top->set_line(*li);
|
||||
}
|
||||
if (gn_system_verilog()) {
|
||||
top->attribute(perm_string::literal("_ivl_schedule_init"),
|
||||
verinum(1));
|
||||
}
|
||||
des->add_process(top);
|
||||
|
||||
scope->set_var_init(proc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class elaborate_package_t : public elaborator_work_item_t {
|
||||
public:
|
||||
elaborate_package_t(Design*d, NetScope*scope, PPackage*p)
|
||||
@@ -6072,6 +6242,7 @@ Design* elaborate(list<perm_string>roots)
|
||||
ivl_assert(*pac->second, pac->first == pac->second->pscope_name());
|
||||
NetScope*scope = des->make_package_scope(pac->first);
|
||||
scope->set_line(pac->second);
|
||||
set_scope_timescale(des, scope, pac->second);
|
||||
|
||||
elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second);
|
||||
des->elaboration_work_list.push_back(es);
|
||||
@@ -6108,11 +6279,7 @@ Design* elaborate(list<perm_string>roots)
|
||||
// Collect some basic properties of this scope from the
|
||||
// Module definition.
|
||||
scope->set_line(rmod);
|
||||
scope->time_unit(rmod->time_unit);
|
||||
scope->time_precision(rmod->time_precision);
|
||||
scope->time_from_timescale(rmod->time_from_timescale);
|
||||
des->set_precision(rmod->time_precision);
|
||||
|
||||
set_scope_timescale(des, scope, rmod);
|
||||
|
||||
// Save this scope, along with its definition, in the
|
||||
// "root_elems" list for later passes.
|
||||
@@ -6244,8 +6411,7 @@ Design* elaborate(list<perm_string>roots)
|
||||
if (netnet != 0) {
|
||||
// Elaboration may actually fail with
|
||||
// erroneous input source
|
||||
ivl_assert(*mport[pin], netnet->pin_count()==1);
|
||||
prt_vector_width += netnet->vector_width();
|
||||
prt_vector_width += netnet->vector_width() * netnet->pin_count();
|
||||
ptype = PortType::merged(netnet->port_type(), ptype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +507,6 @@ int Design::emit(struct target_t*tgt) const
|
||||
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
|
||||
@@ -521,7 +520,6 @@ int Design::emit(struct target_t*tgt) const
|
||||
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
|
||||
@@ -548,6 +546,12 @@ int Design::emit(struct target_t*tgt) const
|
||||
|
||||
// emit task and function definitions
|
||||
bool tasks_rc = true;
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator scope = root_tasks_.begin()
|
||||
; scope != root_tasks_.end() ; ++ scope)
|
||||
tasks_rc &= scope->first->emit_defs(tgt);
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++cur)
|
||||
tasks_rc &= cur->second->emit_defs(tgt);
|
||||
for (map<perm_string,NetScope*>::const_iterator scope = packages_.begin()
|
||||
; scope != packages_.end() ; ++ scope )
|
||||
tasks_rc &= scope->second->emit_defs(tgt);
|
||||
|
||||
+13
-3
@@ -697,7 +697,9 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr
|
||||
// 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);
|
||||
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;
|
||||
@@ -708,12 +710,15 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr
|
||||
// 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);
|
||||
if (is_signed)
|
||||
pad = lv.get(lv.len()-1);
|
||||
|
||||
for (unsigned idx = cnt ; idx < rv.len() ; idx += 1) {
|
||||
if (rv.get(idx) != pad)
|
||||
if (rv.get(idx) != pad) {
|
||||
res = verinum::V0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ne_flag) {
|
||||
@@ -1097,6 +1102,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 +1554,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 +1564,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 +1574,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
|
||||
|
||||
case 'X':
|
||||
invert = true;
|
||||
// fallthrough
|
||||
case '^': {
|
||||
/* Reduction XOR. */
|
||||
unsigned ones = 0, unknown = 0;
|
||||
@@ -1617,6 +1626,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);
|
||||
|
||||
+5
-2
@@ -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
|
||||
@@ -335,6 +335,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 +354,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;
|
||||
@@ -386,7 +388,8 @@ NetNet* NetEBPow::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||
powr->set_line(*this);
|
||||
des->add_node(powr);
|
||||
|
||||
powr->set_signed( has_sign() );
|
||||
// The lpm_pwr object only cares about the signedness of the exponent.
|
||||
powr->set_signed( right_->has_sign() );
|
||||
|
||||
connect(powr->pin_DataA(), lsig->pin(0));
|
||||
connect(powr->pin_DataB(), rsig->pin(0));
|
||||
|
||||
+7
-2
@@ -1,4 +1,4 @@
|
||||
.TH iverilog-vpi 1 "May 10th, 2015" "" "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
|
||||
|
||||
@@ -26,6 +26,11 @@ becomes \fIfoo.vpi\fP.
|
||||
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 searched
|
||||
@@ -115,7 +120,7 @@ iverilog(1), vvp(1),
|
||||
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 2002\-2015 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
|
||||
|
||||
+5
-1
@@ -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"
|
||||
;;
|
||||
|
||||
@@ -148,4 +152,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
|
||||
|
||||
+4
-2
@@ -1245,8 +1245,10 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net);
|
||||
* width of a general power is the XXXX of the widths of the
|
||||
* inputs.
|
||||
*
|
||||
* Power may be signed. If so, the output should be sign extended
|
||||
* to fill in its result.
|
||||
* Power may be signed. This indicates the type of the exponent. The
|
||||
* base will always be treated as unsigned. The compiler must ensure
|
||||
* the width of the base is equal to the width of the output to
|
||||
* obtain the correct result when the base is really a signed value.
|
||||
*
|
||||
* - Part Select (IVL_LPM_PART_VP and IVL_LPM_PART_PV)
|
||||
* There are two part select devices, one that extracts a part from a
|
||||
|
||||
+44
-40
@@ -1,7 +1,7 @@
|
||||
%option prefix="yy"
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1999-2015 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2016 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -148,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;
|
||||
@@ -242,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.
|
||||
@@ -514,29 +528,19 @@ 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);
|
||||
}
|
||||
|
||||
`` { if (istack->file != NULL) ECHO; }
|
||||
|
||||
<MA_START>\( { BEGIN(MA_ADD); macro_start_args(); }
|
||||
|
||||
<MA_START>{W} {}
|
||||
@@ -2096,7 +2100,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
-1
@@ -1,5 +1,5 @@
|
||||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1999-2011 Stephen Williams ([email protected])";
|
||||
"Copyright (c) 1999-2011,2015 Stephen Williams ([email protected])";
|
||||
/*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2015 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -432,18 +432,28 @@ TU [munpf]
|
||||
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; }
|
||||
@@ -847,7 +857,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 {
|
||||
@@ -1596,7 +1606,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
|
||||
|
||||
+14
-10
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
+6
-4
@@ -54,11 +54,13 @@ extern FILE *depend_file;
|
||||
* Use the type name as a key, and search the module library for a
|
||||
* file name that has that key.
|
||||
*/
|
||||
bool load_module(const char*type)
|
||||
bool load_module(const char*type, int&parser_errors)
|
||||
{
|
||||
char path[4096];
|
||||
char*ltype = strdup(type);
|
||||
|
||||
parser_errors = 0;
|
||||
|
||||
for (char*tmp = ltype ; *tmp ; tmp += 1)
|
||||
*tmp = tolower(*tmp);
|
||||
|
||||
@@ -98,7 +100,7 @@ bool load_module(const char*type)
|
||||
if (verbose_flag)
|
||||
cerr << "...parsing output from preprocessor..." << endl << flush;
|
||||
|
||||
pform_parse(path, file);
|
||||
parser_errors = pform_parse(path, file);
|
||||
pclose(file);
|
||||
free(cmdline);
|
||||
|
||||
@@ -109,14 +111,14 @@ bool load_module(const char*type)
|
||||
|
||||
FILE*file = fopen(path, "r");
|
||||
assert(file);
|
||||
pform_parse(path, file);
|
||||
parser_errors = pform_parse(path, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
if (verbose_flag)
|
||||
cerr << "... Load module complete." << endl << flush;
|
||||
|
||||
return true;
|
||||
return parser_errors == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1998-2014 Stephen Williams ([email protected])";
|
||||
"Copyright (c) 1998-2017 Stephen Williams ([email protected])";
|
||||
|
||||
/*
|
||||
* 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 = false;
|
||||
bool gn_verilog_ams_flag = false;
|
||||
|
||||
/*
|
||||
@@ -153,6 +154,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;
|
||||
@@ -343,6 +345,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 {
|
||||
}
|
||||
}
|
||||
@@ -678,6 +686,9 @@ static void read_iconfig_file(const char*ipath)
|
||||
case 'i':
|
||||
warn_implicit = true;
|
||||
break;
|
||||
case 'd':
|
||||
warn_implicit_dimensions = true;
|
||||
break;
|
||||
case 'l':
|
||||
warn_inf_loop = true;
|
||||
break;
|
||||
@@ -922,16 +933,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;
|
||||
}
|
||||
@@ -1026,9 +1043,8 @@ int main(int argc, char*argv[])
|
||||
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);
|
||||
for (size_t idx = 0 ; idx < pform_classes.size() ; idx += 1) {
|
||||
pform_dump(out, pform_classes[idx]);
|
||||
}
|
||||
out << "PFORM DUMP PACKAGES:" << endl;
|
||||
for (map<perm_string,PPackage*>::iterator pac = pform_packages.begin()
|
||||
@@ -1107,7 +1123,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ NetAssign_::NetAssign_(NetAssign_*n)
|
||||
: nest_(n), sig_(0), word_(0), base_(0), sel_type_(IVL_SEL_OTHER)
|
||||
{
|
||||
more = 0;
|
||||
signed_ = false;
|
||||
turn_sig_to_wire_on_release_ = false;
|
||||
}
|
||||
|
||||
NetAssign_::NetAssign_(NetNet*s)
|
||||
@@ -51,6 +53,7 @@ NetAssign_::NetAssign_(NetNet*s)
|
||||
lwid_ = sig_->vector_width();
|
||||
sig_->incr_lref();
|
||||
more = 0;
|
||||
signed_ = false;
|
||||
turn_sig_to_wire_on_release_ = false;
|
||||
}
|
||||
|
||||
|
||||
+154
-6
@@ -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())) {
|
||||
|
||||
|
||||
+14
@@ -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()) {
|
||||
|
||||
+21
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-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
|
||||
@@ -404,6 +404,17 @@ NexusSet* NetDoWhile::nex_input(bool rem_out)
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEvWait::nex_input(bool rem_out)
|
||||
{
|
||||
NexusSet*result;
|
||||
if (statement_)
|
||||
result = statement_->nex_input(rem_out);
|
||||
else
|
||||
result = new NexusSet;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetForce::nex_input(bool)
|
||||
{
|
||||
cerr << get_fileline() << ": internal warning: NetForce::nex_input()"
|
||||
@@ -427,6 +438,15 @@ NexusSet* NetForLoop::nex_input(bool rem_out)
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
if (gn_shared_loop_index_flag) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -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)
|
||||
|
||||
+22
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -139,6 +139,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;
|
||||
@@ -264,19 +265,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 +287,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 +300,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)
|
||||
|
||||
+3
-2
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
+33
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -557,7 +557,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();
|
||||
}
|
||||
}
|
||||
@@ -2724,12 +2724,27 @@ DelayType NetProc::delay_type() const
|
||||
|
||||
DelayType NetBlock::delay_type() 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();
|
||||
if (dt < result) result = dt;
|
||||
if (dt == NO_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();
|
||||
if (dt > result) result = dt;
|
||||
if (dt == DEFINITE_DELAY) break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -2743,10 +2758,11 @@ 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() : 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,6 +2785,7 @@ DelayType NetCondit::delay_type() const
|
||||
*/
|
||||
DelayType NetDoWhile::delay_type() const
|
||||
{
|
||||
ivl_assert(*this, proc_);
|
||||
return proc_->delay_type();
|
||||
}
|
||||
|
||||
@@ -2779,11 +2796,13 @@ DelayType NetEvWait::delay_type() const
|
||||
|
||||
DelayType NetForever::delay_type() const
|
||||
{
|
||||
ivl_assert(*this, statement_);
|
||||
return statement_->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetForLoop::delay_type() const
|
||||
{
|
||||
ivl_assert(*this, statement_);
|
||||
return get_loop_delay_type(condition_, statement_);
|
||||
}
|
||||
|
||||
@@ -2796,9 +2815,10 @@ DelayType NetPDelay::delay_type() const
|
||||
return DEFINITE_DELAY;
|
||||
} else {
|
||||
if (statement_) {
|
||||
return statement_->delay_type();
|
||||
return combine_delays(ZERO_DELAY,
|
||||
statement_->delay_type());
|
||||
} else {
|
||||
return NO_DELAY;
|
||||
return ZERO_DELAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2806,6 +2826,7 @@ DelayType NetPDelay::delay_type() const
|
||||
|
||||
DelayType NetRepeat::delay_type() const
|
||||
{
|
||||
ivl_assert(*this, statement_);
|
||||
return get_loop_delay_type(expr_, statement_);
|
||||
}
|
||||
|
||||
@@ -2821,5 +2842,6 @@ DelayType NetUTask::delay_type() const
|
||||
|
||||
DelayType NetWhile::delay_type() const
|
||||
{
|
||||
ivl_assert(*this, proc_);
|
||||
return get_loop_delay_type(cond_, proc_);
|
||||
}
|
||||
|
||||
@@ -388,6 +388,10 @@ class Nexus {
|
||||
is a variable, but also if this is a net with a force. */
|
||||
bool assign_lval() const;
|
||||
|
||||
/* This method returns true if there are any inputs
|
||||
attached to this nexus but no drivers. */
|
||||
bool has_floating_input() const;
|
||||
|
||||
/* This method returns true if there are any drivers
|
||||
(including variables) attached to this nexus. */
|
||||
bool drivers_present() const;
|
||||
@@ -713,7 +717,7 @@ class NetNet : public NetObj, public PortType {
|
||||
/* This method returns a reference to the packed dimensions
|
||||
for the vector. These are arranged as a list where the
|
||||
first range in the list (front) is the left-most range in
|
||||
the verilog declaration. These packed dims are compressed
|
||||
the Verilog declaration. These packed dims are compressed
|
||||
to represent the dimensions of all the subtypes. */
|
||||
const std::vector<netrange_t>& packed_dims() const { return slice_dims_; }
|
||||
|
||||
@@ -1020,6 +1024,13 @@ class NetScope : public Definitions, public Attrib {
|
||||
TYPE type() const;
|
||||
void print_type(ostream&) const;
|
||||
|
||||
// This provides a link to the variable initialisation process
|
||||
// for use when evaluating a constant function. Note this is
|
||||
// only used for static functions - the variable initialization
|
||||
// for automatic functions is included in the function definition.
|
||||
void set_var_init(const NetProc*proc) { var_init_ = proc; }
|
||||
const NetProc* var_init() const { return var_init_; }
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_class_def(netclass_t*);
|
||||
@@ -1250,6 +1261,8 @@ class NetScope : public Definitions, public Attrib {
|
||||
|
||||
vector<PortInfo> ports_;
|
||||
|
||||
const NetProc*var_init_;
|
||||
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
@@ -2732,6 +2745,12 @@ class NetAssign_ {
|
||||
void set_property(const perm_string&name);
|
||||
inline perm_string get_property(void) const { return member_; }
|
||||
|
||||
// Determine if the assigned object is signed or unsigned.
|
||||
// This is used when determining the expression type for
|
||||
// a compressed assignment statement.
|
||||
bool get_signed() const { return signed_; }
|
||||
void set_signed(bool flag) { signed_ = flag; }
|
||||
|
||||
// Get the width of the r-value that this node expects. This
|
||||
// method accounts for the presence of the mux, so it is not
|
||||
// necessarily the same as the pin_count().
|
||||
@@ -2782,6 +2801,7 @@ class NetAssign_ {
|
||||
// member/property if signal is a class.
|
||||
perm_string member_;
|
||||
|
||||
bool signed_;
|
||||
bool turn_sig_to_wire_on_release_;
|
||||
// indexed part select base
|
||||
NetExpr*base_;
|
||||
@@ -2849,6 +2869,8 @@ class NetAssign : public NetAssignBase {
|
||||
map<perm_string,LocalVar>&ctx) const;
|
||||
|
||||
private:
|
||||
void eval_func_lval_op_real_(const LineInfo&loc, verireal&lv, verireal&rv) const;
|
||||
void eval_func_lval_op_(const LineInfo&loc, verinum&lv, verinum&rv) const;
|
||||
bool eval_func_lval_(const LineInfo&loc, map<perm_string,LocalVar>&ctx,
|
||||
const NetAssign_*lval, NetExpr*rval_result) const;
|
||||
|
||||
@@ -2895,6 +2917,7 @@ class NetBlock : public NetProc {
|
||||
NetScope* subscope() const { return subscope_; }
|
||||
|
||||
void append(NetProc*);
|
||||
void prepend(NetProc*);
|
||||
|
||||
const NetProc*proc_first() const;
|
||||
const NetProc*proc_next(const NetProc*cur) const;
|
||||
@@ -3323,6 +3346,7 @@ class NetEvWait : public NetProc {
|
||||
// process? This method checks.
|
||||
virtual bool is_synchronous();
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual void nex_output(NexusSet&out);
|
||||
|
||||
virtual bool synth_async(Design*des, NetScope*scope,
|
||||
|
||||
+109
-23
@@ -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;
|
||||
}
|
||||
|
||||
@@ -802,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)
|
||||
@@ -824,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;
|
||||
@@ -910,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,
|
||||
@@ -926,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,
|
||||
@@ -1392,8 +1443,8 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
|
||||
{
|
||||
list<index_component_t>::const_iterator icur = indices.begin();
|
||||
for (size_t idx = 0 ; (idx+1) < indices.size() ; idx += 1, ++icur) {
|
||||
assert(icur != indices.end());
|
||||
assert(icur->sel == index_component_t::SEL_BIT);
|
||||
ivl_assert(*(icur->msb), icur != indices.end());
|
||||
ivl_assert(*(icur->msb), icur->sel == index_component_t::SEL_BIT);
|
||||
NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, true);
|
||||
|
||||
long tmp;
|
||||
@@ -1404,7 +1455,7 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
|
||||
return false;
|
||||
}
|
||||
|
||||
prefix_indices .push_back(tmp);
|
||||
prefix_indices.push_back(tmp);
|
||||
delete texpr;
|
||||
}
|
||||
|
||||
@@ -1614,3 +1665,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -258,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,
|
||||
@@ -297,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,
|
||||
@@ -356,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.
|
||||
@@ -387,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 */
|
||||
|
||||
+2
-3
@@ -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
|
||||
@@ -147,13 +147,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
|
||||
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.
|
||||
|
||||
+32
-11
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
@@ -45,7 +45,7 @@ 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<PClass*> pform_classes;
|
||||
extern std::map<perm_string,PPackage*> pform_packages;
|
||||
|
||||
extern void pform_dump(std::ostream&out, const PClass*pac);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -40,6 +40,7 @@
|
||||
# include <sstream>
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <cctype>
|
||||
|
||||
# include "ivl_assert.h"
|
||||
# include "ivl_alloc.h"
|
||||
@@ -70,7 +71,7 @@ set<enum_type_t*>pform_enum_sets;
|
||||
/*
|
||||
* Class definitions in the $root scope go here.
|
||||
*/
|
||||
map<perm_string,PClass*> pform_classes;
|
||||
vector<PClass*> pform_classes;
|
||||
|
||||
/*
|
||||
* Task and function definitions in the $root scope go here.
|
||||
@@ -86,6 +87,42 @@ std::string vlltype::get_fileline() const
|
||||
|
||||
}
|
||||
|
||||
static bool is_hex_digit_str(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
if (!isxdigit(*str)) return false;
|
||||
str++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_dec_digit_str(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
if (!isdigit(*str)) return false;
|
||||
str++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_oct_digit_str(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
if (*str < '0' || *str > '7') return false;
|
||||
str++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_bin_digit_str(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
if (*str != '0' && *str != '1') return false;
|
||||
str++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse configuration file with format <key>=<value>, where key
|
||||
* is the hierarchical name of a valid parameter name, and value
|
||||
@@ -152,90 +189,137 @@ void parm_to_defparam_list(const string¶m)
|
||||
ptr = strchr(nkey, '.');
|
||||
}
|
||||
name.push_back(name_component_t(lex_strings.make(nkey)));
|
||||
free(key);
|
||||
|
||||
// Resolve value to PExpr class. Should support all kind of constant
|
||||
// format including based number, dec number, real number and string.
|
||||
if (*value == '"') { // string type
|
||||
char *buf = strdup (value);
|
||||
char *buf_ptr = buf+1;
|
||||
// Parse until another '"' or '\0'
|
||||
while (*buf_ptr != '"' && *buf_ptr != '\0') {
|
||||
buf_ptr++;
|
||||
// Check for escape, especially '\"', which does not mean the
|
||||
// end of string.
|
||||
if (*buf_ptr == '\\' && *(buf_ptr+1) != '\0')
|
||||
buf_ptr += 2;
|
||||
}
|
||||
if (*buf_ptr == '\0') // String end without '"'
|
||||
cerr << "<command line>: error: missing close quote of string for defparam: " << name << endl;
|
||||
else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape
|
||||
cerr << buf_ptr << endl;
|
||||
cerr << "<command line>: error: \'\"\' appears within string value for defparam: " << name
|
||||
<< ". Ignore characters after \'\"\'" << endl;
|
||||
}
|
||||
|
||||
*buf_ptr = '\0';
|
||||
buf_ptr = buf+1;
|
||||
// Remember to use 'new' to allocate string for PEString
|
||||
// because 'delete' is used by its destructor.
|
||||
char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr);
|
||||
PExpr* ndec = new PEString(nchar);
|
||||
// Is it a string?
|
||||
if (*value == '"') {
|
||||
char *buf = strdup (value);
|
||||
char *buf_ptr = buf+1;
|
||||
// Parse until another '"' or '\0'
|
||||
while (*buf_ptr != '"' && *buf_ptr != '\0') {
|
||||
buf_ptr++;
|
||||
// Check for escape, especially '\"', which does not mean the
|
||||
// end of string.
|
||||
if (*buf_ptr == '\\' && *(buf_ptr+1) != '\0')
|
||||
buf_ptr += 2;
|
||||
}
|
||||
if (*buf_ptr == '\0') // String end without '"'
|
||||
cerr << "<command line>: error: missing close quote of string for defparam: " << name << endl;
|
||||
else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape
|
||||
cerr << buf_ptr << endl;
|
||||
cerr << "<command line>: error: \'\"\' appears within string value for defparam: " << name
|
||||
<< ". Ignore characters after \'\"\'" << endl;
|
||||
}
|
||||
|
||||
*buf_ptr = '\0';
|
||||
buf_ptr = buf+1;
|
||||
// Remember to use 'new' to allocate string for PEString
|
||||
// because 'delete' is used by its destructor.
|
||||
char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr);
|
||||
PExpr* ndec = new PEString(nchar);
|
||||
Module::user_defparms.push_back( make_pair(name, ndec) );
|
||||
free(buf);
|
||||
free(buf);
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
else { // number type
|
||||
char *num = strchr(value, '\'');
|
||||
if (num != 0) {
|
||||
verinum *val;
|
||||
// BASED_NUMBER, something like - scope.parameter='b11
|
||||
// make sure to check 'h' first because 'b'&'d' may be included
|
||||
// in hex format
|
||||
if (strchr(num, 'h') || strchr(num, 'H'))
|
||||
val = make_unsized_hex(num);
|
||||
else if (strchr(num, 'd') || strchr(num, 'D'))
|
||||
if (strchr(num, 'x') || strchr(num, 'X') || strchr(num, 'z') || strchr(num, 'Z'))
|
||||
val = make_undef_highz_dec(num);
|
||||
else
|
||||
val = make_unsized_dec(num);
|
||||
else if (strchr(num, 'b') || strchr(num, 'B')) {
|
||||
val = make_unsized_binary(num);
|
||||
}
|
||||
else if (strchr(num, 'o') || strchr(num, 'O'))
|
||||
val = make_unsized_octal(num);
|
||||
else {
|
||||
cerr << "<command line>: error: value specify error for defparam: " << name << endl;
|
||||
free(key);
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// BASED_NUMBER with size, something like - scope.parameter=2'b11
|
||||
if (num != value) {
|
||||
*num = 0;
|
||||
verinum *siz = make_unsized_dec(value);
|
||||
val = pform_verinum_with_size(siz, val, "<command line>", 0);
|
||||
}
|
||||
|
||||
PExpr* ndec = new PENumber(val);
|
||||
Module::user_defparms.push_back( make_pair(name, ndec) );
|
||||
|
||||
}
|
||||
else {
|
||||
// REALTIME, something like - scope.parameter=1.22 or scope.parameter=1e2
|
||||
if (strchr(value, '.') || strchr(value, 'e') || strchr(value, 'E')) {
|
||||
verireal *val = new verireal(value);
|
||||
PExpr* nreal = new PEFNumber(val);
|
||||
Module::user_defparms.push_back( make_pair(name, nreal) );
|
||||
}
|
||||
else {
|
||||
// DEC_NUMBER, something like - scope.parameter=3
|
||||
verinum *val = make_unsized_dec(value);
|
||||
PExpr* ndec = new PENumber(val);
|
||||
Module::user_defparms.push_back( make_pair(name, ndec) );
|
||||
}
|
||||
}
|
||||
// Is it a based number?
|
||||
char *num = strchr(value, '\'');
|
||||
if (num != 0) {
|
||||
verinum *val;
|
||||
const char *base = num + 1;
|
||||
if (*base == 's' || *base == 'S')
|
||||
base++;
|
||||
switch (*base) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
if (is_hex_digit_str(base+1)) {
|
||||
val = make_unsized_hex(num);
|
||||
} else {
|
||||
cerr << "<command line>: error: invalid digit in hex value specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (is_dec_digit_str(base+1)) {
|
||||
val = make_unsized_dec(num);
|
||||
} else {
|
||||
cerr << "<command line>: error: invalid digit in decimal value specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
case 'O':
|
||||
if (is_oct_digit_str(base+1)) {
|
||||
val = make_unsized_octal(num);
|
||||
} else {
|
||||
cerr << "<command line>: error: invalid digit in octal value specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
if (is_bin_digit_str(base+1)) {
|
||||
val = make_unsized_binary(num);
|
||||
} else {
|
||||
cerr << "<command line>: error: invalid digit in binary value specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "<command line>: error: invalid numeric base specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
if (num != value) { // based number with size
|
||||
*num = 0;
|
||||
if (is_dec_digit_str(value)) {
|
||||
verinum *siz = make_unsized_dec(value);
|
||||
val = pform_verinum_with_size(siz, val, "<command line>", 0);
|
||||
} else {
|
||||
cerr << "<command line>: error: invalid size for value specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PExpr* ndec = new PENumber(val);
|
||||
Module::user_defparms.push_back( make_pair(name, ndec) );
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
free(key);
|
||||
|
||||
// Is it a decimal number?
|
||||
num = (value[0] == '-') ? value + 1 : value;
|
||||
if (is_dec_digit_str(num)) {
|
||||
verinum *val = make_unsized_dec(num);
|
||||
if (value[0] == '-') *val = -(*val);
|
||||
PExpr* ndec = new PENumber(val);
|
||||
Module::user_defparms.push_back( make_pair(name, ndec) );
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// Is it a real number?
|
||||
char *end = 0;
|
||||
double rval = strtod(value, &end);
|
||||
if (end != value && *end == 0) {
|
||||
verireal *val = new verireal(rval);
|
||||
PExpr* nreal = new PEFNumber(val);
|
||||
Module::user_defparms.push_back( make_pair(name, nreal) );
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// None of the above.
|
||||
cerr << "<command line>: error: invalid value specified for defparam: " << name << endl;
|
||||
free(value);
|
||||
}
|
||||
|
||||
@@ -312,12 +396,29 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
|
||||
*/
|
||||
static LexicalScope* lexical_scope = 0;
|
||||
|
||||
LexicalScope* pform_peek_scope(void)
|
||||
{
|
||||
assert(lexical_scope);
|
||||
return lexical_scope;
|
||||
}
|
||||
|
||||
void pform_pop_scope()
|
||||
{
|
||||
assert(lexical_scope);
|
||||
lexical_scope = lexical_scope->parent_scope();
|
||||
}
|
||||
|
||||
static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
if (lifetime != LexicalScope::INHERITED)
|
||||
return lifetime;
|
||||
|
||||
if (lexical_scope != 0)
|
||||
return lexical_scope->default_lifetime;
|
||||
|
||||
return LexicalScope::STATIC;
|
||||
}
|
||||
|
||||
static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
|
||||
{
|
||||
PScopeExtra*scopex = dynamic_cast<PScopeExtra*> (scope);
|
||||
@@ -328,17 +429,37 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
|
||||
return scopex;
|
||||
}
|
||||
|
||||
LexicalScope* pform_peek_scope(void)
|
||||
/*
|
||||
* Set the local time unit/precision to the global value.
|
||||
*/
|
||||
static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc)
|
||||
{
|
||||
assert(lexical_scope);
|
||||
return lexical_scope;
|
||||
scope->time_unit = pform_time_unit;
|
||||
scope->time_precision = pform_time_prec;
|
||||
/* If we have a timescale file then the time information is from
|
||||
* a timescale directive. */
|
||||
scope->time_from_timescale = pform_timescale_file != 0;
|
||||
|
||||
if (warn_timescale && (lexical_scope == 0) && pform_timescale_file
|
||||
&& (strcmp(pform_timescale_file, loc.text) != 0)) {
|
||||
|
||||
cerr << loc.get_fileline() << ": warning: "
|
||||
<< "timescale for " << scope->pscope_name()
|
||||
<< " inherited from another file." << endl;
|
||||
cerr << pform_timescale_file << ":" << pform_timescale_line
|
||||
<< ": ...: The inherited timescale is here." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
|
||||
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
PClass*class_scope = new PClass(name, lexical_scope);
|
||||
class_scope->default_lifetime = find_lifetime(lifetime);
|
||||
FILE_NAME(class_scope, loc);
|
||||
|
||||
pform_set_scope_timescale(class_scope, loc);
|
||||
|
||||
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
||||
|
||||
assert(!pform_cur_generate);
|
||||
@@ -346,7 +467,7 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
|
||||
/* If no scope was found then this is being defined in the
|
||||
* compilation unit scope. */
|
||||
if (scopex == 0) {
|
||||
pform_classes[name] = class_scope;
|
||||
pform_classes.push_back(class_scope);
|
||||
lexical_scope = class_scope;
|
||||
return class_scope;
|
||||
}
|
||||
@@ -364,22 +485,33 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
|
||||
return class_scope;
|
||||
}
|
||||
|
||||
PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name)
|
||||
PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name,
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
PPackage*pkg_scope = new PPackage(name, lexical_scope);
|
||||
pkg_scope->default_lifetime = find_lifetime(lifetime);
|
||||
FILE_NAME(pkg_scope, loc);
|
||||
|
||||
pform_set_scope_timescale(pkg_scope, loc);
|
||||
|
||||
lexical_scope = pkg_scope;
|
||||
return pkg_scope;
|
||||
}
|
||||
|
||||
PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
|
||||
PTask* pform_push_task_scope(const struct vlltype&loc, char*name,
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
perm_string task_name = lex_strings.make(name);
|
||||
|
||||
LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime);
|
||||
bool is_auto = default_lifetime == LexicalScope::AUTOMATIC;
|
||||
|
||||
PTask*task = new PTask(task_name, lexical_scope, is_auto);
|
||||
task->default_lifetime = default_lifetime;
|
||||
FILE_NAME(task, loc);
|
||||
|
||||
pform_set_scope_timescale(task, loc);
|
||||
|
||||
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
||||
if ((scopex == 0) && !gn_system_verilog()) {
|
||||
cerr << task->get_fileline() << ": error: task declarations "
|
||||
@@ -424,15 +556,21 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
|
||||
}
|
||||
|
||||
PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
|
||||
bool is_auto)
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
perm_string func_name = lex_strings.make(name);
|
||||
|
||||
LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime);
|
||||
bool is_auto = default_lifetime == LexicalScope::AUTOMATIC;
|
||||
|
||||
PFunction*func = new PFunction(func_name, lexical_scope, is_auto);
|
||||
func->default_lifetime = default_lifetime;
|
||||
FILE_NAME(func, loc);
|
||||
|
||||
pform_set_scope_timescale(func, loc);
|
||||
|
||||
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
||||
if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) {
|
||||
if ((scopex == 0) && !gn_system_verilog()) {
|
||||
cerr << func->get_fileline() << ": error: function declarations "
|
||||
"must be contained within a module." << endl;
|
||||
error_count += 1;
|
||||
@@ -489,6 +627,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
|
||||
}
|
||||
|
||||
PBlock*block = new PBlock(block_name, lexical_scope, bt);
|
||||
block->default_lifetime = find_lifetime(LexicalScope::INHERITED);
|
||||
lexical_scope = block;
|
||||
|
||||
return block;
|
||||
@@ -1041,7 +1180,10 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check)
|
||||
|
||||
int pform_get_timeunit()
|
||||
{
|
||||
return pform_cur_module.front()->time_unit;
|
||||
if (pform_cur_module.empty())
|
||||
return pform_time_unit;
|
||||
else
|
||||
return pform_cur_module.front()->time_unit;
|
||||
}
|
||||
|
||||
void pform_set_timeprecision(const char*txt, bool in_module, bool only_check)
|
||||
@@ -1131,6 +1273,7 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val,
|
||||
|
||||
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)
|
||||
{
|
||||
if (! pform_cur_module.empty() && !gn_system_verilog()) {
|
||||
@@ -1139,6 +1282,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
if (lifetime != LexicalScope::INHERITED && !gn_system_verilog()) {
|
||||
cerr << loc << ": error: Default subroutine lifetimes "
|
||||
"require SystemVerilog." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
if (gn_system_verilog() && ! pform_cur_module.empty()) {
|
||||
if (pform_cur_module.front()->program_block) {
|
||||
cerr << loc << ": error: module, program, or interface "
|
||||
@@ -1158,17 +1307,14 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||
Module*cur_module = new Module(lexical_scope, lex_name);
|
||||
cur_module->program_block = program_block;
|
||||
cur_module->is_interface = is_interface;
|
||||
/* Set the local time unit/precision to the global value. */
|
||||
cur_module->time_unit = pform_time_unit;
|
||||
cur_module->time_precision = pform_time_prec;
|
||||
cur_module->default_lifetime = find_lifetime(lifetime);
|
||||
|
||||
FILE_NAME(cur_module, loc);
|
||||
|
||||
pform_set_scope_timescale(cur_module, loc);
|
||||
tu_local_flag = tu_global_flag;
|
||||
tp_local_flag = tp_global_flag;
|
||||
|
||||
/* If we have a timescale file then the time information is from
|
||||
* a timescale directive. */
|
||||
cur_module->time_from_timescale = pform_timescale_file != 0;
|
||||
|
||||
FILE_NAME(cur_module, loc);
|
||||
cur_module->library_flag = pform_library_flag;
|
||||
|
||||
pform_cur_module.push_front(cur_module);
|
||||
@@ -1179,15 +1325,6 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||
zero. That's just the way it is, thanks to the standard. */
|
||||
scope_generate_counter = 1;
|
||||
|
||||
if (warn_timescale && pform_timescale_file
|
||||
&& (strcmp(pform_timescale_file,loc.text) != 0)) {
|
||||
|
||||
cerr << cur_module->get_fileline() << ": warning: "
|
||||
<< "timescale for " << name
|
||||
<< " inherited from another file." << endl;
|
||||
cerr << pform_timescale_file << ":" << pform_timescale_line
|
||||
<< ": ...: The inherited timescale is here." << endl;
|
||||
}
|
||||
pform_bind_attributes(cur_module->attributes, attr);
|
||||
}
|
||||
|
||||
@@ -1199,7 +1336,7 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
|
||||
void pform_check_timeunit_prec()
|
||||
{
|
||||
assert(! pform_cur_module.empty());
|
||||
if ((generation_flag & (GN_VER2005_SV | GN_VER2009 | GN_VER2012)) &&
|
||||
if (gn_system_verilog() &&
|
||||
(pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) {
|
||||
VLerror("error: a timeprecision is missing or is too large!");
|
||||
} else assert(pform_cur_module.front()->time_unit >=
|
||||
@@ -1905,6 +2042,7 @@ static void pform_set_net_range(perm_string name,
|
||||
VLerror("error: name is not a valid net.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is not implicit ("implicit" meaning we don't
|
||||
// know what the type is yet) then set the type now.
|
||||
if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) {
|
||||
@@ -2000,9 +2138,11 @@ static void pform_makegate(PGBuiltin::Type type,
|
||||
return;
|
||||
}
|
||||
|
||||
for (list<PExpr*>::iterator cur = info.parms->begin()
|
||||
; cur != info.parms->end() ; ++cur) {
|
||||
pform_declare_implicit_nets(*cur);
|
||||
if (info.parms) {
|
||||
for (list<PExpr*>::iterator cur = info.parms->begin()
|
||||
; cur != info.parms->end() ; ++cur) {
|
||||
pform_declare_implicit_nets(*cur);
|
||||
}
|
||||
}
|
||||
|
||||
perm_string dev_name = lex_strings.make(info.name);
|
||||
@@ -2248,23 +2388,30 @@ void pform_make_pgassign_list(list<PExpr*>*alist,
|
||||
}
|
||||
|
||||
/*
|
||||
* this function makes the initial assignment to a register as given
|
||||
* in the source. It handles the case where a reg variable is assigned
|
||||
* where it it declared:
|
||||
* This function makes the initial assignment to a variable as given
|
||||
* in the source. It handles the case where a variable is assigned
|
||||
* where it is declared, e.g.
|
||||
*
|
||||
* reg foo = <expr>;
|
||||
*
|
||||
* This is equivalent to the combination of statements:
|
||||
* In Verilog-2001 this is only supported at the module level, and is
|
||||
* equivalent to the combination of statements:
|
||||
*
|
||||
* reg foo;
|
||||
* initial foo = <expr>;
|
||||
*
|
||||
* and that is how it is parsed. This syntax is not part of the
|
||||
* IEEE1364-1995 standard, but is approved by OVI as enhancement
|
||||
* BTF-B14.
|
||||
* In SystemVerilog, variable initializations are allowed in any scope.
|
||||
* For static variables, initializations are performed before the start
|
||||
* of simulation. For automatic variables, initializations are performed
|
||||
* each time the enclosing block is entered. Here we store the variable
|
||||
* assignments in the current scope, and later elaboration creates an
|
||||
* initialization block that will be executed at the appropriate time.
|
||||
*
|
||||
* This syntax is not part of the IEEE1364-1995 standard, but is
|
||||
* approved by OVI as enhancement BTF-B14.
|
||||
*/
|
||||
void pform_make_reginit(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr)
|
||||
void pform_make_var_init(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr)
|
||||
{
|
||||
if (! pform_at_module_level() && !gn_system_verilog()) {
|
||||
VLerror(li, "error: variable declaration assignments are only "
|
||||
@@ -2275,7 +2422,7 @@ void pform_make_reginit(const struct vlltype&li,
|
||||
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
VLerror(li, "internal error: reginit to non-register?");
|
||||
VLerror(li, "internal error: var_init to non-register?");
|
||||
delete expr;
|
||||
return;
|
||||
}
|
||||
@@ -2284,10 +2431,8 @@ void pform_make_reginit(const struct vlltype&li,
|
||||
FILE_NAME(lval, li);
|
||||
PAssign*ass = new PAssign(lval, expr, true);
|
||||
FILE_NAME(ass, li);
|
||||
PProcess*top = new PProcess(IVL_PR_INITIAL, ass);
|
||||
FILE_NAME(top, li);
|
||||
|
||||
pform_put_behavior_in_scope(top);
|
||||
lexical_scope->var_inits.push_back(ass);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2305,7 +2450,8 @@ void pform_module_define_port(const struct vlltype&li,
|
||||
NetNet::PortType port_kind,
|
||||
NetNet::Type type,
|
||||
data_type_t*vtype,
|
||||
list<named_pexpr_t>*attr)
|
||||
list<named_pexpr_t>*attr,
|
||||
bool keep_attr)
|
||||
{
|
||||
struct_type_t*struct_type = 0;
|
||||
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
|
||||
@@ -2394,10 +2540,37 @@ void pform_module_define_port(const struct vlltype&li,
|
||||
cur->set_unpacked_idx(*urange);
|
||||
}
|
||||
|
||||
pform_bind_attributes(cur->attributes, attr);
|
||||
pform_bind_attributes(cur->attributes, attr, keep_attr);
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
}
|
||||
|
||||
void pform_module_define_port(const struct vlltype&li,
|
||||
list<pform_port_t>*ports,
|
||||
NetNet::PortType port_kind,
|
||||
NetNet::Type type,
|
||||
data_type_t*vtype,
|
||||
list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<pform_port_t>::iterator cur = ports->begin()
|
||||
; cur != ports->end() ; ++ cur ) {
|
||||
|
||||
data_type_t*use_type = vtype;
|
||||
if (cur->udims)
|
||||
use_type = new uarray_type_t(vtype, cur->udims);
|
||||
|
||||
pform_module_define_port(li, cur->name, port_kind, type, use_type,
|
||||
attr, true);
|
||||
if (cur->udims)
|
||||
delete use_type;
|
||||
|
||||
if (cur->expr)
|
||||
pform_make_var_init(li, cur->name, cur->expr);
|
||||
}
|
||||
|
||||
delete ports;
|
||||
delete attr;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function makes a single signal (a wire, a reg, etc) as
|
||||
* requested by the parser. The name is unscoped, so I attach the
|
||||
@@ -2591,6 +2764,15 @@ void pform_makewire(const struct vlltype&li,
|
||||
NetNet::Type type,
|
||||
data_type_t*data_type)
|
||||
{
|
||||
if ((lexical_scope == 0) && !gn_system_verilog()) {
|
||||
VLerror(li, "error: variable declarations must be contained within a module.");
|
||||
return;
|
||||
}
|
||||
if (lexical_scope == 0) {
|
||||
VLerror(li, "sorry: variable declarations in the $root scope are not yet supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
list<perm_string>*names = new list<perm_string>;
|
||||
|
||||
for (list<decl_assignment_t*>::iterator cur = assign_list->begin()
|
||||
@@ -2887,6 +3069,14 @@ void pform_set_parameter(const struct vlltype&loc,
|
||||
LexicalScope::range_t*value_range)
|
||||
{
|
||||
LexicalScope*scope = lexical_scope;
|
||||
if ((scope == 0) && !gn_system_verilog()) {
|
||||
VLerror(loc, "error: parameter declarations must be contained within a module.");
|
||||
return;
|
||||
}
|
||||
if (scope == 0) {
|
||||
VLerror(loc, "sorry: parameter declarations in the $root scope are not yet supported.");
|
||||
return;
|
||||
}
|
||||
if (scope == pform_cur_generate) {
|
||||
VLerror("parameter declarations are not permitted in generate blocks");
|
||||
return;
|
||||
@@ -2910,7 +3100,7 @@ void pform_set_parameter(const struct vlltype&loc,
|
||||
error_count += 1;
|
||||
}
|
||||
// Only a Module scope has specparams.
|
||||
if ((dynamic_cast<Module*> (scope)) &&
|
||||
if ((dynamic_cast<Module*> (scope)) &&
|
||||
(scope == pform_cur_module.front()) &&
|
||||
(pform_cur_module.front()->specparams.find(name) !=
|
||||
pform_cur_module.front()->specparams.end())) {
|
||||
@@ -2954,7 +3144,14 @@ void pform_set_localparam(const struct vlltype&loc,
|
||||
bool signed_flag, list<pform_range_t>*range, PExpr*expr)
|
||||
{
|
||||
LexicalScope*scope = lexical_scope;
|
||||
ivl_assert(loc, scope);
|
||||
if ((scope == 0) && !gn_system_verilog()) {
|
||||
VLerror(loc, "error: localparam declarations must be contained within a module.");
|
||||
return;
|
||||
}
|
||||
if (scope == 0) {
|
||||
VLerror(loc, "sorry: localparam declarations in the $root scope are not yet supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the localparam name is already in the dictionary.
|
||||
if (scope->localparams.find(name) != scope->localparams.end()) {
|
||||
@@ -3176,24 +3373,53 @@ static void pform_set_port_type(perm_string name, NetNet::PortType pt,
|
||||
}
|
||||
|
||||
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 pt,
|
||||
data_type_t*dt,
|
||||
list<named_pexpr_t>*attr)
|
||||
{
|
||||
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
|
||||
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ cur ) {
|
||||
perm_string txt = *cur;
|
||||
pform_set_port_type(txt, pt, li.text, li.first_line);
|
||||
pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE,
|
||||
SR_PORT, attr);
|
||||
list<pform_range_t>*range = 0;
|
||||
bool signed_flag = false;
|
||||
if (vector_type_t*vt = dynamic_cast<vector_type_t*> (dt)) {
|
||||
assert(vt->implicit_flag);
|
||||
range = vt->pdims.get();
|
||||
signed_flag = vt->signed_flag;
|
||||
} else {
|
||||
assert(dt == 0);
|
||||
}
|
||||
|
||||
delete names;
|
||||
delete range;
|
||||
bool have_init_expr = false;
|
||||
for (list<pform_port_t>::iterator cur = ports->begin()
|
||||
; cur != ports->end() ; ++ cur ) {
|
||||
|
||||
pform_set_port_type(cur->name, pt, li.text, li.first_line);
|
||||
pform_set_net_range(cur->name, NetNet::NONE, range, signed_flag,
|
||||
IVL_VT_NO_TYPE, SR_PORT, attr);
|
||||
if (cur->udims) {
|
||||
cerr << li.text << ":" << li.first_line << ": warning: "
|
||||
<< "Array dimensions in incomplete port declarations "
|
||||
<< "are currently ignored." << endl;
|
||||
cerr << li.text << ":" << li.first_line << ": : "
|
||||
<< "The dimensions specified in the net or variable "
|
||||
<< "declaration will be used." << endl;
|
||||
delete cur->udims;
|
||||
}
|
||||
if (cur->expr) {
|
||||
have_init_expr = true;
|
||||
delete cur->expr;
|
||||
}
|
||||
}
|
||||
if (have_init_expr) {
|
||||
cerr << li.text << ":" << li.first_line << ": error: "
|
||||
<< "Incomplete port declarations cannot be initialized."
|
||||
<< endl;
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
delete ports;
|
||||
delete dt;
|
||||
delete attr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef IVL_pform_H
|
||||
#define IVL_pform_H
|
||||
/*
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-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
|
||||
@@ -163,18 +163,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*>*);
|
||||
|
||||
/* 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 +194,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 +220,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 +256,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 +368,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,
|
||||
|
||||
+51
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-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
|
||||
@@ -318,7 +318,7 @@ void PECallFunction::dump(ostream &out) const
|
||||
|
||||
void PECastSize::dump(ostream &out) const
|
||||
{
|
||||
out << size_ << "'(";
|
||||
out << *size_ << "'(";
|
||||
base_->dump(out);
|
||||
out << ")";
|
||||
}
|
||||
@@ -789,6 +789,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) {
|
||||
@@ -926,7 +928,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 +994,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 +1014,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 +1044,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 +1061,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 +1091,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 +1147,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 +1160,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
|
||||
@@ -1157,7 +1184,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 +1299,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 +1440,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 +1604,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 ) {
|
||||
|
||||
+9
-3
@@ -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;
|
||||
}
|
||||
@@ -152,6 +153,11 @@ void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident)
|
||||
|
||||
scope->imports[cur->first] = pkg;
|
||||
}
|
||||
|
||||
for (set<enum_type_t*>::const_iterator cur = pkg->enum_sets.begin()
|
||||
; cur != pkg->enum_sets.end() ; ++ cur) {
|
||||
scope->enum_sets.insert(*cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -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);
|
||||
|
||||
+32
-9
@@ -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.
|
||||
*/
|
||||
@@ -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 */
|
||||
|
||||
+11
-7
@@ -4,22 +4,26 @@
|
||||
# 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
|
||||
# The above assumes that there is a tag "v10_1" at the point
|
||||
# to be released. (The tag has the "v", but the argument to this
|
||||
# script does not have the "v"). This script extracts based on the
|
||||
# tag, uses the temporary directory to stage intermediate results,
|
||||
# and finally creates a file called verilog-0.9.1.tar.gz that
|
||||
# and finally creates a file called verilog-10.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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-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
|
||||
@@ -103,6 +103,14 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||
NetNet*rsig = rval_->synthesize(des, scope, rval_);
|
||||
assert(rsig);
|
||||
|
||||
if (lval_->word() && ! dynamic_cast<NetEConst*>(lval_->word())) {
|
||||
cerr << get_fileline() << ": sorry: assignment to variable "
|
||||
"location in memory is not currently supported in "
|
||||
"synthesis." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
NetNet*lsig = lval_->sig();
|
||||
if (!lsig) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
@@ -218,6 +226,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||
rsig = tmp;
|
||||
}
|
||||
|
||||
rsig = crop_to_width(des, rsig, lsig->vector_width());
|
||||
|
||||
if (nex_out.pin_count() > 1) {
|
||||
NexusSet tmp_set;
|
||||
nex_output(tmp_set);
|
||||
@@ -555,7 +565,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
|
||||
// The minimum selector width is the number of inputs that
|
||||
// are selected, rounded up to the nearest power of 2.
|
||||
unsigned sel_need = ceil(log2(max_guard_value + 1));
|
||||
unsigned sel_need = max(ceil(log2(max_guard_value + 1)), 1.0);
|
||||
|
||||
// If the sel_width can select more than just the explicit
|
||||
// guard values, and there is a default statement, then adjust
|
||||
@@ -1411,6 +1421,16 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
||||
are used to collect the outputs from the substatement
|
||||
for the inputs of the FF bank. */
|
||||
NetBus tmp_out (scope, tmp_set.size());
|
||||
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
|
||||
unsigned ptr = nex_map.find_nexus(tmp_set[idx]);
|
||||
ivl_assert(*this, ptr < nex_out.pin_count());
|
||||
if (nex_out.pin(ptr).is_linked()) {
|
||||
cerr << get_fileline() << ": sorry: multiple statements "
|
||||
"assigning to the same flip-flop are not yet "
|
||||
"supported in synthesis." << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a temporary ff_ce (FF clock-enable) that
|
||||
accounts for the subset of outputs that this
|
||||
|
||||
+2
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2018 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -171,13 +171,6 @@ extern "C" unsigned ivl_expr_lineno(ivl_expr_t net)
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
inline static const char *basename(ivl_scope_t scope, const char *inst)
|
||||
{
|
||||
inst += strlen(ivl_scope_name(scope));
|
||||
assert(*inst == '.');
|
||||
return inst+1;
|
||||
}
|
||||
|
||||
extern "C" ivl_variable_type_t ivl_const_type(ivl_net_const_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1464,6 +1457,7 @@ extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net)
|
||||
case IVL_LPM_CONCATZ:
|
||||
cerr << "error: ivl_lpm_selects() is no longer supported for "
|
||||
"IVL_LPM_CONCAT, use ivl_lpm_size() instead." << endl;
|
||||
// fallthrough
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2018 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -151,13 +151,6 @@ void ivl_net_const_s::operator delete(void*, size_t)
|
||||
|
||||
static StringHeapLex net_const_strings;
|
||||
|
||||
inline static const char *basename(ivl_scope_t scope, const char *inst)
|
||||
{
|
||||
inst += strlen(ivl_scope_name(scope));
|
||||
assert(*inst == '.');
|
||||
return inst+1;
|
||||
}
|
||||
|
||||
static perm_string make_scope_name(const hname_t&name)
|
||||
{
|
||||
if (! name.has_numbers())
|
||||
@@ -288,6 +281,13 @@ ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur)
|
||||
return scope;
|
||||
}
|
||||
|
||||
for (map<const NetScope*,ivl_scope_t>::iterator idx = des.root_tasks.begin()
|
||||
; idx != des.root_tasks.end() ; ++ idx) {
|
||||
ivl_scope_t scope = find_scope_from_root(idx->second, cur);
|
||||
if (scope)
|
||||
return scope;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2489,6 +2489,7 @@ void dll_target::scope(const NetScope*net)
|
||||
case NetScope::PACKAGE:
|
||||
cerr << "?:?" << ": internal error: "
|
||||
<< "Package scopes should not have parents." << endl;
|
||||
// fallthrough
|
||||
case NetScope::MODULE:
|
||||
scop->type_ = IVL_SCT_MODULE;
|
||||
scop->tname_ = net->module_name();
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ using namespace std;
|
||||
|
||||
static const char*version_string =
|
||||
"Icarus Verilog BLIF Code Generator " VERSION " (" VERSION_TAG ")\n\n"
|
||||
"Copyright (c) 2013 Stephen Williams ([email protected])\n\n"
|
||||
"Copyright (c) 2013,2015 Stephen Williams ([email protected])\n\n"
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
" it under the terms of the GNU General Public License as published by\n"
|
||||
" the Free Software Foundation; either version 2 of the License, or\n"
|
||||
|
||||
+2
-2
@@ -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
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
static const char*version_string =
|
||||
"Icarus Verilog NULL Code Generator " VERSION " (" VERSION_TAG ")\n\n"
|
||||
"Copyright (c) 2000-2014 Stephen Williams ([email protected])\n\n"
|
||||
"Copyright (c) 2000-2015 Stephen Williams ([email protected])\n\n"
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
" it under the terms of the GNU General Public License as published by\n"
|
||||
" the Free Software Foundation; either version 2 of the License, or\n"
|
||||
|
||||
@@ -91,6 +91,7 @@ fp.cc: $(srcdir)/fp.y
|
||||
$(YACC) --verbose -t -p fp -d -o $@ $<
|
||||
fp.h: fp.cc
|
||||
mv fp.cc.h $@ 2>/dev/null || mv fp.hh $@
|
||||
touch $@
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
|
||||
+5
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Stephen Williams ([email protected])
|
||||
* Copyright (C) 2011-2017 Stephen Williams ([email protected])
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -79,11 +79,14 @@ void init_fp_lexor(FILE*fd)
|
||||
yyrestart(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modern version of flex (>=2.5.9) can clean up the scanner data.
|
||||
*/
|
||||
void destroy_fp_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
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2014,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
|
||||
@@ -34,7 +34,7 @@ using namespace std;
|
||||
|
||||
static const char*version_string =
|
||||
"Icarus Verilog SIZER Statistics Generator " VERSION " (" VERSION_TAG ")\n\n"
|
||||
"Copyright (c) 2014 Stephen Williams ([email protected])\n\n"
|
||||
"Copyright (c) 2014,2015 Stephen Williams ([email protected])\n\n"
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
" it under the terms of the GNU General Public License as published by\n"
|
||||
" the Free Software Foundation; either version 2 of the License, or\n"
|
||||
|
||||
@@ -42,7 +42,6 @@ void show_constant(ivl_net_const_t net)
|
||||
case IVL_VT_REAL:
|
||||
fprintf(out, "%f", ivl_const_real(net));
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
fprintf(out, "<unsupported type>");
|
||||
break;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// are not used here.
|
||||
|
||||
// target_design()
|
||||
unusedFunction:stub.c:1773
|
||||
unusedFunction:stub.c:1774
|
||||
|
||||
// target_query()
|
||||
unusedFunction:stub.c:1843
|
||||
unusedFunction:stub.c:1844
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
|
||||
static const char*version_string =
|
||||
"Icarus Verilog STUB Code Generator " VERSION " (" VERSION_TAG ")\n\n"
|
||||
"Copyright (c) 2000-2014 Stephen Williams ([email protected])\n\n"
|
||||
"Copyright (c) 2000-2015 Stephen Williams ([email protected])\n\n"
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
" it under the terms of the GNU General Public License as published by\n"
|
||||
" the Free Software Foundation; either version 2 of the License, or\n"
|
||||
|
||||
+5
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* VHDL code generation for statements.
|
||||
*
|
||||
* Copyright (C) 2008-2013 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2018 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -683,8 +683,10 @@ static void get_nexuses_from_expr(ivl_expr_t expr, set<ivl_nexus_t> &out)
|
||||
break;
|
||||
case IVL_EX_TERNARY:
|
||||
get_nexuses_from_expr(ivl_expr_oper3(expr), out);
|
||||
// fallthrough
|
||||
case IVL_EX_BINARY:
|
||||
get_nexuses_from_expr(ivl_expr_oper2(expr), out);
|
||||
// fallthrough
|
||||
case IVL_EX_UNARY:
|
||||
get_nexuses_from_expr(ivl_expr_oper1(expr), out);
|
||||
break;
|
||||
@@ -1180,7 +1182,7 @@ static long get_number_as_long(ivl_expr_t expr)
|
||||
}
|
||||
|
||||
if (ivl_expr_signed(expr) && bits[nbits-1] == '1' &&
|
||||
nbits < 8*sizeof(long)) imm |= -1L << nbits;
|
||||
nbits < 8*sizeof(long)) imm |= -1UL << nbits;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1248,6 +1250,7 @@ static void process_number(vhdl_binop_expr *all, vhdl_var_ref *test,
|
||||
switch (bits[i]) {
|
||||
case 'x':
|
||||
if (is_casez) break;
|
||||
// fallthrough
|
||||
case '?':
|
||||
case 'z':
|
||||
continue; // Ignore these.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
functor:cprop
|
||||
functor:nodangle
|
||||
flag:DLL=vhdl.tgt
|
||||
flag:DISABLE_CONCATZ_GENERATION=true
|
||||
|
||||
@@ -108,7 +108,7 @@ void vhdl_element::print() const
|
||||
// Trap allocations of vhdl_element subclasses.
|
||||
// This records the pointer allocated in a static field of vhdl_element
|
||||
// so we can delete it just before the code generator exits.
|
||||
void* vhdl_element::operator new(size_t size) throw (bad_alloc)
|
||||
void* vhdl_element::operator new(size_t size)
|
||||
{
|
||||
// Let the default new handle the allocation
|
||||
void* ptr = ::operator new(size);
|
||||
@@ -171,4 +171,3 @@ int vhdl_element::free_all_objects()
|
||||
|
||||
return freed;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class vhdl_element {
|
||||
public:
|
||||
virtual ~vhdl_element() {}
|
||||
|
||||
void* operator new(size_t size) throw (std::bad_alloc);
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* ptr);
|
||||
|
||||
virtual void emit(std::ostream &of, int level=0) const = 0;
|
||||
@@ -74,4 +74,3 @@ std::string nl_string(int level);
|
||||
void blank_line(std::ostream &of, int level);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2018 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -447,6 +447,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
//fallthrough
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
@@ -492,6 +493,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
// fallthrough
|
||||
case 'l':
|
||||
case 'r':
|
||||
emit_expr(scope, oper1, wid, 0, 0, 0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2015 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2018 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -1055,6 +1055,7 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
|
||||
"should not be generated.\n",
|
||||
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
vlog_errors += 1;
|
||||
// fallthrough
|
||||
case IVL_LPM_CONCAT:
|
||||
emit_lpm_concat(scope, lpm);
|
||||
break;
|
||||
@@ -1407,7 +1408,7 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm)
|
||||
}
|
||||
nex = ivl_lpm_sync_set(lpm);
|
||||
if (nex) {
|
||||
if (! sset_bits || (sset_bits && (sset_bits[0] == '1'))) {
|
||||
if (! sset_bits || (sset_bits[0] == '1')) {
|
||||
emit_nexus_as_ca(scope, nex, 0, 0);
|
||||
if (have_data) fprintf(vlog_out, " | ");
|
||||
} else {
|
||||
@@ -2167,10 +2168,9 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
case IVL_VT_BOOL: fprintf(stderr, " bool"); break;
|
||||
case IVL_VT_LOGIC: fprintf(stderr, " logic"); break;
|
||||
case IVL_VT_STRING: fprintf(stderr, " string"); break;
|
||||
case IVL_VT_DARRAY: fprintf(stderr, " dynamic array");
|
||||
case IVL_VT_CLASS: fprintf(stderr, " class");
|
||||
case IVL_VT_QUEUE: fprintf(stderr, " queue");
|
||||
break;
|
||||
case IVL_VT_DARRAY: fprintf(stderr, " dynamic array"); break;
|
||||
case IVL_VT_CLASS: fprintf(stderr, " class"); break;
|
||||
case IVL_VT_QUEUE: fprintf(stderr, " queue"); break;
|
||||
}
|
||||
if (ivl_signal_signed(sig)) fprintf(stderr, " <signed>");
|
||||
} else fprintf(stderr, "Error: No/missing information!");
|
||||
|
||||
+39
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -747,7 +747,9 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD)
|
||||
* This function traverses the scope tree looking for the enclosing module
|
||||
* scope. When it is found the module scope is returned. As far as this
|
||||
* translation is concerned a package is a special form of a module
|
||||
* definition and a class is also a top level scope.
|
||||
* definition and a class is also a top level scope. In SystemVerilog,
|
||||
* tasks and functions can also be top level scopes - we create a wrapper
|
||||
* module for these later.
|
||||
*/
|
||||
ivl_scope_t get_module_scope(ivl_scope_t scope)
|
||||
{
|
||||
@@ -756,6 +758,12 @@ ivl_scope_t get_module_scope(ivl_scope_t scope)
|
||||
(ivl_scope_type(scope) != IVL_SCT_PACKAGE) &&
|
||||
(ivl_scope_type(scope) != IVL_SCT_CLASS)) {
|
||||
ivl_scope_t pscope = ivl_scope_parent(scope);
|
||||
if (pscope == 0) {
|
||||
if (ivl_scope_type(scope) == IVL_SCT_TASK)
|
||||
break;
|
||||
if (ivl_scope_type(scope) == IVL_SCT_FUNCTION)
|
||||
break;
|
||||
}
|
||||
assert(pscope);
|
||||
scope = pscope;
|
||||
}
|
||||
@@ -872,7 +880,8 @@ void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
|
||||
/* Check to see if this is a root scope task or function. */
|
||||
if (ivl_scope_parent(call_scope) == 0) {
|
||||
fprintf(vlog_out, "ivl_root_scope.");
|
||||
fprintf(vlog_out, "ivl_root_scope_%s.",
|
||||
ivl_scope_basename(call_scope));
|
||||
mod_scope = 0;
|
||||
call_mod_scope = 0;
|
||||
} else {
|
||||
@@ -938,3 +947,30 @@ void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char*get_time_const(int time_value)
|
||||
{
|
||||
switch (time_value) {
|
||||
case 2: return "100s";
|
||||
case 1: return "10s";
|
||||
case 0: return "1s";
|
||||
case -1: return "100ms";
|
||||
case -2: return "10ms";
|
||||
case -3: return "1ms";
|
||||
case -4: return "100us";
|
||||
case -5: return "10us";
|
||||
case -6: return "1us";
|
||||
case -7: return "100ns";
|
||||
case -8: return "10ns";
|
||||
case -9: return "1ns";
|
||||
case -10: return "100ps";
|
||||
case -11: return "10ps";
|
||||
case -12: return "1ps";
|
||||
case -13: return "100fs";
|
||||
case -14: return "10fs";
|
||||
case -15: return "1fs";
|
||||
default:
|
||||
fprintf(stderr, "Invalid time constant value %d.\n", time_value);
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
+1
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,33 +24,6 @@
|
||||
|
||||
const char *func_rtn_name = 0;
|
||||
|
||||
static const char*get_time_const(int time_value)
|
||||
{
|
||||
switch (time_value) {
|
||||
case 2: return "100s";
|
||||
case 1: return "10s";
|
||||
case 0: return "1s";
|
||||
case -1: return "100ms";
|
||||
case -2: return "10ms";
|
||||
case -3: return "1ms";
|
||||
case -4: return "100us";
|
||||
case -5: return "10us";
|
||||
case -6: return "1us";
|
||||
case -7: return "100ns";
|
||||
case -8: return "10ns";
|
||||
case -9: return "1ns";
|
||||
case -10: return "100ps";
|
||||
case -11: return "10ps";
|
||||
case -12: return "1ps";
|
||||
case -13: return "100fs";
|
||||
case -14: return "10fs";
|
||||
case -15: return "1fs";
|
||||
default:
|
||||
fprintf(stderr, "Invalid time constant value %d.\n", time_value);
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_func_return(ivl_signal_t sig)
|
||||
{
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
+16
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
static const char*version_string =
|
||||
"Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n"
|
||||
"Copyright (C) 2010-2013 Cary R. ([email protected])\n\n"
|
||||
"Copyright (C) 2010-2015 Cary R. ([email protected])\n\n"
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
" it under the terms of the GNU General Public License as published by\n"
|
||||
" the Free Software Foundation; either version 2 of the License, or\n"
|
||||
@@ -60,7 +60,6 @@ int target_design(ivl_design_t des)
|
||||
{
|
||||
ivl_scope_t *roots;
|
||||
unsigned nroots, idx;
|
||||
unsigned has_root_scope = 0;
|
||||
const char*path = ivl_design_flag(des, "-o");
|
||||
/* Set the indent spacing with the -pspacing flag passed to iverilog
|
||||
* (e.g. -pspacing=4). The default is 2 spaces. */
|
||||
@@ -190,23 +189,27 @@ int target_design(ivl_design_t des)
|
||||
switch(ivl_scope_type(roots[idx])) {
|
||||
case IVL_SCT_FUNCTION:
|
||||
case IVL_SCT_TASK:
|
||||
if (! has_root_scope) {
|
||||
fprintf(vlog_out, "module ivl_root_scope;\n");
|
||||
indent += indent_incr;
|
||||
has_root_scope = 1;
|
||||
}
|
||||
/* Create a separate module for each task/function.
|
||||
This allows us to handle different timescales. */
|
||||
fprintf(vlog_out, "\n`timescale %s/%s\n",
|
||||
get_time_const(ivl_scope_time_units(roots[idx])),
|
||||
get_time_const(ivl_scope_time_precision(roots[idx])));
|
||||
fprintf(vlog_out, "module ivl_root_scope_%s;\n",
|
||||
ivl_scope_basename(roots[idx]));
|
||||
indent += indent_incr;
|
||||
|
||||
/* Say this task/function has a parent so the
|
||||
* definition is emitted correctly. */
|
||||
emit_scope(roots[idx], roots[idx]);
|
||||
|
||||
indent -= indent_incr;
|
||||
assert(indent == 0);
|
||||
fprintf(vlog_out, "endmodule /* ivl_root_scope_%p */\n",
|
||||
roots[idx]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_root_scope) {
|
||||
indent -= indent_incr;
|
||||
assert(indent == 0);
|
||||
fprintf(vlog_out, "endmodule /* ivl_root_scope */\n");
|
||||
}
|
||||
/* Emit the rest of the scope objects. */
|
||||
for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef IVL_vlog95_priv_H
|
||||
#define IVL_vlog95_priv_H
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -145,6 +145,11 @@ extern char * get_package_name(ivl_scope_t scope);
|
||||
*/
|
||||
extern void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb);
|
||||
|
||||
/*
|
||||
* Convert a timescale value to a string.
|
||||
*/
|
||||
extern const char*get_time_const(int time_value);
|
||||
|
||||
/*
|
||||
* Cleanup functions.
|
||||
*/
|
||||
|
||||
+2
-2
@@ -47,8 +47,8 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
||||
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.o draw_net_input.o \
|
||||
draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||
O = vvp.o draw_class.o draw_delay.o draw_enum.o draw_mux.o draw_net_input.o \
|
||||
draw_substitute.o draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||
eval_bool.o \
|
||||
eval_condit.o \
|
||||
eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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 "vvp_priv.h"
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* This function draws a BUFT to drive a constant delay value.
|
||||
*/
|
||||
static char* draw_const_net(void*ptr, char*suffix, uint64_t value)
|
||||
{
|
||||
char tmp[64];
|
||||
char c4_value[69];
|
||||
unsigned idx;
|
||||
c4_value[0] = 'C';
|
||||
c4_value[1] = '4';
|
||||
c4_value[2] = '<';
|
||||
for (idx = 0; idx < 64; idx += 1) {
|
||||
c4_value[66-idx] = (value & 1) ? '1' : '0';
|
||||
value >>= 1;
|
||||
}
|
||||
c4_value[67] = '>';
|
||||
c4_value[68] = 0;
|
||||
|
||||
/* Make the constant an argument to a BUFT, which is
|
||||
what we use to drive the value. */
|
||||
fprintf(vvp_out, "L_%p/%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n",
|
||||
ptr, suffix, c4_value);
|
||||
snprintf(tmp, sizeof tmp, "L_%p/%s", ptr, suffix);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the appropriate delay statement.
|
||||
*/
|
||||
void draw_delay(void*ptr, unsigned wid, const char*input, ivl_expr_t rise_exp,
|
||||
ivl_expr_t fall_exp, ivl_expr_t decay_exp)
|
||||
{
|
||||
char tmp[64];
|
||||
if (input == 0) {
|
||||
snprintf(tmp, sizeof tmp, "L_%p/d", ptr);
|
||||
input = tmp;
|
||||
}
|
||||
|
||||
/* If the delays are all constants then process them here. */
|
||||
if (number_is_immediate(rise_exp, 64, 0) &&
|
||||
number_is_immediate(fall_exp, 64, 0) &&
|
||||
number_is_immediate(decay_exp, 64, 0)) {
|
||||
|
||||
assert(! number_is_unknown(rise_exp));
|
||||
assert(! number_is_unknown(fall_exp));
|
||||
assert(! number_is_unknown(decay_exp));
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay %u "
|
||||
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n",
|
||||
ptr, wid,
|
||||
get_number_immediate64(rise_exp),
|
||||
get_number_immediate64(fall_exp),
|
||||
get_number_immediate64(decay_exp),
|
||||
input);
|
||||
|
||||
/* For a variable delay we indicate only two delays by setting the
|
||||
* decay time to zero. */
|
||||
} else {
|
||||
char*rise_const = 0;
|
||||
char*fall_const = 0;
|
||||
char*decay_const = 0;
|
||||
const char*rise_str;
|
||||
const char*fall_str;
|
||||
const char*decay_str;
|
||||
|
||||
if (number_is_immediate(rise_exp, 64, 0)) {
|
||||
uint64_t value = get_number_immediate64(rise_exp);
|
||||
rise_str = rise_const = draw_const_net(ptr, "tr", value);
|
||||
} else {
|
||||
ivl_signal_t sig = ivl_expr_signal(rise_exp);
|
||||
assert(sig && ivl_signal_dimensions(sig) == 0);
|
||||
rise_str = draw_net_input(ivl_signal_nex(sig,0));
|
||||
}
|
||||
|
||||
if (number_is_immediate(fall_exp, 64, 0)) {
|
||||
uint64_t value = get_number_immediate64(fall_exp);
|
||||
fall_str = fall_const = draw_const_net(ptr, "tf", value);
|
||||
} else {
|
||||
ivl_signal_t sig = ivl_expr_signal(fall_exp);
|
||||
assert(sig && ivl_signal_dimensions(sig) == 0);
|
||||
fall_str = draw_net_input(ivl_signal_nex(sig,0));
|
||||
}
|
||||
|
||||
if (decay_exp == 0) {
|
||||
decay_str = "0";
|
||||
} else if (number_is_immediate(decay_exp, 64, 0)) {
|
||||
uint64_t value = get_number_immediate64(decay_exp);
|
||||
decay_str = decay_const = draw_const_net(ptr, "td", value);
|
||||
} else {
|
||||
ivl_signal_t sig = ivl_expr_signal(decay_exp);
|
||||
assert(sig && ivl_signal_dimensions(sig) == 0);
|
||||
decay_str = draw_net_input(ivl_signal_nex(sig,0));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay %u %s, %s, %s, %s;\n",
|
||||
ptr, wid, input, rise_str, fall_str, decay_str);
|
||||
|
||||
free(rise_const);
|
||||
free(fall_const);
|
||||
free(decay_const);
|
||||
}
|
||||
}
|
||||
+2
-38
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-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
|
||||
@@ -51,44 +51,8 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
|
||||
if (data_type_of_nexus(ivl_lpm_q(net)) == IVL_VT_REAL)
|
||||
dly_width = 0;
|
||||
|
||||
draw_delay(net, dly_width, 0, d_rise, d_fall, d_decay);
|
||||
dly = "/d";
|
||||
if (number_is_immediate(d_rise, 64, 0) &&
|
||||
number_is_immediate(d_fall, 64, 0) &&
|
||||
number_is_immediate(d_decay, 64, 0)) {
|
||||
|
||||
assert( ! number_is_unknown(d_rise));
|
||||
assert( ! number_is_unknown(d_fall));
|
||||
assert( ! number_is_unknown(d_decay));
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
|
||||
net, dly_width,
|
||||
get_number_immediate64(d_rise),
|
||||
get_number_immediate64(d_fall),
|
||||
get_number_immediate64(d_decay), net);
|
||||
} else {
|
||||
ivl_signal_t sig;
|
||||
// We do not currently support calculating the decay from
|
||||
// the rise and fall variable delays.
|
||||
assert(d_decay != 0);
|
||||
assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
|
||||
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
|
||||
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay %u L_%p/d",
|
||||
net, dly_width, net);
|
||||
|
||||
sig = ivl_expr_signal(d_rise);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, ", v%p_0", sig);
|
||||
|
||||
sig = ivl_expr_signal(d_fall);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, ", v%p_0", sig);
|
||||
|
||||
sig = ivl_expr_signal(d_decay);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, ", v%p_0;\n", sig);
|
||||
}
|
||||
}
|
||||
|
||||
input[0] = draw_net_input(ivl_lpm_data(net,0));
|
||||
|
||||
+13
-60
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-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
|
||||
@@ -330,9 +330,11 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
|
||||
cptr = ivl_nexus_ptr_con(nptr);
|
||||
if (cptr) {
|
||||
char tmp[64];
|
||||
char *result = 0;
|
||||
ivl_expr_t d_rise, d_fall, d_decay;
|
||||
unsigned dly_width = 0;
|
||||
char *dly;
|
||||
|
||||
/* Constants should have exactly 1 pin, with a literal value. */
|
||||
assert(nptr_pin == 0);
|
||||
@@ -368,68 +370,17 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
d_fall = ivl_const_delay(cptr, 1);
|
||||
d_decay = ivl_const_delay(cptr, 2);
|
||||
|
||||
/* We have a delayed constant, so we need to build some code. */
|
||||
dly = "";
|
||||
if (d_rise != 0) {
|
||||
char tmp[128];
|
||||
fprintf(vvp_out, "L_%p/d .functor BUFT 1, %s, "
|
||||
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
|
||||
free(result);
|
||||
|
||||
/* Is this a fixed or variable delay? */
|
||||
if (number_is_immediate(d_rise, 64, 0) &&
|
||||
number_is_immediate(d_fall, 64, 0) &&
|
||||
number_is_immediate(d_decay, 64, 0)) {
|
||||
|
||||
assert(! number_is_unknown(d_rise));
|
||||
assert(! number_is_unknown(d_fall));
|
||||
assert(! number_is_unknown(d_decay));
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay %u "
|
||||
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
|
||||
cptr, dly_width,
|
||||
get_number_immediate64(d_rise),
|
||||
get_number_immediate64(d_fall),
|
||||
get_number_immediate64(d_decay), cptr);
|
||||
|
||||
} else {
|
||||
ivl_signal_t sig;
|
||||
// We do not currently support calculating the decay
|
||||
// from the rise and fall variable delays.
|
||||
assert(d_decay != 0);
|
||||
assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
|
||||
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
|
||||
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay %u L_%p/d",
|
||||
cptr, dly_width, cptr);
|
||||
|
||||
sig = ivl_expr_signal(d_rise);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, ", v%p_0", sig);
|
||||
|
||||
sig = ivl_expr_signal(d_fall);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, ", v%p_0", sig);
|
||||
|
||||
sig = ivl_expr_signal(d_decay);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, ", v%p_0;\n", sig);
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
result = strdup(tmp);
|
||||
|
||||
} else {
|
||||
char tmp[64];
|
||||
fprintf(vvp_out, "L_%p .functor BUFT 1, %s, "
|
||||
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
|
||||
free(result);
|
||||
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
result = strdup(tmp);
|
||||
draw_delay(cptr, dly_width, 0, d_rise, d_fall, d_decay);
|
||||
dly = "/d";
|
||||
}
|
||||
fprintf(vvp_out, "L_%p%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n",
|
||||
cptr, dly, result);
|
||||
free(result);
|
||||
|
||||
return result;
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
lpm = ivl_nexus_ptr_lpm(nptr);
|
||||
@@ -711,6 +662,8 @@ static void draw_net_input_x(ivl_nexus_t nex,
|
||||
tmp += strlen(tmp);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
case IVL_SIT_TRIAND:
|
||||
case IVL_SIT_TRIOR:
|
||||
case IVL_SIT_UWIRE:
|
||||
for (jdx = 0 ; jdx < wid ; jdx += 1)
|
||||
*tmp++ = 'z';
|
||||
|
||||
+4
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010,2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-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
|
||||
@@ -38,18 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw)
|
||||
ivl_expr_t fall_exp = ivl_switch_delay(sw, 1);
|
||||
ivl_expr_t decay_exp= ivl_switch_delay(sw, 2);
|
||||
|
||||
if ((rise_exp || fall_exp || decay_exp) &&
|
||||
(!number_is_immediate(rise_exp, 64, 0) ||
|
||||
number_is_unknown(rise_exp) ||
|
||||
!number_is_immediate(fall_exp, 64, 0) ||
|
||||
number_is_unknown(fall_exp) ||
|
||||
!number_is_immediate(decay_exp, 64, 0) ||
|
||||
number_is_unknown(decay_exp))) {
|
||||
fprintf(stderr, "%s:%u: error: Invalid tranif delay expression.\n",
|
||||
ivl_switch_file(sw), ivl_switch_lineno(sw));
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
island = ivl_switch_island(sw);
|
||||
if (ivl_island_flag_test(island, 0) == 0)
|
||||
draw_tran_island(island);
|
||||
@@ -67,24 +55,18 @@ void draw_switch_in_scope(ivl_switch_t sw)
|
||||
char str_e_buf[4 + 2*sizeof(void*)];
|
||||
|
||||
if (enable && rise_exp) {
|
||||
assert(fall_exp && decay_exp);
|
||||
|
||||
/* If the enable has a delay, then generate a .delay
|
||||
node to delay the input by the specified amount. Do
|
||||
the delay outside of the island so that the island
|
||||
processing doesn't have to deal with it. */
|
||||
const char*raw = draw_net_input(enable);
|
||||
|
||||
draw_delay(sw, 1, raw, rise_exp, fall_exp, decay_exp);
|
||||
|
||||
snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw);
|
||||
str_e = str_e_buf;
|
||||
|
||||
fprintf(vvp_out, "%s/d .delay 1 "
|
||||
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n",
|
||||
str_e, get_number_immediate64(rise_exp),
|
||||
get_number_immediate64(fall_exp),
|
||||
get_number_immediate64(decay_exp), raw);
|
||||
|
||||
fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e);
|
||||
fprintf(vvp_out, "%s .import I%p, L_%p;\n", str_e, island, sw);
|
||||
|
||||
} else if (enable) {
|
||||
str_e = draw_island_net_input(island, enable);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2014-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
|
||||
@@ -76,8 +76,8 @@ static int draw_condition_binary_compare(ivl_expr_t expr)
|
||||
%cmp instruction. */
|
||||
if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) {
|
||||
ivl_expr_t tmp = le;
|
||||
re = le;
|
||||
le = tmp;
|
||||
le = re;
|
||||
re = tmp;
|
||||
}
|
||||
|
||||
draw_eval_vec4(le);
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ long get_number_immediate(ivl_expr_t expr)
|
||||
assert(0);
|
||||
}
|
||||
if (ivl_expr_signed(expr) && bits[nbits-1]=='1' &&
|
||||
nbits < 8*sizeof(long)) imm |= -1L << nbits;
|
||||
nbits < 8*sizeof(long)) imm |= -1UL << nbits;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
unsigned idx;
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
|
||||
draw_eval_vec4(ivl_expr_parm(init_expr,idx));
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||
@@ -110,6 +111,11 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
errors += 1;
|
||||
break;
|
||||
}
|
||||
} else if (init_expr && (ivl_expr_value(init_expr) == IVL_VT_DARRAY)) {
|
||||
ivl_signal_t sig = ivl_expr_signal(init_expr);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%scopy;\n");
|
||||
|
||||
} else if (init_expr && number_is_immediate(size_expr,32,0)) {
|
||||
/* In this case, there is an init expression, the
|
||||
expression is NOT an array_pattern, and the size
|
||||
|
||||
+12
-12
@@ -117,13 +117,18 @@ static void draw_binary_vec4_arith(ivl_expr_t expr)
|
||||
unsigned rwid = ivl_expr_width(re);
|
||||
unsigned ewid = ivl_expr_width(expr);
|
||||
|
||||
int signed_flag = ivl_expr_signed(le) && ivl_expr_signed(re) ? 1 : 0;
|
||||
int is_power_op = ivl_expr_opcode(expr) == 'p' ? 1 : 0;
|
||||
|
||||
/* The power operation differs from the other arithmetic operations
|
||||
in that we only use the signed version of the operation if the
|
||||
right hand operand (the exponent) is signed. */
|
||||
int signed_flag = (ivl_expr_signed(le) || is_power_op) && ivl_expr_signed(re) ? 1 : 0;
|
||||
const char*signed_string = signed_flag? "/s" : "";
|
||||
|
||||
/* All the arithmetic operations handled here require that the
|
||||
operands (and the result) be the same width. We further
|
||||
assume that the core has not given us an operand wider then
|
||||
the expression width. So padd operands as needed. */
|
||||
/* All the arithmetic operations handled here (except for the power
|
||||
operation) require that the operands (and the result) be the same
|
||||
width. We further assume that the core has not given us an operand
|
||||
wider then the expression width. So pad operands as needed. */
|
||||
draw_eval_vec4(le);
|
||||
if (lwid != ewid) {
|
||||
fprintf(vvp_out, " %%pad/%c %u;\n", ivl_expr_signed(le)? 's' : 'u', ewid);
|
||||
@@ -150,7 +155,7 @@ static void draw_binary_vec4_arith(ivl_expr_t expr)
|
||||
}
|
||||
|
||||
draw_eval_vec4(re);
|
||||
if (rwid != ewid) {
|
||||
if ((rwid != ewid) && !is_power_op) {
|
||||
fprintf(vvp_out, " %%pad/%c %u;\n", ivl_expr_signed(re)? 's' : 'u', ewid);
|
||||
}
|
||||
|
||||
@@ -171,11 +176,6 @@ static void draw_binary_vec4_arith(ivl_expr_t expr)
|
||||
fprintf(vvp_out, " %%mod%s;\n", signed_string);
|
||||
break;
|
||||
case 'p':
|
||||
/* Note that the power operator is signed if EITHER of
|
||||
the operands is signed. This is different from other
|
||||
arithmetic operators. */
|
||||
if (ivl_expr_signed(le) || ivl_expr_signed(re))
|
||||
signed_string = "/s";
|
||||
fprintf(vvp_out, " %%pow%s;\n", signed_string);
|
||||
break;
|
||||
|
||||
@@ -1032,7 +1032,7 @@ static void draw_string_vec4(ivl_expr_t expr)
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 8) {
|
||||
tmp <<= 8;
|
||||
tmp |= *p;
|
||||
tmp |= (unsigned long)*p;
|
||||
p += 1;
|
||||
tmp_wid += 8;
|
||||
if (tmp_wid == 32) {
|
||||
|
||||
+180
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2011-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
|
||||
@@ -183,17 +183,17 @@ static void get_vec_from_lval(ivl_statement_t net, struct vec_slice_info*slices)
|
||||
unsigned wid = ivl_stmt_lwidth(net);
|
||||
|
||||
cur_bit = 0;
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
for (lidx = ivl_stmt_lvals(net) ; lidx > 0 ; lidx -= 1) {
|
||||
ivl_lval_t lval;
|
||||
unsigned bit_limit = wid - cur_bit;
|
||||
|
||||
lval = ivl_stmt_lval(net, lidx);
|
||||
lval = ivl_stmt_lval(net, lidx-1);
|
||||
|
||||
if (bit_limit > ivl_lval_width(lval))
|
||||
bit_limit = ivl_lval_width(lval);
|
||||
|
||||
get_vec_from_lval_slice(lval, slices+lidx, bit_limit);
|
||||
if (lidx > 0) {
|
||||
get_vec_from_lval_slice(lval, slices+lidx-1, bit_limit);
|
||||
if (cur_bit > 0) {
|
||||
fprintf(vvp_out, " %%concat/vec4;\n");
|
||||
}
|
||||
|
||||
@@ -555,28 +555,130 @@ static int show_stmt_assign_vector(ivl_statement_t net)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assigns a value to a real variable. This is destined
|
||||
* for /dev/null when typed ivl_signal_t takes over all the real
|
||||
* variable support.
|
||||
*/
|
||||
static int show_stmt_assign_sig_real(ivl_statement_t net)
|
||||
enum real_lval_type_e {
|
||||
REAL_NO_TYPE = 0,
|
||||
REAL_SIMPLE_WORD,
|
||||
REAL_MEMORY_WORD_STATIC,
|
||||
REAL_MEMORY_WORD_DYNAMIC
|
||||
};
|
||||
|
||||
struct real_lval_info {
|
||||
enum real_lval_type_e type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned long use_word;
|
||||
} simple_word;
|
||||
|
||||
struct {
|
||||
unsigned long use_word;
|
||||
} memory_word_static;
|
||||
|
||||
struct {
|
||||
/* Index reg that holds the memory word index */
|
||||
int word_idx_reg;
|
||||
/* Stored x/non-x flag */
|
||||
unsigned x_flag;
|
||||
} memory_word_dynamic;
|
||||
} u_;
|
||||
};
|
||||
|
||||
static void get_real_from_lval(ivl_lval_t lval, struct real_lval_info*slice)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
|
||||
/* If the word index is a constant expression, then evaluate
|
||||
it to select the word, and pay no further heed to the
|
||||
expression itself. */
|
||||
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
|
||||
assert(! number_is_unknown(word_ix));
|
||||
use_word = get_number_immediate(word_ix);
|
||||
word_ix = 0;
|
||||
}
|
||||
|
||||
if (ivl_signal_dimensions(sig)==0 && word_ix==0) {
|
||||
|
||||
slice->type = REAL_SIMPLE_WORD;
|
||||
slice->u_.simple_word.use_word = use_word;
|
||||
fprintf(vvp_out, " %%load/real v%p_%lu;\n", sig, use_word);
|
||||
|
||||
} else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {
|
||||
|
||||
slice->type = REAL_MEMORY_WORD_STATIC;
|
||||
slice->u_.memory_word_static.use_word = use_word;
|
||||
if (use_word < ivl_signal_array_count(sig)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||
use_word);
|
||||
fprintf(vvp_out, " %%load/reala v%p, 3;\n", sig);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%pushi/real 0, 0;\n");
|
||||
}
|
||||
|
||||
} else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {
|
||||
|
||||
slice->type = REAL_MEMORY_WORD_DYNAMIC;
|
||||
|
||||
slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
|
||||
slice->u_.memory_word_dynamic.x_flag = allocate_flag();
|
||||
|
||||
draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
fprintf(vvp_out, " %%flag_mov %u, 4;\n", slice->u_.memory_word_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%load/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void put_real_to_lval(ivl_lval_t lval, struct real_lval_info*slice)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
|
||||
switch (slice->type) {
|
||||
default:
|
||||
fprintf(vvp_out, " ; XXXX slice->type=%d\n", slice->type);
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case REAL_SIMPLE_WORD:
|
||||
fprintf(vvp_out, " %%store/real v%p_%lu;\n",
|
||||
sig, slice->u_.simple_word.use_word);
|
||||
break;
|
||||
|
||||
case REAL_MEMORY_WORD_STATIC:
|
||||
if (slice->u_.memory_word_static.use_word < ivl_signal_array_count(sig)) {
|
||||
int word_idx = allocate_word();
|
||||
fprintf(vvp_out," %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out," %%ix/load %d, %lu, 0;\n", word_idx, slice->u_.memory_word_static.use_word);
|
||||
fprintf(vvp_out," %%store/reala v%p, %d;\n", sig, word_idx);
|
||||
clr_word(word_idx);
|
||||
} else {
|
||||
fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word);
|
||||
}
|
||||
break;
|
||||
|
||||
case REAL_MEMORY_WORD_DYNAMIC:
|
||||
fprintf(vvp_out, " %%flag_mov 4, %u;\n", slice->u_.memory_word_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%store/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
clr_word(slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
clr_flag(slice->u_.memory_word_dynamic.x_flag);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void store_real_to_lval(ivl_lval_t lval)
|
||||
{
|
||||
ivl_lval_t lval;
|
||||
ivl_signal_t var;
|
||||
|
||||
assert(ivl_stmt_opcode(net) == 0);
|
||||
|
||||
draw_eval_real(ivl_stmt_rval(net));
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
lval = ivl_stmt_lval(net, 0);
|
||||
var = ivl_lval_sig(lval);
|
||||
assert(var != 0);
|
||||
|
||||
if (ivl_signal_dimensions(var) == 0) {
|
||||
fprintf(vvp_out, " %%store/real v%p_0;\n", var);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, only support 1-dimensional arrays.
|
||||
@@ -612,7 +714,66 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
|
||||
}
|
||||
|
||||
clr_word(word_ix);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assigns a value to a real variable. This is destined
|
||||
* for /dev/null when typed ivl_signal_t takes over all the real
|
||||
* variable support.
|
||||
*/
|
||||
static int show_stmt_assign_sig_real(ivl_statement_t net)
|
||||
{
|
||||
struct real_lval_info*slice = 0;
|
||||
ivl_lval_t lval;
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
lval = ivl_stmt_lval(net, 0);
|
||||
|
||||
/* If this is a compressed assignment, then get the contents
|
||||
of the l-value. We need this value as part of the r-value
|
||||
calculation. */
|
||||
if (ivl_stmt_opcode(net) != 0) {
|
||||
fprintf(vvp_out, " ; show_stmt_assign_real: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net));
|
||||
slice = calloc(1, sizeof(struct real_lval_info));
|
||||
get_real_from_lval(lval, slice);
|
||||
}
|
||||
|
||||
draw_eval_real(ivl_stmt_rval(net));
|
||||
|
||||
switch (ivl_stmt_opcode(net)) {
|
||||
case 0:
|
||||
store_real_to_lval(lval);
|
||||
if (slice) free(slice);
|
||||
return 0;
|
||||
|
||||
case '+':
|
||||
fprintf(vvp_out, " %%add/wr;\n");
|
||||
break;
|
||||
|
||||
case '-':
|
||||
fprintf(vvp_out, " %%sub/wr;\n");
|
||||
break;
|
||||
|
||||
case '*':
|
||||
fprintf(vvp_out, " %%mul/wr;\n");
|
||||
break;
|
||||
|
||||
case '/':
|
||||
fprintf(vvp_out, " %%div/wr;\n");
|
||||
break;
|
||||
|
||||
case '%':
|
||||
fprintf(vvp_out, " %%mod/wr;\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net));
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
put_real_to_lval(lval, slice);
|
||||
free(slice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user