mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-24 14:56:57 +02:00
Compare commits
341
Commits
s20140801
...
vec4-stack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
105521b547 | ||
|
|
fd3086f0a9 | ||
|
|
77ebfcacb9 | ||
|
|
d62a307c34 | ||
|
|
011519cb5b | ||
|
|
8a0b9acadc | ||
|
|
77d1671d8f | ||
|
|
561564065d | ||
|
|
409f8c5823 | ||
|
|
03198356a5 | ||
|
|
b1d2393789 | ||
|
|
0f740289e9 | ||
|
|
46ce236cfb | ||
|
|
86139c855d | ||
|
|
eb070b061b | ||
|
|
2b1393e7b9 | ||
|
|
85c7b07a9b | ||
|
|
0c5ed2b60f | ||
|
|
8fd1ead082 | ||
|
|
3bd307db85 | ||
|
|
35db02d35d | ||
|
|
f287546f49 | ||
|
|
1645e682f4 | ||
|
|
a57e0a1e3f | ||
|
|
b83144c552 | ||
|
|
58fb80aec4 | ||
|
|
38f277d81b | ||
|
|
f3ba335493 | ||
|
|
fb5ae48b18 | ||
|
|
68258f244e | ||
|
|
ee34ccec70 | ||
|
|
1834d470cb | ||
|
|
9bc463aac0 | ||
|
|
7c77097f71 | ||
|
|
cc4c5f4998 | ||
|
|
230c435ae7 | ||
|
|
4ddef32631 | ||
|
|
a236c274f3 | ||
|
|
21a8cb71ee | ||
|
|
b4ccaa1b0c | ||
|
|
a8d43fa743 | ||
|
|
ca2ef5c956 | ||
|
|
6015aceda2 | ||
|
|
9538501b54 | ||
|
|
ea7fa24f9e | ||
|
|
48d3701c02 | ||
|
|
c1164dcc33 | ||
|
|
1166cd932a | ||
|
|
c3a318f14e | ||
|
|
b2deae7ba9 | ||
|
|
675dd91403 | ||
|
|
b12e00d875 | ||
|
|
103828577b | ||
|
|
21c8b8ca5a | ||
|
|
25c588252f | ||
|
|
89d1125979 | ||
|
|
43c6a0bacd | ||
|
|
610ca95cbe | ||
|
|
daa59a95ad | ||
|
|
13f861a963 | ||
|
|
82ca4cf641 | ||
|
|
ac2e8dd6cd | ||
|
|
cd992b4d5a | ||
|
|
679021a1b5 | ||
|
|
f3392561ed | ||
|
|
7a9a022744 | ||
|
|
c222b3b6a4 | ||
|
|
663c79d4af | ||
|
|
bea03db25d | ||
|
|
b96f04ccce | ||
|
|
a9db765f98 | ||
|
|
c71ab5869a | ||
|
|
04bdfbccee | ||
|
|
2acc9fbdee | ||
|
|
725ed869ba | ||
|
|
301edf69d3 | ||
|
|
1612c6d638 | ||
|
|
aadd67cd3b | ||
|
|
c2ca9c3b73 | ||
|
|
0601b4e43b | ||
|
|
8aca66b109 | ||
|
|
2aeb3871ed | ||
|
|
ea21fb856e | ||
|
|
754899c99e | ||
|
|
4e94b81a4b | ||
|
|
6948c27c2d | ||
|
|
2e9c4cde55 | ||
|
|
2e8c4e3dbc | ||
|
|
cc9fcfd13d | ||
|
|
4660e0bf2f | ||
|
|
1e7509a021 | ||
|
|
c2e53f0d63 | ||
|
|
f171161822 | ||
|
|
0237297e93 | ||
|
|
e38b5d9fb7 | ||
|
|
d5123011b3 | ||
|
|
9a471bd81c | ||
|
|
632e15a55c | ||
|
|
d4313dad75 | ||
|
|
c25538d750 | ||
|
|
871d447ff7 | ||
|
|
b286b76134 | ||
|
|
4f62a0d1f2 | ||
|
|
e7df9774aa | ||
|
|
08afbde08d | ||
|
|
7ab0824adf | ||
|
|
7fad4779c5 | ||
|
|
8ac06fb63f | ||
|
|
4e727adc25 | ||
|
|
3e9c14060f | ||
|
|
702a8c3a05 | ||
|
|
48d3972299 | ||
|
|
62fce50f8c | ||
|
|
e4b862f3d1 | ||
|
|
09d3a5de59 | ||
|
|
97bde47c31 | ||
|
|
1c80c6e37a | ||
|
|
4588f7c615 | ||
|
|
006aef93d0 | ||
|
|
24b8752475 | ||
|
|
3ddcf03764 | ||
|
|
35f5d51028 | ||
|
|
87c019c65c | ||
|
|
69a1fecd2e | ||
|
|
9964d67e5e | ||
|
|
a98f21aa65 | ||
|
|
a63ca15735 | ||
|
|
d139142c29 | ||
|
|
af85d44d9f | ||
|
|
c5e0507941 | ||
|
|
c55a013162 | ||
|
|
dfbca0b186 | ||
|
|
4a779f43bd | ||
|
|
97df6183a9 | ||
|
|
95faed8e9d | ||
|
|
76aab15798 | ||
|
|
e896f0c8e6 | ||
|
|
f36bebf0e1 | ||
|
|
3fd622e4eb | ||
|
|
da4200c5bd | ||
|
|
712f394224 | ||
|
|
d6685f40a1 | ||
|
|
9ff9cbf4aa | ||
|
|
a992f3ce7c | ||
|
|
1a4edcac48 | ||
|
|
8cac72192f | ||
|
|
7f6100be2a | ||
|
|
4b60d2737e | ||
|
|
c7beef907d | ||
|
|
44da7de651 | ||
|
|
6887c82540 | ||
|
|
1333bc54a2 | ||
|
|
fddb3ec129 | ||
|
|
bfafd175fa | ||
|
|
23238aa7ac | ||
|
|
2397aa1587 | ||
|
|
b4119de9b1 | ||
|
|
338a0eb11a | ||
|
|
fde6525acb | ||
|
|
c5fee8bdb9 | ||
|
|
194a950f8d | ||
|
|
9951521212 | ||
|
|
9e856810b9 | ||
|
|
675b7d8efa | ||
|
|
e352bea476 | ||
|
|
747e656a0e | ||
|
|
7b5470c8a7 | ||
|
|
985a3eb206 | ||
|
|
e1ec27e18c | ||
|
|
d13e488f4c | ||
|
|
f5dd2ac87e | ||
|
|
94abef195a | ||
|
|
54696e0127 | ||
|
|
d85096c56a | ||
|
|
d16a9dcfc6 | ||
|
|
9842035d89 | ||
|
|
480668fee6 | ||
|
|
fa21527e9f | ||
|
|
98799ff7fa | ||
|
|
ea4b000be6 | ||
|
|
e330a0bd6e | ||
|
|
cb03802a17 | ||
|
|
22d18cb28d | ||
|
|
c98c3e5d14 | ||
|
|
a63289c2fc | ||
|
|
251b75003f | ||
|
|
01b4d49d4a | ||
|
|
f851fc6981 | ||
|
|
a25cde3bc7 | ||
|
|
51b121ae7a | ||
|
|
94caa4881e | ||
|
|
ef7ac5ed03 | ||
|
|
acce9fc2a0 | ||
|
|
1cfbd2db63 | ||
|
|
853512868b | ||
|
|
9b1de4b038 | ||
|
|
ec2793c9b0 | ||
|
|
697701a26e | ||
|
|
facc982af4 | ||
|
|
8bb1d3dabe | ||
|
|
88e951418b | ||
|
|
1572dcd3fd | ||
|
|
96d793ed6b | ||
|
|
15ccd8f4c9 | ||
|
|
d1a35d5152 | ||
|
|
3b0dfaadba | ||
|
|
1465fd1570 | ||
|
|
886b6cd349 | ||
|
|
0dc28c0fc3 | ||
|
|
dec4cd5071 | ||
|
|
0cd6fbaf41 | ||
|
|
9fa764285a | ||
|
|
fe8e7a6261 | ||
|
|
a0ea7e17cf | ||
|
|
8c3f7d78b9 | ||
|
|
684c2fe19e | ||
|
|
a67f18f8ef | ||
|
|
931039761a | ||
|
|
3852545f21 | ||
|
|
b4d0c43a96 | ||
|
|
c24c26725e | ||
|
|
1269c12054 | ||
|
|
4fb91ec7c7 | ||
|
|
e5f49baaac | ||
|
|
0f728b9150 | ||
|
|
b0c79d5d1c | ||
|
|
150fe088a6 | ||
|
|
bb66ed8b9d | ||
|
|
447e402d16 | ||
|
|
86bb269d47 | ||
|
|
486dc7abeb | ||
|
|
6765e32ab9 | ||
|
|
b1d15436fd | ||
|
|
c846b2cf3f | ||
|
|
10446df80e | ||
|
|
0a2100c87f | ||
|
|
27730395ca | ||
|
|
8e9c25a23e | ||
|
|
feccae56bf | ||
|
|
5de83906f7 | ||
|
|
8b969202c0 | ||
|
|
ea5789e4d9 | ||
|
|
f602ae84ab | ||
|
|
335db49282 | ||
|
|
8c2d51142b | ||
|
|
5ee253b03b | ||
|
|
c9ff48bd4e | ||
|
|
9b4681918b | ||
|
|
0894bc6409 | ||
|
|
da63ef02d4 | ||
|
|
a730572e37 | ||
|
|
d891285326 | ||
|
|
e8b8fcba57 | ||
|
|
6d052d4ff7 | ||
|
|
72ff9ac00b | ||
|
|
c92dea77fc | ||
|
|
4ea512c4fd | ||
|
|
89f1344288 | ||
|
|
96414af721 | ||
|
|
2d2a720ea8 | ||
|
|
9031f392ba | ||
|
|
4786f80b0b | ||
|
|
0f294cb607 | ||
|
|
f4c88b4a01 | ||
|
|
374948ce1b | ||
|
|
6a2b579fb0 | ||
|
|
d2ad7a4d28 | ||
|
|
5830ecd67e | ||
|
|
69b145e216 | ||
|
|
5ed60a151f | ||
|
|
c7a36722e3 | ||
|
|
66d31b02be | ||
|
|
0a6d75f1db | ||
|
|
88e4938074 | ||
|
|
e932c7a637 | ||
|
|
b5e0099f28 | ||
|
|
1afe7476e3 | ||
|
|
4068570f43 | ||
|
|
7ceb18fb37 | ||
|
|
d2ff77d56c | ||
|
|
91b7c6ab55 | ||
|
|
ebed793dec | ||
|
|
be5bfeb172 | ||
|
|
801e795112 | ||
|
|
e66fc7e5cc | ||
|
|
1d63875e5d | ||
|
|
554fb7ebdd | ||
|
|
c9e8392dc7 | ||
|
|
60d37e1f53 | ||
|
|
401fccdf6e | ||
|
|
f5564a195f | ||
|
|
c7e61f3aa4 | ||
|
|
1805598eae | ||
|
|
0eca210722 | ||
|
|
fdc9e8590d | ||
|
|
e497f63e29 | ||
|
|
75233a9bca | ||
|
|
11197baf86 | ||
|
|
23ba0bc019 | ||
|
|
9cfb15a302 | ||
|
|
8bebe59e20 | ||
|
|
20d415463a | ||
|
|
9c1dcad994 | ||
|
|
0e13726e83 | ||
|
|
54346d7095 | ||
|
|
0121fbc88c | ||
|
|
f1855eed0e | ||
|
|
0f9828f179 | ||
|
|
d2c2d6d8dc | ||
|
|
f94a655121 | ||
|
|
078a3fd409 | ||
|
|
dfaed128c0 | ||
|
|
1fc4093191 | ||
|
|
ae1f8be277 | ||
|
|
d8533104b0 | ||
|
|
c6c697bdb7 | ||
|
|
660d59a7a9 | ||
|
|
92a5e6a698 | ||
|
|
aaa054a932 | ||
|
|
079065ea73 | ||
|
|
1905264061 | ||
|
|
b0a9430e98 | ||
|
|
6a93b6a7e4 | ||
|
|
ec6009dd8f | ||
|
|
4820d46353 | ||
|
|
a2845cee70 | ||
|
|
c897ca017c | ||
|
|
aee540d8bb | ||
|
|
19402aeef2 | ||
|
|
fcc0a6a203 | ||
|
|
e5eb754150 | ||
|
|
063c6d6065 | ||
|
|
2fc8ce8a16 | ||
|
|
1a3adbe9cd | ||
|
|
63fa44fa4a | ||
|
|
f89dbd48c8 | ||
|
|
9fc3e84e93 | ||
|
|
e708a5b59d | ||
|
|
d55e4c0552 | ||
|
|
54926840e6 | ||
|
|
5ef077fdf6 |
+2
-2
@@ -109,7 +109,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
||||
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \
|
||||
net_design.o netclass.o netdarray.o \
|
||||
netenum.o netparray.o netscalar.o netstruct.o netvector.o \
|
||||
netenum.o netparray.o netqueue.o netscalar.o netstruct.o netvector.o \
|
||||
net_event.o net_expr.o net_func.o \
|
||||
net_func_eval.o net_link.o net_modulo.o \
|
||||
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
|
||||
@@ -267,7 +267,7 @@ lexor.cc: $(srcdir)/lexor.lex
|
||||
lexor_keyword.o: lexor_keyword.cc parse.h
|
||||
|
||||
lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf
|
||||
gperf -o -i 7 -C -k 1-4,6,9,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
gperf -o -i 7 -C -k 1-4,6,9,$$ -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
|
||||
iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in version.exe
|
||||
./version.exe `head -1 $(srcdir)/iverilog-vpi.man.in`'\n' > $@
|
||||
|
||||
@@ -146,6 +146,15 @@ PECastSize::~PECastSize()
|
||||
{
|
||||
}
|
||||
|
||||
PECastType::PECastType(data_type_t*t, PExpr*b)
|
||||
: target_(t), base_(b)
|
||||
{
|
||||
}
|
||||
|
||||
PECastType::~PECastType()
|
||||
{
|
||||
}
|
||||
|
||||
PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
|
||||
: PEBinary(op, l, r)
|
||||
{
|
||||
|
||||
@@ -245,6 +245,10 @@ class PEConcat : public PExpr {
|
||||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
@@ -505,12 +509,23 @@ class PEIdent : public PExpr {
|
||||
NetESignal*net,
|
||||
NetScope*found,
|
||||
bool need_const) const;
|
||||
NetExpr*elaborate_expr_net_bit_last_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found,
|
||||
bool need_const) const;
|
||||
|
||||
NetExpr*elaborate_expr_class_member_(Design*des,
|
||||
NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
||||
unsigned test_width_method_(Design*des, NetScope*scope, width_mode_t&mode);
|
||||
NetExpr*elaborate_expr_method_(Design*des,
|
||||
NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool bidirectional_flag) const;
|
||||
@@ -921,7 +936,8 @@ class PECallFunction : public PExpr {
|
||||
NetExpr*elaborate_expr_pkg_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags)const;
|
||||
NetExpr*elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid) const;
|
||||
unsigned expr_wid,
|
||||
bool add_this_flag = false) const;
|
||||
#if 0
|
||||
NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const;
|
||||
NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope,
|
||||
@@ -970,6 +986,28 @@ class PECastSize : public PExpr {
|
||||
PExpr* base_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Support the SystemVerilog cast to a different type.
|
||||
*/
|
||||
class PECastType : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PECastType(data_type_t*target, PExpr*base);
|
||||
~PECastType();
|
||||
|
||||
void dump(ostream &out) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
width_mode_t&mode);
|
||||
|
||||
private:
|
||||
data_type_t* target_;
|
||||
PExpr* base_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class is used for error recovery. All methods do nothing and return
|
||||
* null or default values.
|
||||
|
||||
@@ -31,6 +31,9 @@ PScope::PScope(perm_string n)
|
||||
|
||||
PScope::~PScope()
|
||||
{
|
||||
for(map<perm_string, data_type_t*>::iterator it = typedefs.begin();
|
||||
it != typedefs.end(); ++it)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
PWire* LexicalScope::wires_find(perm_string name)
|
||||
|
||||
@@ -49,6 +49,12 @@ class PTaskFunc : public PScope, public LineInfo {
|
||||
// to the class type.
|
||||
inline class_type_t* method_of() const { return this_type_; }
|
||||
|
||||
|
||||
virtual void elaborate_sig(Design*des, NetScope*scope) const =0;
|
||||
virtual void elaborate(Design*des, NetScope*scope) const =0;
|
||||
|
||||
virtual void dump(std::ostream&, unsigned) const =0;
|
||||
|
||||
protected:
|
||||
// Elaborate the ports list. Write into the ports vector the
|
||||
// NetNet pointers for the ports, and write into the pdefs the
|
||||
|
||||
@@ -336,6 +336,20 @@ PForce::~PForce()
|
||||
delete expr_;
|
||||
}
|
||||
|
||||
PForeach::PForeach(perm_string av, const list<perm_string>&ix, Statement*s)
|
||||
: array_var_(av), index_vars_(ix.size()), statement_(s)
|
||||
{
|
||||
size_t idx = 0;
|
||||
for (list<perm_string>::const_iterator cur = ix.begin()
|
||||
; cur != ix.end() ; ++cur)
|
||||
index_vars_[idx++] = *cur;
|
||||
}
|
||||
|
||||
PForeach::~PForeach()
|
||||
{
|
||||
delete statement_;
|
||||
}
|
||||
|
||||
PForever::PForever(Statement*s)
|
||||
: statement_(s)
|
||||
{
|
||||
|
||||
+26
-2
@@ -224,12 +224,16 @@ class PCallTask : public Statement {
|
||||
NetProc* elaborate_sys(Design*des, NetScope*scope) const;
|
||||
NetProc* elaborate_usr(Design*des, NetScope*scope) const;
|
||||
|
||||
NetProc*elaborate_method_(Design*des, NetScope*scope) const;
|
||||
NetProc*elaborate_method_(Design*des, NetScope*scope,
|
||||
bool add_this_flag = false) const;
|
||||
NetProc*elaborate_function_(Design*des, NetScope*scope) const;
|
||||
|
||||
NetProc*elaborate_build_call_(Design*des, NetScope*scope,
|
||||
NetScope*task, NetExpr*use_this) const;
|
||||
|
||||
NetProc*elaborate_sys_task_method_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const;
|
||||
bool test_task_calls_ok_(Design*des, NetScope*scope) const;
|
||||
|
||||
PPackage*package_;
|
||||
@@ -440,6 +444,26 @@ class PForce : public Statement {
|
||||
PExpr*expr_;
|
||||
};
|
||||
|
||||
class PForeach : public Statement {
|
||||
public:
|
||||
explicit PForeach(perm_string var, const std::list<perm_string>&ix, Statement*stmt);
|
||||
~PForeach();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetProc* elaborate_static_array_(Design*des, NetScope*scope,
|
||||
const std::vector<netrange_t>&dims) const;
|
||||
|
||||
private:
|
||||
perm_string array_var_;
|
||||
std::vector<perm_string> index_vars_;
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
class PForever : public Statement {
|
||||
public:
|
||||
explicit PForever(Statement*s);
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ echo "Autoconf in root..."
|
||||
autoconf -f
|
||||
|
||||
echo "Precompiling lexor_keyword.gperf"
|
||||
gperf -o -i 7 -C -k 1-4,6,9,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
gperf -o -i 7 -C -k 1-4,6,9,\$ -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
|
||||
echo "Precompiling vhdlpp/lexor_keyword.gperf"
|
||||
(cd vhdlpp ; gperf -o -i 7 --ignore-case -C -k 1-4,6,9,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc )
|
||||
(cd vhdlpp ; gperf -o -i 7 --ignore-case -C -k 1-4,6,9,\$ -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc )
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
// These are correct and are used to find the base (zero) pin.
|
||||
thisSubtraction:netlist.h:4863
|
||||
thisSubtraction:netlist.h:4872
|
||||
thisSubtraction:netlist.h:4938
|
||||
thisSubtraction:netlist.h:4947
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
# include "discipline.h"
|
||||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netqueue.h"
|
||||
# include "netvector.h"
|
||||
# include "ivl_assert.h"
|
||||
# include "PExpr.h"
|
||||
@@ -113,6 +114,9 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
|
||||
case IVL_VT_CLASS:
|
||||
o << "class";
|
||||
break;
|
||||
case IVL_VT_QUEUE:
|
||||
o << "queue";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
@@ -199,12 +203,33 @@ ostream& ivl_type_s::debug_dump(ostream&o) const
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& netclass_t::debug_dump(ostream&fd) const
|
||||
{
|
||||
fd << "class " << name_ << "{";
|
||||
for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) {
|
||||
if (idx != 0) fd << "; ";
|
||||
if (property_table_[idx].type)
|
||||
property_table_[idx].type->debug_dump(fd);
|
||||
else
|
||||
fd << "NO_TYPE";
|
||||
fd << " " << property_table_[idx].name;
|
||||
}
|
||||
fd << "}";
|
||||
return fd;
|
||||
}
|
||||
|
||||
ostream& netdarray_t::debug_dump(ostream&o) const
|
||||
{
|
||||
o << "dynamic array of " << *element_type();
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& netqueue_t::debug_dump(ostream&fd) const
|
||||
{
|
||||
fd << "queue of " << *element_type();
|
||||
return fd;
|
||||
}
|
||||
|
||||
ostream& netvector_t::debug_dump(ostream&o) const
|
||||
{
|
||||
o << type_ << (signed_? " signed" : " unsigned") << packed_dims_;
|
||||
@@ -1636,6 +1661,16 @@ void NetEBinary::dump(ostream&o) const
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void NetECast::dump(ostream&fd) const
|
||||
{
|
||||
if (op_=='2')
|
||||
fd << "bool<" << expr_width() << ">(" << *expr_ << ")";
|
||||
else if (op_=='4')
|
||||
fd << "logic<" << expr_width() << ">(" << *expr_ << ")";
|
||||
else
|
||||
NetEUnary::dump(fd);
|
||||
}
|
||||
|
||||
void NetEConcat::dump(ostream&o) const
|
||||
{
|
||||
if (repeat_ != 1)
|
||||
@@ -1694,6 +1729,11 @@ void NetEEvent::dump(ostream&o) const
|
||||
o << "<event=" << event_->name() << ">";
|
||||
}
|
||||
|
||||
void NetELast::dump(ostream&fd) const
|
||||
{
|
||||
fd << "<last of " << sig_->name() << ">";
|
||||
}
|
||||
|
||||
void NetENetenum::dump(ostream&o) const
|
||||
{
|
||||
o << "<netenum=" << netenum_ << ">";
|
||||
@@ -1719,6 +1759,8 @@ void NetENull::dump(ostream&o) const
|
||||
void NetEProperty::dump(ostream&o) const
|
||||
{
|
||||
o << net_->name() << ".<" << pidx_ << ">";
|
||||
if (index_)
|
||||
o << "[" << *index_ << "]";
|
||||
}
|
||||
|
||||
void NetEScope::dump(ostream&o) const
|
||||
@@ -1847,6 +1889,18 @@ void Design::dump(ostream&o) const
|
||||
cur->second->dump(o);
|
||||
}
|
||||
|
||||
o << "$ROOT CLASSESS:" << endl;
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++cur) {
|
||||
cur->second->dump_scope(o);
|
||||
}
|
||||
|
||||
o << "$ROOT TASKS/FUNCTIONS:" << endl;
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
cur->first->dump(o);
|
||||
}
|
||||
|
||||
o << "SCOPES:" << endl;
|
||||
for (list<NetScope*>::const_iterator scope = root_scopes_.begin();
|
||||
scope != root_scopes_.end(); ++ scope ) {
|
||||
|
||||
@@ -182,6 +182,14 @@ NetEEvent* NetEEvent::dup_expr() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetELast* NetELast::dup_expr() const
|
||||
{
|
||||
NetELast*tmp = new NetELast(sig_);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetENetenum* NetENetenum::dup_expr() const
|
||||
{
|
||||
ivl_assert(*this, 0);
|
||||
|
||||
+550
-29
@@ -30,11 +30,13 @@
|
||||
# include "netlist.h"
|
||||
# include "netclass.h"
|
||||
# include "netenum.h"
|
||||
# include "netparray.h"
|
||||
# include "netvector.h"
|
||||
# include "discipline.h"
|
||||
# include "netmisc.h"
|
||||
# include "netdarray.h"
|
||||
# include "netstruct.h"
|
||||
# include "netscalar.h"
|
||||
# include "util.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
@@ -106,6 +108,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
|
||||
int context_wid = -1;
|
||||
switch (lv_type) {
|
||||
case IVL_VT_DARRAY:
|
||||
case IVL_VT_QUEUE:
|
||||
// For these types, use a different elab_and_eval that
|
||||
// uses the lv_net_type. We should eventually transition
|
||||
// all the types to this new form.
|
||||
@@ -264,6 +267,13 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
|
||||
unsigned l_width = left_->test_width(des, scope, mode);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEBinary::test_width: "
|
||||
<< "op_=" << op_ << ", l_width=" << l_width
|
||||
<< ", r_width=" << r_width
|
||||
<< ", saved_mode=" << saved_mode << endl;
|
||||
}
|
||||
|
||||
// If the width mode changed, retest the right operand, as it
|
||||
// may choose a different width if it is in a lossless context.
|
||||
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS))
|
||||
@@ -309,7 +319,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
|
||||
case '%':
|
||||
case '/':
|
||||
min_width_ = max(min_width_, expr_width_);
|
||||
min_width_ = UINT_MAX; // disable width pruning
|
||||
break;
|
||||
|
||||
case 'l': // << Should be handled by PEBShift
|
||||
@@ -714,6 +724,14 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
ivl_assert(*this, left_);
|
||||
ivl_assert(*this, right_);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEBLeftWidth::test_width: "
|
||||
<< "op_=" << op_
|
||||
<< ", left_=" << *left_
|
||||
<< ", right_=" << *right_
|
||||
<< ", mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
// The right operand is self determined. Test its type and
|
||||
// width for use later. We only need to know its width now
|
||||
// if the left operand is unsized and we need to calculate
|
||||
@@ -721,11 +739,26 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
width_mode_t r_mode = SIZED;
|
||||
unsigned r_width = right_->test_width(des, scope, r_mode);
|
||||
|
||||
expr_width_ = left_->test_width(des, scope, mode);
|
||||
// The left operand is what will determine the size of the
|
||||
// expression. The l_mode will be converted to UNSIZED if the
|
||||
// expression does not have a well-determined size.
|
||||
width_mode_t l_mode = SIZED;
|
||||
expr_width_ = left_->test_width(des, scope, l_mode);
|
||||
expr_type_ = left_->expr_type();
|
||||
signed_flag_ = left_->has_sign();
|
||||
|
||||
if (mode==SIZED)
|
||||
mode = l_mode;
|
||||
|
||||
// The left operand width defines the size of the
|
||||
// expression. If the expression has a well-defined size, the
|
||||
// left_->test_width() above would have set mode==SIZED and we
|
||||
// can skip a lot of stuff. But if the mode is an undetermined
|
||||
// size, we need to figure out what we really want to keep a
|
||||
// lossless value. That's what the following if(...) {...} is
|
||||
// all about.
|
||||
if ((mode >= EXPAND) && type_is_vectorable(expr_type_)) {
|
||||
|
||||
// We need to make our best guess at the right operand
|
||||
// value, to minimize the calculated width. This is
|
||||
// particularly important for the power operator...
|
||||
@@ -755,6 +788,13 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
if (rc && (r_width < sizeof(long)*8))
|
||||
r_val = rc->value().as_long();
|
||||
|
||||
if (debug_elaborate && rc) {
|
||||
cerr << get_fileline() << ": PEBLeftWidth::test_width: "
|
||||
<< "Evaluated rc=" << *rc
|
||||
<< ", r_val=" << r_val
|
||||
<< ", width_cap=" << width_cap << endl;
|
||||
}
|
||||
|
||||
// Clip to a sensible range to avoid underflow/overflow
|
||||
// in the following calculations.
|
||||
if (r_val < 0)
|
||||
@@ -771,7 +811,8 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
unsigned use_width = expr_width_;
|
||||
switch (op_) {
|
||||
case 'l': // <<
|
||||
use_width += (unsigned)r_val;
|
||||
if (l_mode != SIZED)
|
||||
use_width += (unsigned)r_val;
|
||||
break;
|
||||
|
||||
case 'r': // >>
|
||||
@@ -809,13 +850,26 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
if ((rc == 0) && (use_width > expr_width_) && (use_width > integer_width))
|
||||
use_width = integer_width;
|
||||
|
||||
if (use_width >= width_cap) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "Unsized expression (" << *this << ")"
|
||||
<< " expanded beyond and was clipped to " << use_width
|
||||
<< " bits. Try using sized operands." << endl;
|
||||
}
|
||||
expr_width_ = use_width;
|
||||
}
|
||||
|
||||
if (op_ == 'l')
|
||||
min_width_ = left_->min_width();
|
||||
else
|
||||
min_width_ = expr_width_;
|
||||
min_width_ = UINT_MAX; // disable width pruning
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEBLeftWidth::test_width: "
|
||||
<< "Done calculating expr_width_=" << expr_width_
|
||||
<< ", min_width_=" << min_width_
|
||||
<< ", mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
return fix_width_(mode);
|
||||
}
|
||||
@@ -1270,6 +1324,18 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
||||
if (net == 0)
|
||||
return 0;
|
||||
|
||||
// Look fonr built in string attributes.
|
||||
if (net->data_type()==IVL_VT_STRING) {
|
||||
|
||||
if (method_name == "len") {
|
||||
expr_type_ = IVL_VT_BOOL;
|
||||
expr_width_ = 32;
|
||||
min_width_ = 32;
|
||||
signed_flag_= true;
|
||||
return expr_width_;
|
||||
}
|
||||
}
|
||||
|
||||
// function int size()
|
||||
if (use_darray && method_name == "size") {
|
||||
if (debug_elaborate) {
|
||||
@@ -1284,10 +1350,27 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
if (use_darray && (method_name == "pop_back" || method_name=="pop_front")) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::test_width_method_: "
|
||||
<< "Detected " << method_name << " method"
|
||||
<< " of dynamic arrays." << endl;
|
||||
}
|
||||
|
||||
expr_type_ = use_darray->element_base_type();
|
||||
expr_width_ = use_darray->element_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_= false;
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
if (const netclass_t*class_type = net->class_type()) {
|
||||
cerr << get_fileline() << ": PECallFunction::test_width_method_: "
|
||||
<< "Try to find method " << method_name
|
||||
<< " of class " << class_type->get_name() << endl;
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::test_width_method_: "
|
||||
<< "Try to find method " << method_name
|
||||
<< " of class " << class_type->get_name() << endl;
|
||||
}
|
||||
|
||||
NetScope*func = class_type->method_from_name(method_name);
|
||||
if (func == 0) {
|
||||
@@ -1313,6 +1396,13 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
||||
|
||||
NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::cast_to_width_: "
|
||||
<< "cast to " << wid
|
||||
<< " bits " << (signed_flag_?"signed":"unsigned")
|
||||
<< " 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)) {
|
||||
@@ -1325,10 +1415,6 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: cast to " << wid
|
||||
<< " bits " << (signed_flag_?"signed":"unsigned") << endl;
|
||||
|
||||
NetESelect*tmp = new NetESelect(expr, 0, wid);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
tmp->set_line(*this);
|
||||
@@ -1372,6 +1458,10 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: "
|
||||
<< name << " expression is the argument cast to expr_wid=" << expr_wid << endl;
|
||||
}
|
||||
PExpr*expr = parms_[0];
|
||||
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags);
|
||||
|
||||
@@ -1749,6 +1839,14 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li,
|
||||
bool calculate_part(const LineInfo*li, Design*des, NetScope*scope,
|
||||
const index_component_t&index, long&off, unsigned long&wid)
|
||||
{
|
||||
if (index.sel == index_component_t::SEL_BIT_LAST) {
|
||||
cerr << li->get_fileline() << ": sorry: "
|
||||
<< "Last element select expression "
|
||||
<< "not supported." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate the last index expression into a constant long.
|
||||
NetExpr*texpr = elab_and_eval(des, scope, index.msb, -1, true);
|
||||
long msb;
|
||||
@@ -2037,11 +2135,24 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
ivl_assert(*this, def);
|
||||
|
||||
ivl_assert(*this, def);
|
||||
NetScope*dscope = def->scope();
|
||||
ivl_assert(*this, dscope);
|
||||
|
||||
/* In SystemVerilog a method calling another method in the
|
||||
* current class needs to be elaborated as a method with an
|
||||
* implicit this added. */
|
||||
if (gn_system_verilog() && (path_.size() == 1)) {
|
||||
const NetScope *c_scope = scope->get_class_scope();
|
||||
if (c_scope && (c_scope == dscope->get_class_scope())) {
|
||||
NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid,
|
||||
true);
|
||||
assert(tmp);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
// It is possible to get here before the called function has been
|
||||
@@ -2235,17 +2346,22 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid) const
|
||||
unsigned expr_wid,
|
||||
bool add_this_flag) const
|
||||
{
|
||||
pform_name_t use_path = path_;
|
||||
perm_string method_name = peek_tail_name(use_path);
|
||||
use_path.pop_back();
|
||||
|
||||
/* Add the implicit this reference when requested. */
|
||||
if (add_this_flag) {
|
||||
assert(use_path.empty());
|
||||
use_path.push_front(name_component_t(perm_string::literal("@")));
|
||||
}
|
||||
|
||||
// If there is no object to the left of the method name, then
|
||||
// give up on the idea of looking for an object method.
|
||||
if (use_path.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (use_path.empty()) return 0;
|
||||
|
||||
NetNet *net = 0;
|
||||
const NetExpr *par;
|
||||
@@ -2309,12 +2425,31 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
if (net->darray_type()) {
|
||||
|
||||
if (method_name == "size") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$size",
|
||||
NetESFunc*sys_expr = new NetESFunc("$size",
|
||||
IVL_VT_BOOL, 32, 1);
|
||||
sys_expr->parm(0, new NetESignal(net));
|
||||
sys_expr->set_line(*this);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "pop_back") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$pop_back",
|
||||
expr_type_,
|
||||
expr_width_, 1);
|
||||
sys_expr->parm(0, new NetESignal(net));
|
||||
sys_expr->set_line(*this);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "pop_front") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$pop_front",
|
||||
expr_type_,
|
||||
expr_width_, 1);
|
||||
sys_expr->parm(0, new NetESignal(net));
|
||||
sys_expr->set_line(*this);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (const netclass_t*class_type = net->class_type()) {
|
||||
@@ -2367,6 +2502,87 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
|
||||
return sel;
|
||||
}
|
||||
|
||||
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid)
|
||||
{
|
||||
ivl_type_t t = target_->elaborate_type(des, scope);
|
||||
base_->test_width(des, scope, wid);
|
||||
|
||||
if(const netdarray_t*use_darray = dynamic_cast<const netdarray_t*> (t)) {
|
||||
expr_type_ = use_darray->element_base_type();
|
||||
expr_width_ = use_darray->element_width();
|
||||
}
|
||||
|
||||
else if(const netstring_t*use_string = dynamic_cast<const netstring_t*> (t)) {
|
||||
expr_type_ = use_string->base_type();
|
||||
expr_width_ = 8;
|
||||
}
|
||||
|
||||
else {
|
||||
expr_type_ = t->base_type();
|
||||
expr_width_ = t->packed_width();
|
||||
}
|
||||
|
||||
signed_flag_= t->get_signed();
|
||||
min_width_ = expr_width_;
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned, unsigned) const
|
||||
{
|
||||
NetExpr*expr = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS);
|
||||
|
||||
if(dynamic_cast<const real_type_t*>(target_)) {
|
||||
return cast_to_real(expr);
|
||||
}
|
||||
|
||||
if(const atom2_type_t*atom = dynamic_cast<const atom2_type_t*>(target_)) {
|
||||
if(base_->expr_width() > expr_width_) {
|
||||
cerr << get_fileline() << ": cast type is not wide enough to store the result." << endl;
|
||||
ivl_assert(*this, 0);
|
||||
}
|
||||
|
||||
if(base_->has_sign() != atom->signed_flag) {
|
||||
cerr << get_fileline() << ": cast type and subject differ in signedness." << endl;
|
||||
ivl_assert(*this, 0);
|
||||
}
|
||||
|
||||
// That is how you both resize & cast to integers
|
||||
return new NetECast('2', expr, expr_width_, expr->has_sign());
|
||||
}
|
||||
|
||||
if(const vector_type_t*vec = dynamic_cast<const vector_type_t*>(target_)) {
|
||||
switch(vec->base_type) {
|
||||
case IVL_VT_BOOL:
|
||||
return cast_to_int2(expr, expr_width_);
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
return cast_to_int4(expr, expr_width_);
|
||||
|
||||
default:
|
||||
break; /* Suppress warnings */
|
||||
}
|
||||
}
|
||||
|
||||
else if(dynamic_cast<const string_type_t*>(target_)) {
|
||||
if(base_->expr_type() == IVL_VT_STRING)
|
||||
return expr; // no conversion
|
||||
|
||||
if((base_->expr_type() != IVL_VT_BOOL) &&
|
||||
(base_->expr_type() != IVL_VT_LOGIC)) {
|
||||
cerr << get_fileline() << ": cannot be casted to 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;
|
||||
}
|
||||
|
||||
unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
{
|
||||
expr_width_ = 0;
|
||||
@@ -2452,6 +2668,24 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
// Keep track of the concatenation/repeat depth.
|
||||
static int concat_depth = 0;
|
||||
|
||||
NetExpr* PEConcat::elaborate_expr(Design*, NetScope*,
|
||||
ivl_type_t type, unsigned /*flags*/) const
|
||||
{
|
||||
switch (type->base_type()) {
|
||||
case IVL_VT_QUEUE:
|
||||
if (parms_.size() == 0) {
|
||||
NetENull*tmp = new NetENull;
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "I don't know how to elaborate(ivl_type_t)"
|
||||
<< " this expression: " << *this << endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
@@ -2774,6 +3008,48 @@ bool PEIdent::calculate_param_range_(Design*, NetScope*,
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
return 0;
|
||||
if (path_.size() < 2)
|
||||
return 0;
|
||||
|
||||
pform_name_t use_path = path_;
|
||||
perm_string member_name = peek_tail_name(path_);
|
||||
use_path.pop_back();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::test_width_method_: "
|
||||
<< "Try to find method=" << member_name
|
||||
<< " of signal " << use_path << endl;
|
||||
}
|
||||
|
||||
NetNet*net = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent*eve = 0;
|
||||
const NetExpr*ex1 = 0, *ex2 = 0;
|
||||
symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2);
|
||||
if (net == 0) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": PEIdent::test_width_method_: "
|
||||
<< "Only nets can have methods, so give up here." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (/*const netdarray_t*dtype =*/ net->darray_type()) {
|
||||
if (member_name == "size") {
|
||||
expr_type_ = IVL_VT_BOOL;
|
||||
expr_width_ = 32;
|
||||
min_width_ = 32;
|
||||
signed_flag_= true;
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
{
|
||||
NetNet* net = 0;
|
||||
@@ -2788,6 +3064,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
ivl_assert(*this, use_scope);
|
||||
}
|
||||
|
||||
if (unsigned tmp = test_width_method_(des, scope, mode)) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetScope*found_in = symbol_search(this, des, use_scope, path_,
|
||||
net, par, eve,
|
||||
ex1, ex2);
|
||||
@@ -2839,21 +3119,31 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
if ((net == 0) || (net->packed_dimensions() <= 1))
|
||||
use_width = 1;
|
||||
break;
|
||||
case index_component_t::SEL_BIT_LAST:
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::test_width: "
|
||||
<< "Queue/Darray last index ($)" << endl;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
}
|
||||
|
||||
if (const netdarray_t*darray = net? net->darray_type() : 0) {
|
||||
if (use_sel == index_component_t::SEL_BIT) {
|
||||
switch (use_sel) {
|
||||
case index_component_t::SEL_BIT:
|
||||
case index_component_t::SEL_BIT_LAST:
|
||||
expr_type_ = darray->element_base_type();
|
||||
expr_width_ = darray->element_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = net->get_signed();
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
expr_type_ = net->data_type();
|
||||
expr_width_ = net->vector_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = net->get_signed();
|
||||
break;
|
||||
}
|
||||
return expr_width_;
|
||||
}
|
||||
@@ -3012,8 +3302,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t ntype, unsigned) const
|
||||
ivl_type_t ntype, unsigned flags) const
|
||||
{
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
NetNet* net = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
@@ -3025,6 +3317,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_assert(*this, use_scope);
|
||||
}
|
||||
|
||||
if (NetExpr* tmp = elaborate_expr_class_member_(des, scope, 0, flags)) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* NetScope*found_in = */ symbol_search(this, des, use_scope, path_,
|
||||
net, par, eve,
|
||||
ex1, ex2);
|
||||
@@ -3084,7 +3380,69 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
}
|
||||
ivl_assert(*this, ntype->type_compatible(net->net_type()));
|
||||
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
const name_component_t&use_comp = path_.back();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
<< "Typed ident " << net->name()
|
||||
<< " with " << use_comp.index.size() << " indices"
|
||||
<< " and " << net->unpacked_dimensions() << " expected."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (net->unpacked_dimensions() != use_comp.index.size()) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Net " << net->name()
|
||||
<< " expects " << net->unpacked_dimensions()
|
||||
<< ", but got " << use_comp.index.size() << "."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (net->unpacked_dimensions() == 0) {
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Convert a set of index expressions to a single expression
|
||||
// that addresses the canonical element.
|
||||
list<NetExpr*>unpacked_indices;
|
||||
list<long> unpacked_indices_const;
|
||||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
use_comp.index, net->unpacked_dimensions(),
|
||||
need_const, net->unpacked_count(),
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
|
||||
if (idx_flags.invalid) {
|
||||
// Nothing to do
|
||||
|
||||
} else if (idx_flags.undefined) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "returning 'bx for undefined array access "
|
||||
<< net->name() << as_indices(unpacked_indices)
|
||||
<< "." << endl;
|
||||
|
||||
} else if (idx_flags.variable) {
|
||||
ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices);
|
||||
|
||||
} else {
|
||||
ivl_assert(*this, unpacked_indices_const.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices_const);
|
||||
}
|
||||
|
||||
ivl_assert(*this, canon_index);
|
||||
NetESignal*tmp = new NetESignal(net, canon_index);
|
||||
tmp->set_line(*this);
|
||||
|
||||
return tmp;
|
||||
@@ -3106,19 +3464,24 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
||||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
const netclass_t*class_type = scope->parent()->class_def();
|
||||
const netclass_t*class_type = find_class_containing_scope(*this, scope);
|
||||
if (class_type == 0)
|
||||
return 0;
|
||||
|
||||
perm_string member_name = peek_tail_name(path_);
|
||||
const name_component_t&name_comp = path_.back();
|
||||
|
||||
perm_string member_name = name_comp.name;
|
||||
int pidx = class_type->property_idx_from_name(member_name);
|
||||
if (pidx < 0)
|
||||
return 0;
|
||||
|
||||
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
|
||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||
ivl_assert(*this, scope_method);
|
||||
|
||||
NetNet*this_net = scope_method->find_signal(perm_string::literal("@"));
|
||||
if (this_net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unable to find 'this' port of " << scope_path(scope)
|
||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||
<< "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -3128,7 +3491,8 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
||||
<< "Found member " << member_name
|
||||
<< " is a member of class " << class_type->get_name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
<< ", so synthesizing a NetEProperty." << endl;
|
||||
<< ", type=" << *class_type->get_prop_type(pidx)
|
||||
<< ", so making a NetEProperty." << endl;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
@@ -3144,11 +3508,98 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
||||
return class_static_property_expression(this, class_type, member_name);
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(this_net, member_name);
|
||||
NetExpr*canon_index = 0;
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
|
||||
const std::vector<netrange_t>&dims = tmp_ua->static_dimensions();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " has " << dims.size() << " dimensions, "
|
||||
<< " got " << name_comp.index.size() << " indices." << endl;
|
||||
}
|
||||
|
||||
if (dims.size() != name_comp.index.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << name_comp.index.size() << " indices, "
|
||||
<< "expecting " << dims.size()
|
||||
<< " to index the property " << class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else {
|
||||
|
||||
canon_index = make_canonical_index(des, scope, this,
|
||||
name_comp.index, tmp_ua, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate && canon_index) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " canonical index: " << *canon_index << endl;
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(this_net, member_name, canon_index);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
unsigned, unsigned) const
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
return 0;
|
||||
if (path_.size() < 2)
|
||||
return 0;
|
||||
|
||||
pform_name_t use_path = path_;
|
||||
perm_string member_name = peek_tail_name(path_);
|
||||
use_path.pop_back();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: "
|
||||
<< "Try to find method=" << member_name
|
||||
<< " of signal " << use_path << endl;
|
||||
}
|
||||
|
||||
NetNet*net = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent*eve = 0;
|
||||
const NetExpr*ex1 = 0, *ex2 = 0;
|
||||
symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2);
|
||||
if (net == 0) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: "
|
||||
<< "Only nets can have methods, so give up here." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (net->darray_type()) {
|
||||
if (member_name == "size") {
|
||||
NetESFunc*fun = new NetESFunc("$size", IVL_VT_BOOL, 32, 1);
|
||||
fun->set_line(*this);
|
||||
|
||||
NetESignal*arg = new NetESignal(net);
|
||||
arg->set_line(*net);
|
||||
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: "
|
||||
<< "Give up trying to find method " << member_name
|
||||
<< " of " << path_ << "." << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate an identifier in an expression. The identifier can be a
|
||||
* parameter name, a signal name or a memory name. It can also be a
|
||||
@@ -3209,6 +3660,14 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_assert(*this, use_scope);
|
||||
}
|
||||
|
||||
// Special case: Detect the special situation that the name is
|
||||
// a method of an object (including built-in methods) that has
|
||||
// no arguments. For example, "foo.size" is the call to the
|
||||
// size() method if foo is an array type.
|
||||
if (NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid, flags)) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetScope*found_in = symbol_search(this, des, use_scope, path_,
|
||||
net, par, eve,
|
||||
ex1, ex2);
|
||||
@@ -3917,6 +4376,8 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_assert(*this, use_sel != index_component_t::SEL_BIT_LAST);
|
||||
|
||||
if (use_sel == index_component_t::SEL_BIT)
|
||||
return elaborate_expr_param_bit_(des, scope, par, found_in,
|
||||
par_msb, par_lsb, need_const);
|
||||
@@ -4028,7 +4489,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, net->unpacked_dimensions(),
|
||||
need_const,
|
||||
need_const, net->unpacked_count(),
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
@@ -4633,6 +5094,18 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||
return res;
|
||||
}
|
||||
|
||||
if (net->sig()->data_type() == IVL_VT_STRING) {
|
||||
// Special case: This is a select of a string.
|
||||
// This should be interpreted as a byte select.
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Bit select of a string becomes NetESelect." << endl;
|
||||
}
|
||||
NetESelect*res = new NetESelect(net, mux, 8);
|
||||
res->set_line(*net);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Non-constant bit select? punt and make a subsignal
|
||||
// device to mux the bit in the net. This is a fairly
|
||||
// complicated task because we need to generate
|
||||
@@ -4645,6 +5118,29 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||
return ss;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*, NetScope*,
|
||||
NetESignal*net,
|
||||
NetScope* /* found_in */,
|
||||
bool need_const) const
|
||||
{
|
||||
if (need_const) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Expression with \"[$]\" is not constant." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned use_width = 1;
|
||||
if (const netdarray_t*darray = net->sig()->darray_type()) {
|
||||
use_width = darray->element_width();
|
||||
}
|
||||
|
||||
NetELast*mux = new NetELast(net->sig());
|
||||
mux->set_line(*this);
|
||||
NetESelect*ss = new NetESelect(net, mux, use_width);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
|
||||
NetNet*net, NetScope*found_in,
|
||||
unsigned expr_wid,
|
||||
@@ -4697,6 +5193,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
|
||||
return elaborate_expr_net_bit_(des, scope, node, found_in,
|
||||
need_const);
|
||||
|
||||
if (use_sel == index_component_t::SEL_BIT_LAST)
|
||||
return elaborate_expr_net_bit_last_(des, scope, node, found_in,
|
||||
need_const);
|
||||
|
||||
// It's not anything else, so this must be a simple identifier
|
||||
// expression with no part or bit select. Return the signal
|
||||
// itself as the expression.
|
||||
@@ -4775,6 +5275,8 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
|
||||
const netclass_t*ctype,
|
||||
NetExpr*obj, unsigned /*flags*/) const
|
||||
{
|
||||
ivl_assert(*this, ctype);
|
||||
|
||||
// If there is an initializer function, then pass the object
|
||||
// through that function first. Note that the initializer
|
||||
// function has no arguments other than the object itself.
|
||||
@@ -4812,6 +5314,12 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
|
||||
|
||||
|
||||
NetFuncDef*def = new_scope->func_def();
|
||||
if (def == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Scope " << scope_path(new_scope)
|
||||
<< " is missing constructor definition." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
ivl_assert(*this, def);
|
||||
|
||||
// Are there too many arguments passed to the function. If so,
|
||||
@@ -4957,10 +5465,23 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode)
|
||||
expr_width_ = integer_width;
|
||||
mode = UNSIZED;
|
||||
} else if (mode < LOSSLESS) {
|
||||
mode = LOSSLESS;
|
||||
if (expr_width_ < integer_width) {
|
||||
expr_width_ = integer_width;
|
||||
if (mode < UNSIZED)
|
||||
mode = UNSIZED;
|
||||
} else {
|
||||
mode = LOSSLESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PENumber::test_width: "
|
||||
<< "Value=" << *value_
|
||||
<< ", width=" << expr_width_
|
||||
<< ", output mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
|
||||
+83
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -27,6 +27,7 @@
|
||||
# include "netstruct.h"
|
||||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netparray.h"
|
||||
# include "netvector.h"
|
||||
# include "compiler.h"
|
||||
# include <cstdlib>
|
||||
@@ -201,6 +202,11 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
NetEvent* eve = 0;
|
||||
perm_string method_name;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval: "
|
||||
<< "Elaborate l-value ident expression: " << *this << endl;
|
||||
}
|
||||
|
||||
/* Try to detect the special case that we are in a method and
|
||||
the identifier is a member of the class. */
|
||||
if (NetAssign_*tmp = elaborate_lval_method_class_member_(des, scope))
|
||||
@@ -259,6 +265,13 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
}
|
||||
|
||||
ivl_assert(*this, reg);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval: "
|
||||
<< "Found l-value as reg."
|
||||
<< " unpacked_dimensions()=" << reg->unpacked_dimensions() << endl;
|
||||
}
|
||||
|
||||
// We are processing the tail of a string of names. For
|
||||
// example, the verilog may be "a.b.c", so we are processing
|
||||
// "c" at this point. (Note that if method_name is not nil,
|
||||
@@ -385,23 +398,49 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
||||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
const netclass_t*class_type = scope->parent()->class_def();
|
||||
const netclass_t*class_type = find_class_containing_scope(*this, scope);
|
||||
if (class_type == 0)
|
||||
return 0;
|
||||
|
||||
perm_string member_name = peek_tail_name(path_);
|
||||
const name_component_t&name_comp = path_.back();
|
||||
|
||||
perm_string member_name = name_comp.name;
|
||||
int pidx = class_type->property_idx_from_name(member_name);
|
||||
if (pidx < 0)
|
||||
return 0;
|
||||
|
||||
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
|
||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||
ivl_assert(*this, scope_method);
|
||||
|
||||
NetNet*this_net = scope_method->find_signal(perm_string::literal("@"));
|
||||
if (this_net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unable to find 'this' port of " << scope_path(scope)
|
||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||
<< "." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Ident " << member_name
|
||||
<< " is a property of class " << class_type->get_name() << endl;
|
||||
}
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
if (! name_comp.index.empty()) {
|
||||
ivl_type_t property_type = class_type->get_prop_type(pidx);
|
||||
|
||||
if (const netsarray_t* stype = dynamic_cast<const netsarray_t*> (property_type)) {
|
||||
canon_index = make_canonical_index(des, scope, this,
|
||||
name_comp.index, stype, false);
|
||||
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Index expressions don't apply to this type of property." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect assignment to constant properties. Note that the
|
||||
// initializer constructor MAY assign to constant properties,
|
||||
// as this is how the property gets its value.
|
||||
@@ -436,8 +475,34 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
||||
}
|
||||
}
|
||||
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
|
||||
const std::vector<netrange_t>&dims = tmp_ua->static_dimensions();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " has " << dims.size() << " dimensions, "
|
||||
<< " got " << name_comp.index.size() << " indices." << endl;
|
||||
if (canon_index) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Canonical index is:" << *canon_index << endl;
|
||||
};
|
||||
}
|
||||
|
||||
if (dims.size() != name_comp.index.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << name_comp.index.size() << " indices, "
|
||||
<< "expecting " << dims.size()
|
||||
<< " to index the property " << class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
NetAssign_*this_lval = new NetAssign_(this_net);
|
||||
this_lval->set_property(member_name);
|
||||
if (canon_index) this_lval->set_word(canon_index);
|
||||
|
||||
return this_lval;
|
||||
}
|
||||
@@ -450,6 +515,11 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_word_: "
|
||||
<< "Handle as n-dimensional array." << endl;
|
||||
}
|
||||
|
||||
if (name_tail.index.size() < reg->unpacked_dimensions()) {
|
||||
cerr << get_fileline() << ": error: Array " << reg->name()
|
||||
<< " needs " << reg->unpacked_dimensions() << " indices,"
|
||||
@@ -458,6 +528,8 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned array_need_words = reg->unpacked_count();
|
||||
|
||||
// Make sure there are enough indices to address an array element.
|
||||
const index_component_t&index_head = name_tail.index.front();
|
||||
if (index_head.sel == index_component_t::SEL_PART) {
|
||||
@@ -475,7 +547,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, reg->unpacked_dimensions(),
|
||||
false,
|
||||
false, array_need_words,
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
@@ -517,6 +589,11 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
canon_index = new NetEConst(verinum(verinum::Vx));
|
||||
canon_index->set_line(*this);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_word_: "
|
||||
<< "canon_index=" << *canon_index << endl;
|
||||
}
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Unable to assign words of unresolved wire array." << endl;
|
||||
|
||||
+1
-1
@@ -630,7 +630,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
path_tail.index, sig->unpacked_dimensions(),
|
||||
true,
|
||||
true, sig->unpacked_count(),
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
+249
-68
@@ -168,7 +168,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
assert(enum_type->range->size() == 1);
|
||||
pform_range_t&range = enum_type->range->front();
|
||||
NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1);
|
||||
NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1);
|
||||
NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1);
|
||||
|
||||
long msb = 0;
|
||||
rc_flag = eval_as_long(msb, msb_ex);
|
||||
@@ -177,8 +177,11 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
rc_flag = eval_as_long(lsb, lsb_ex);
|
||||
assert(rc_flag);
|
||||
|
||||
netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag,
|
||||
msb, lsb, enum_type->names->size());
|
||||
netenum_t*use_enum = new netenum_t(enum_type->base_type,
|
||||
enum_type->signed_flag,
|
||||
enum_type->integer_flag, msb, lsb,
|
||||
enum_type->names->size(),
|
||||
enum_type);
|
||||
|
||||
use_enum->set_line(enum_type->li);
|
||||
if (scope)
|
||||
@@ -186,26 +189,32 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
else
|
||||
des->add_enumeration_set(enum_type, use_enum);
|
||||
|
||||
verinum cur_value (0);
|
||||
verinum one_value (1);
|
||||
size_t name_idx = 0;
|
||||
// Find the minimum and maximum allowed enumeration values.
|
||||
// Find the enumeration width.
|
||||
long raw_width = use_enum->packed_width();
|
||||
assert(raw_width > 0);
|
||||
unsigned enum_width = (unsigned)raw_width;
|
||||
// Define the default start value and the increment value to be the
|
||||
// correct type for this enumeration.
|
||||
verinum cur_value ((uint64_t)0, enum_width);
|
||||
cur_value.has_sign(enum_type->signed_flag);
|
||||
verinum one_value ((uint64_t)1, enum_width);
|
||||
one_value.has_sign(enum_type->signed_flag);
|
||||
// Find the maximum allowed enumeration value.
|
||||
verinum min_value (0);
|
||||
verinum max_value (0);
|
||||
if (enum_type->signed_flag) {
|
||||
min_value = -pow(verinum(2), verinum(use_enum->packed_width()-1));
|
||||
max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) -
|
||||
one_value;
|
||||
min_value = -pow(verinum(2), verinum(enum_width-1));
|
||||
max_value = pow(verinum(2), verinum(enum_width-1)) - one_value;
|
||||
} else {
|
||||
max_value = pow(verinum(2), verinum(use_enum->packed_width())) -
|
||||
one_value;
|
||||
max_value = pow(verinum(2), verinum(enum_width)) - one_value;
|
||||
}
|
||||
min_value.has_sign(true);
|
||||
max_value.has_sign(enum_type->signed_flag);
|
||||
// Process the enumeration definition.
|
||||
for (list<named_pexpr_t>::const_iterator cur = enum_type->names->begin()
|
||||
; cur != enum_type->names->end() ; ++ cur, name_idx += 1) {
|
||||
|
||||
|
||||
// Check to see if the enumeration name has a value given.
|
||||
if (cur->parm) {
|
||||
// There is an explicit value. elaborate/evaluate
|
||||
// the value and assign it to the enumeration name.
|
||||
@@ -213,37 +222,140 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
|
||||
if (val_const == 0) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration expression is not "
|
||||
"constant." << endl;
|
||||
<< ": error: Enumeration expression for "
|
||||
<< cur->name <<" is not an integer constant."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
cur_value = val_const->value();
|
||||
|
||||
// A 2-state value can not have a constant with X/Z bits.
|
||||
if (enum_type->base_type==IVL_VT_BOOL &&
|
||||
! cur_value.is_defined()) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " cannot have an undefined value." << endl;
|
||||
<< " can not have an undefined value." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
// If this is a literal constant and it has a defined
|
||||
// width then the width must match the enumeration width.
|
||||
if (PENumber *tmp = dynamic_cast<PENumber*>(cur->parm)) {
|
||||
if (tmp->value().has_len() &&
|
||||
(tmp->value().len() != enum_width)) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " has an incorrectly sized constant."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are padding/truncating a negative value for an
|
||||
// unsigned enumeration that is an error or if the new
|
||||
// value does not have a defined width.
|
||||
if (((cur_value.len() != enum_width) ||
|
||||
! cur_value.has_len()) &&
|
||||
! enum_type->signed_flag && cur_value.is_negative()) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " has a negative value." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
// Narrower values need to be padded to the width of the
|
||||
// enumeration and defined to have the specified width.
|
||||
if (cur_value.len() < enum_width) {
|
||||
cur_value = pad_to_width(cur_value, enum_width);
|
||||
}
|
||||
|
||||
// Some wider values can be truncated.
|
||||
if (cur_value.len() > enum_width) {
|
||||
unsigned check_width = enum_width - 1;
|
||||
// Check that the upper bits match the MSB
|
||||
for (unsigned idx = enum_width;
|
||||
idx < cur_value.len();
|
||||
idx += 1) {
|
||||
if (cur_value[idx] != cur_value[check_width]) {
|
||||
// If this is an unsigned enumeration
|
||||
// then zero padding is okay.
|
||||
if (! enum_type->signed_flag &&
|
||||
(idx == enum_width) &&
|
||||
(cur_value[idx] == verinum::V0)) {
|
||||
check_width += 1;
|
||||
continue;
|
||||
}
|
||||
if (cur_value.is_defined()) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name "
|
||||
<< cur->name
|
||||
<< " has a value that is too "
|
||||
<< ((cur_value > max_value) ?
|
||||
"large" : "small")
|
||||
<< " " << cur_value << "."
|
||||
<< endl;
|
||||
} else {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name "
|
||||
<< cur->name
|
||||
<< " has trimmed bits that do "
|
||||
<< "not match the enumeration "
|
||||
<< "MSB: " << cur_value << "."
|
||||
<< endl;
|
||||
}
|
||||
des->errors += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If this is an unsigned value then make sure
|
||||
// The upper bits are not 1.
|
||||
if (! cur_value.has_sign() &&
|
||||
(cur_value[enum_width] == verinum::V1)) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name "
|
||||
<< cur->name
|
||||
<< " has a value that is too large: "
|
||||
<< cur_value << "." << endl;
|
||||
des->errors += 1;
|
||||
break;
|
||||
}
|
||||
cur_value = verinum(cur_value, enum_width);
|
||||
}
|
||||
|
||||
// At this point the value has the correct size and needs
|
||||
// to have the correct sign attribute set.
|
||||
cur_value.has_len(true);
|
||||
cur_value.has_sign(enum_type->signed_flag);
|
||||
|
||||
} else if (! cur_value.is_defined()) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " cannot have an undefined inferred value." << endl;
|
||||
<< " has an undefined inferred value." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cast any undefined bits to zero so the comparisons below
|
||||
// return just true (1) or false (0).
|
||||
verinum two_state_value = cur_value;
|
||||
two_state_value.cast_to_int2();
|
||||
|
||||
// The enumeration value must fit into the enumeration bits.
|
||||
if ((cur_value > max_value) ||
|
||||
(cur_value.has_sign() && (cur_value < min_value))) {
|
||||
if (!cur_value.is_defined()) {
|
||||
if (cur_value.len() > (unsigned long)use_enum->packed_width()) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " value=" << cur_value
|
||||
<< " is too wide for enumeration base type." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
} else if ((two_state_value > max_value) ||
|
||||
(cur_value.has_sign() && (two_state_value < min_value))) {
|
||||
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " cannot have a value equal to " << cur_value
|
||||
<< "." << endl;
|
||||
<< " has an inferred value that overflowed." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
@@ -257,22 +369,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
// The values are explicitly sized to the width of the
|
||||
// base type of the enumeration.
|
||||
verinum tmp_val (0);
|
||||
if (cur_value.len() < (unsigned long)use_enum->packed_width()) {
|
||||
// Pad the current value if it is narrower than the final
|
||||
// width of the enum.
|
||||
tmp_val = pad_to_width (cur_value, use_enum->packed_width());
|
||||
tmp_val.has_len(true);
|
||||
} else {
|
||||
// Truncate an oversized value. We report out of bound
|
||||
// values above. This may create duplicates.
|
||||
tmp_val = verinum(cur_value, use_enum->packed_width());
|
||||
}
|
||||
tmp_val.has_sign(enum_type->signed_flag);
|
||||
|
||||
rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val);
|
||||
rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value);
|
||||
if (scope)
|
||||
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
||||
else
|
||||
@@ -287,8 +384,9 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
|
||||
// In case the next name has an implicit value,
|
||||
// increment the current value by one.
|
||||
if (cur_value.is_defined())
|
||||
if (cur_value.is_defined()) {
|
||||
cur_value = cur_value + one_value;
|
||||
}
|
||||
}
|
||||
|
||||
use_enum->insert_name_close();
|
||||
@@ -416,6 +514,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
||||
|
||||
netclass_t*use_base_class = 0;
|
||||
if (base_class) {
|
||||
ivl_assert(*pclass, scope);
|
||||
use_base_class = scope->find_class(base_class->name);
|
||||
if (use_base_class == 0) {
|
||||
cerr << pclass->get_fileline() << ": error: "
|
||||
@@ -427,6 +526,9 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
||||
|
||||
netclass_t*use_class = new netclass_t(use_type->name, use_base_class);
|
||||
|
||||
ivl_assert(*pclass, use_type->save_elaborated_type == 0);
|
||||
use_type->save_elaborated_type = use_class;
|
||||
|
||||
// Class scopes have no parent scope, because references are
|
||||
// not allowed to escape a class method.
|
||||
NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()),
|
||||
@@ -434,18 +536,22 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
||||
class_scope->set_line(pclass);
|
||||
class_scope->set_class_def(use_class);
|
||||
use_class->set_class_scope(class_scope);
|
||||
use_class->set_definition_scope(scope);
|
||||
|
||||
// Collect the properties, elaborate them, and add them to the
|
||||
// elaborated class definition.
|
||||
for (map<perm_string, class_type_t::prop_info_t>::iterator cur = use_type->properties.begin()
|
||||
; cur != use_type->properties.end() ; ++ cur) {
|
||||
if (debug_scopes) {
|
||||
cerr << pclass->get_fileline() << ": elaborate_scope_class: "
|
||||
<< " Property " << cur->first << endl;
|
||||
}
|
||||
|
||||
ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope);
|
||||
ivl_assert(*pclass, tmp);
|
||||
if (debug_scopes) {
|
||||
cerr << pclass->get_fileline() << ": elaborate_scope_class: "
|
||||
<< " Property " << cur->first
|
||||
<< " type=" << *tmp << endl;
|
||||
}
|
||||
use_class->set_property(cur->first, cur->second.qual, tmp);
|
||||
|
||||
}
|
||||
|
||||
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()
|
||||
@@ -484,7 +590,12 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
||||
cur->second->elaborate_scope(des, method_scope);
|
||||
}
|
||||
|
||||
scope->add_class(use_class);
|
||||
if (scope) {
|
||||
scope->add_class(use_class);
|
||||
|
||||
} else {
|
||||
des->add_class(use_class, pclass);
|
||||
}
|
||||
}
|
||||
|
||||
static void elaborate_scope_classes(Design*des, NetScope*scope,
|
||||
@@ -496,6 +607,18 @@ static void elaborate_scope_classes(Design*des, NetScope*scope,
|
||||
}
|
||||
}
|
||||
|
||||
void elaborate_rootscope_classes(Design*des)
|
||||
{
|
||||
if (pform_classes.empty())
|
||||
return;
|
||||
|
||||
for (map<perm_string,PClass*>::iterator cur = pform_classes.begin()
|
||||
; cur != pform_classes.end() ; ++ cur) {
|
||||
blend_class_constructors(cur->second);
|
||||
elaborate_scope_class(des, 0, cur->second);
|
||||
}
|
||||
}
|
||||
|
||||
static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,
|
||||
const Module::replace_t&replacements)
|
||||
{
|
||||
@@ -537,6 +660,25 @@ static void elaborate_scope_events_(Design*des, NetScope*scope,
|
||||
}
|
||||
}
|
||||
|
||||
static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task)
|
||||
{
|
||||
hname_t use_name( task->pscope_name() );
|
||||
|
||||
NetScope*task_scope = new NetScope(scope, use_name, NetScope::TASK);
|
||||
task_scope->is_auto(task->is_auto());
|
||||
task_scope->set_line(task);
|
||||
|
||||
if (scope==0)
|
||||
des->add_root_task(task_scope, task);
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << task->get_fileline() << ": elaborate_scope_task: "
|
||||
<< "Elaborate task scope " << scope_path(task_scope) << endl;
|
||||
}
|
||||
|
||||
task->elaborate_scope(des, task_scope);
|
||||
}
|
||||
|
||||
static void elaborate_scope_tasks(Design*des, NetScope*scope,
|
||||
const map<perm_string,PTask*>&tasks)
|
||||
{
|
||||
@@ -578,19 +720,30 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetScope*task_scope = new NetScope(scope, use_name,
|
||||
NetScope::TASK);
|
||||
task_scope->is_auto((*cur).second->is_auto());
|
||||
task_scope->set_line((*cur).second);
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << cur->second->get_fileline() << ": debug: "
|
||||
<< "Elaborate task scope " << scope_path(task_scope) << endl;
|
||||
(*cur).second->elaborate_scope(des, task_scope);
|
||||
elaborate_scope_task(des, scope, cur->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task)
|
||||
{
|
||||
hname_t use_name( task->pscope_name() );
|
||||
|
||||
NetScope*task_scope = new NetScope(scope, use_name, NetScope::FUNC);
|
||||
task_scope->is_auto(task->is_auto());
|
||||
task_scope->set_line(task);
|
||||
|
||||
if (scope==0)
|
||||
des->add_root_task(task_scope, task);
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << task->get_fileline() << ": elaborate_scope_func: "
|
||||
<< "Elaborate task scope " << scope_path(task_scope) << endl;
|
||||
}
|
||||
|
||||
task->elaborate_scope(des, task_scope);
|
||||
}
|
||||
|
||||
static void elaborate_scope_funcs(Design*des, NetScope*scope,
|
||||
const map<perm_string,PFunction*>&funcs)
|
||||
{
|
||||
@@ -633,19 +786,33 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetScope*func_scope = new NetScope(scope, use_name,
|
||||
NetScope::FUNC);
|
||||
func_scope->is_auto((*cur).second->is_auto());
|
||||
func_scope->set_line((*cur).second);
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << cur->second->get_fileline() << ": debug: "
|
||||
<< "Elaborate function scope " << scope_path(func_scope) << endl;
|
||||
(*cur).second->elaborate_scope(des, func_scope);
|
||||
elaborate_scope_func(des, scope, cur->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void elaborate_rootscope_tasks(Design*des)
|
||||
{
|
||||
for (map<perm_string,PTaskFunc*>::iterator cur = pform_tasks.begin()
|
||||
; cur != pform_tasks.end() ; ++ cur) {
|
||||
|
||||
if (PTask*task = dynamic_cast<PTask*> (cur->second)) {
|
||||
elaborate_scope_task(des, 0, task);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PFunction*func = dynamic_cast<PFunction*>(cur->second)) {
|
||||
elaborate_scope_func(des, 0, func);
|
||||
continue;
|
||||
}
|
||||
|
||||
cerr << cur->second->get_fileline() << ": internal error: "
|
||||
<< "elabortae_rootscope_tasks does not understand "
|
||||
<< "this object," << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
class generate_schemes_work_item_t : public elaborator_work_item_t {
|
||||
public:
|
||||
generate_schemes_work_item_t(Design*des__, NetScope*scope, Module*mod)
|
||||
@@ -681,12 +848,14 @@ class generate_schemes_work_item_t : public elaborator_work_item_t {
|
||||
bool PPackage::elaborate_scope(Design*des, NetScope*scope)
|
||||
{
|
||||
if (debug_scopes) {
|
||||
cerr << get_fileline() << ": debug: Elaborate package scope "
|
||||
<< scope_path(scope) << "." << endl;
|
||||
cerr << get_fileline() << ": PPackage::elaborate_scope: "
|
||||
<< "Elaborate package " << scope_path(scope) << "." << endl;
|
||||
}
|
||||
|
||||
collect_scope_parameters_(des, scope, parameters);
|
||||
collect_scope_localparams_(des, scope, localparams);
|
||||
elaborate_scope_enumerations(des, scope, enum_sets);
|
||||
elaborate_scope_classes(des, scope, classes_lexical);
|
||||
elaborate_scope_funcs(des, scope, funcs);
|
||||
elaborate_scope_tasks(des, scope, tasks);
|
||||
return true;
|
||||
@@ -696,8 +865,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
const replace_t&replacements)
|
||||
{
|
||||
if (debug_scopes) {
|
||||
cerr << get_fileline() << ": debug: Elaborate scope "
|
||||
<< scope_path(scope) << "." << endl;
|
||||
cerr << get_fileline() << ": Module::elaborate_scope: "
|
||||
<< "Elaborate " << scope_path(scope) << "." << endl;
|
||||
}
|
||||
|
||||
// Add the genvars to the scope.
|
||||
@@ -747,7 +916,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
delete[]attr;
|
||||
|
||||
// Generate schemes need to have their scopes elaborated, but
|
||||
// we cannot do that until defparams are run, so push it off
|
||||
// we can not do that until defparams are run, so push it off
|
||||
// into an elaborate work item.
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
@@ -1489,7 +1658,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||
continue;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: You cannot instantiate "
|
||||
cerr << get_fileline() << ": error: You can not instantiate "
|
||||
<< "module " << mod->mod_name() << " within itself." << endl;
|
||||
cerr << get_fileline() << ": : The offending instance is "
|
||||
<< get_name() << " within " << scope_path(scn) << "." << endl;
|
||||
@@ -1890,6 +2059,18 @@ void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* The standard says that we create an implicit scope for foreach
|
||||
* loops, but that is just to hold the index variables, and we'll
|
||||
* handle them by creating unique names. So just jump into the
|
||||
* contained statement for scope elaboration.
|
||||
*/
|
||||
void PForeach::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
|
||||
+70
-80
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -41,6 +41,7 @@
|
||||
# include "netvector.h"
|
||||
# include "netdarray.h"
|
||||
# include "netparray.h"
|
||||
# include "netqueue.h"
|
||||
# include "util.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
@@ -206,6 +207,11 @@ bool PPackage::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PPackage::elaborate_sig: "
|
||||
<< "Start package scope=" << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
flag = elaborate_sig_wires_(des, scope) && flag;
|
||||
|
||||
// After all the wires are elaborated, we are free to
|
||||
@@ -214,6 +220,13 @@ bool PPackage::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
elaborate_sig_funcs(des, scope, funcs);
|
||||
elaborate_sig_tasks(des, scope, tasks);
|
||||
elaborate_sig_classes(des, scope, classes);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PPackage::elaborate_sig: "
|
||||
<< "Done package scope=" << scope_path(scope)
|
||||
<< ", flag=" << flag << endl;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
@@ -584,7 +597,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||
if (dynamic_cast<const struct void_type_t*> (return_type_)) {
|
||||
ret_type = 0;
|
||||
} else {
|
||||
ret_type = return_type_->elaborate_type(des, scope);
|
||||
ret_type = return_type_->elaborate_type(des, scope->parent());
|
||||
ivl_assert(*this, ret_type);
|
||||
}
|
||||
} else {
|
||||
@@ -597,7 +610,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PFunction::elaborate_sig: "
|
||||
<< "return type: " << *ret_type << endl;
|
||||
return_type_->pform_dump(cerr, 8);
|
||||
if (return_type_)
|
||||
return_type_->pform_dump(cerr, 8);
|
||||
}
|
||||
list<netrange_t> ret_unpacked;
|
||||
ret_sig = new NetNet(scope, fname, NetNet::REG, ret_unpacked, ret_type);
|
||||
@@ -805,6 +819,12 @@ void PEventStatement::elaborate_sig(Design*des, NetScope*scope) const
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PForeach::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PForever::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
@@ -829,55 +849,6 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
static bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
vector<netrange_t>&llist,
|
||||
const list<pform_range_t>&rlist)
|
||||
{
|
||||
bool bad_msb = false, bad_lsb = false;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = rlist.begin()
|
||||
; cur != rlist.end() ; ++cur) {
|
||||
long use_msb, use_lsb;
|
||||
|
||||
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
|
||||
if (! eval_as_long(use_msb, texpr)) {
|
||||
cerr << cur->first->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->first->get_fileline() << " : "
|
||||
"This MSB expression violates the rule: "
|
||||
<< *cur->first << endl;
|
||||
des->errors += 1;
|
||||
bad_msb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
texpr = elab_and_eval(des, scope, cur->second, -1, true);
|
||||
if (! eval_as_long(use_lsb, texpr)) {
|
||||
cerr << cur->second->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->second->get_fileline() << " : "
|
||||
"This LSB expression violates the rule: "
|
||||
<< *cur->second << endl;
|
||||
des->errors += 1;
|
||||
bad_lsb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
llist.push_back(netrange_t(use_msb, use_lsb));
|
||||
}
|
||||
|
||||
return bad_msb | bad_lsb;
|
||||
}
|
||||
|
||||
static netclass_t* locate_class_type(Design*, NetScope*scope,
|
||||
class_type_t*class_type)
|
||||
{
|
||||
netclass_t*use_class = scope->find_class(class_type->name);
|
||||
return use_class;
|
||||
}
|
||||
|
||||
static ivl_type_s*elaborate_type(Design*des, NetScope*scope,
|
||||
data_type_t*pform_type)
|
||||
{
|
||||
@@ -1025,10 +996,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
<< ". Now check for consistency." << endl;
|
||||
}
|
||||
|
||||
/* If we find errors here, then give up on this signal. */
|
||||
if (bad_range)
|
||||
return 0;
|
||||
|
||||
/* We have a port size error */
|
||||
if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) {
|
||||
|
||||
@@ -1084,7 +1051,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
|
||||
list<netrange_t>unpacked_dimensions;
|
||||
netdarray_t*netarray = 0;
|
||||
netdarray_t*netdarray = 0;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
|
||||
; cur != unpacked_.end() ; ++cur) {
|
||||
@@ -1097,13 +1064,23 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
if (use_lidx==0 && use_ridx==0) {
|
||||
netvector_t*vec = new netvector_t(packed_dimensions, data_type_);
|
||||
packed_dimensions.clear();
|
||||
ivl_assert(*this, netarray==0);
|
||||
netarray = new netdarray_t(vec);
|
||||
ivl_assert(*this, netdarray==0);
|
||||
netdarray = new netdarray_t(vec);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Special case: Detect the mark for a QUEUE
|
||||
// declaration, which is the dimensions [null:<nil>].
|
||||
if (use_ridx==0 && dynamic_cast<PENull*>(use_lidx)) {
|
||||
netvector_t*vec = new netvector_t(packed_dimensions, data_type_);
|
||||
packed_dimensions.clear();
|
||||
ivl_assert(*this, netdarray==0);
|
||||
netdarray = new netqueue_t(vec);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot handle dynamic arrays of arrays yet.
|
||||
ivl_assert(*this, netarray==0);
|
||||
ivl_assert(*this, netdarray==0);
|
||||
ivl_assert(*this, use_lidx && use_ridx);
|
||||
|
||||
NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true);
|
||||
@@ -1196,22 +1173,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
// should already have been elaborated. All we need to
|
||||
// do right now is locate the netclass_t object for the
|
||||
// class, and use that to build the net.
|
||||
netclass_t*use_type = locate_class_type(des, scope, class_type);
|
||||
if (use_type == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Class " << class_type->name
|
||||
<< " isn't elaborated in scope=" << scope_path(scope) << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
ivl_assert(*this, use_type);
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Create class instance signal " << wtype
|
||||
<< " " << name_ << endl;
|
||||
}
|
||||
// (No arrays of classes)
|
||||
list<netrange_t> use_unpacked;
|
||||
sig = new NetNet(scope, name_, wtype, use_unpacked, use_type);
|
||||
|
||||
ivl_assert(*this, class_type->save_elaborated_type);
|
||||
netclass_t*use_type = class_type->save_elaborated_type;
|
||||
|
||||
sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_type);
|
||||
|
||||
} else if (struct_type_t*struct_type = dynamic_cast<struct_type_t*>(set_data_type_)) {
|
||||
// If this is a struct type, then build the net with the
|
||||
@@ -1232,7 +1198,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
} else if (enum_type_t*enum_type = dynamic_cast<enum_type_t*>(set_data_type_)) {
|
||||
list<named_pexpr_t>::const_iterator sample_name = enum_type->names->begin();
|
||||
const netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);
|
||||
const netenum_t*use_enum = scope->find_enumeration_for_name(sample_name->name);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
@@ -1246,7 +1212,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_enum);
|
||||
|
||||
|
||||
} else if (netarray) {
|
||||
} else if (netdarray) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
@@ -1256,7 +1222,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
ivl_assert(*this, packed_dimensions.empty());
|
||||
ivl_assert(*this, unpacked_dimensions.empty());
|
||||
sig = new NetNet(scope, name_, wtype, netarray);
|
||||
sig = new NetNet(scope, name_, wtype, netdarray);
|
||||
|
||||
} else if (parray_type_t*parray_type = dynamic_cast<parray_type_t*>(set_data_type_)) {
|
||||
// The pform gives us a parray_type_t for packed arrays
|
||||
@@ -1272,7 +1238,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
<< " parray=" << use_type->packed_dimensions()
|
||||
<< " parray=" << use_type->static_dimensions()
|
||||
<< " " << name_ << unpacked_dimensions
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
@@ -1327,3 +1293,27 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
||||
void Design::root_elaborate_sig(void)
|
||||
{
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++ cur) {
|
||||
|
||||
netclass_t*cur_class = cur->second;
|
||||
PClass*cur_pclass = class_to_pclass_[cur_class];
|
||||
|
||||
cur_class->elaborate_sig(this, cur_pclass);
|
||||
}
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << cur->second->get_fileline() << ": root_elaborate_sig: "
|
||||
<< "Elaborate_sig for root task/func " << scope_path(cur->first) << endl;
|
||||
}
|
||||
|
||||
cur->second->elaborate_sig(this, cur->first);
|
||||
}
|
||||
}
|
||||
|
||||
+47
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -22,6 +22,7 @@
|
||||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netenum.h"
|
||||
# include "netparray.h"
|
||||
# include "netscalar.h"
|
||||
# include "netstruct.h"
|
||||
# include "netvector.h"
|
||||
@@ -37,8 +38,12 @@ using namespace std;
|
||||
*/
|
||||
ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope)
|
||||
{
|
||||
map<NetScope*,ivl_type_s*>::iterator pos = cache_type_elaborate_.lower_bound(scope);
|
||||
if (pos->first == scope)
|
||||
Definitions*use_definitions = scope;
|
||||
if (use_definitions == 0)
|
||||
use_definitions = des;
|
||||
|
||||
map<Definitions*,ivl_type_s*>::iterator pos = cache_type_elaborate_.lower_bound(use_definitions);
|
||||
if (pos->first == use_definitions)
|
||||
return pos->second;
|
||||
|
||||
ivl_type_s*tmp = elaborate_type_raw(des, scope);
|
||||
@@ -90,9 +95,10 @@ ivl_type_s* atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const
|
||||
}
|
||||
}
|
||||
|
||||
ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*scope) const
|
||||
ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*) const
|
||||
{
|
||||
return scope->find_class(name);
|
||||
ivl_assert(*this, save_elaborated_type);
|
||||
return save_elaborated_type;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,18 +126,20 @@ ivl_type_s* vector_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
||||
; cur != pdims->end() ; ++ cur) {
|
||||
|
||||
NetExpr*me = elab_and_eval(des, scope, cur->first, 0, true);
|
||||
assert(me);
|
||||
|
||||
NetExpr*le = elab_and_eval(des, scope, cur->second, 0, true);
|
||||
assert(le);
|
||||
|
||||
/* If elaboration failed for either expression, we
|
||||
should have already reported the error, so just
|
||||
skip the following evaluation to recover. */
|
||||
|
||||
long mnum = 0, lnum = 0;
|
||||
if ( ! eval_as_long(mnum, me) ) {
|
||||
if ( me && ! eval_as_long(mnum, me) ) {
|
||||
assert(0);
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if ( ! eval_as_long(lnum, le) ) {
|
||||
if ( le && ! eval_as_long(lnum, le) ) {
|
||||
assert(0);
|
||||
des->errors += 1;
|
||||
}
|
||||
@@ -163,6 +171,15 @@ ivl_type_s* string_type_t::elaborate_type_raw(Design*, NetScope*) const
|
||||
return &netstring_t::type_string;
|
||||
}
|
||||
|
||||
ivl_type_s* parray_type_t::elaborate_type_raw(Design*des, NetScope*) const
|
||||
{
|
||||
cerr << get_fileline() << " : sorry: "
|
||||
<< "Packed arrays are not currently supported in this context."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
netstruct_t* struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
||||
{
|
||||
netstruct_t*res = new netstruct_t;
|
||||
@@ -203,9 +220,27 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
||||
|
||||
ivl_type_t btype = base_type->elaborate_type(des, scope);
|
||||
|
||||
assert(dims->size() == 1);
|
||||
assert(dims->size() >= 1);
|
||||
list<pform_range_t>::const_iterator cur = dims->begin();
|
||||
assert(cur->first == 0 && cur->second==0);
|
||||
ivl_type_s*res = new netdarray_t(btype);
|
||||
|
||||
// Special case: if the dimension is nil:nil, this is a
|
||||
// dynamic array. Note that we only know how to handle dynamic
|
||||
// arrays with 1 dimension at a time.
|
||||
if (cur->first==0 && cur->second==0) {
|
||||
assert(dims->size()==1);
|
||||
ivl_type_s*res = new netdarray_t(btype);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<netrange_t> dimensions;
|
||||
bool bad_range = evaluate_ranges(des, scope, dimensions, *dims);
|
||||
|
||||
if (bad_range) {
|
||||
cerr << get_fileline() << " : warning: "
|
||||
<< "Bad dimensions for type here." << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, btype);
|
||||
ivl_type_s*res = new netuarray_t(dimensions, btype);
|
||||
return res;
|
||||
}
|
||||
|
||||
+375
-13
@@ -38,8 +38,10 @@
|
||||
# include "PPackage.h"
|
||||
# include "PSpec.h"
|
||||
# include "netlist.h"
|
||||
# include "netenum.h"
|
||||
# include "netvector.h"
|
||||
# include "netdarray.h"
|
||||
# include "netparray.h"
|
||||
# include "netclass.h"
|
||||
# include "netmisc.h"
|
||||
# include "util.h"
|
||||
@@ -2290,6 +2292,14 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
|
||||
NetAssign_*lv = new NetAssign_(tmp);
|
||||
return lv;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PAssign_::elaborate_lval: "
|
||||
<< "lval_ = " << *lval_ << endl;
|
||||
cerr << get_fileline() << ": PAssign_::elaborate_lval: "
|
||||
<< "lval_ expr type = " << typeid(*lval_).name() << endl;
|
||||
}
|
||||
|
||||
return lval_->elaborate_lval(des, scope, false, false);
|
||||
}
|
||||
|
||||
@@ -2520,6 +2530,23 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||
|
||||
rv = elaborate_rval_(des, scope, use_lv_type);
|
||||
|
||||
} else if (const netuarray_t*utype = dynamic_cast<const netuarray_t*>(lv_net_type)) {
|
||||
ivl_assert(*this, lv->more==0);
|
||||
if (debug_elaborate) {
|
||||
if (lv->word())
|
||||
cerr << get_fileline() << ": PAssign::elaborate: "
|
||||
<< "lv->word() = " << *lv->word() << endl;
|
||||
else
|
||||
cerr << get_fileline() << ": PAssign::elaborate: "
|
||||
<< "lv->word() = <nil>" << endl;
|
||||
}
|
||||
ivl_type_t use_lv_type = lv_net_type;
|
||||
ivl_assert(*this, lv->word());
|
||||
use_lv_type = utype->element_type();
|
||||
|
||||
ivl_assert(*this, use_lv_type);
|
||||
rv = elaborate_rval_(des, scope, use_lv_type);
|
||||
|
||||
} else {
|
||||
/* Elaborate the r-value expression, then try to evaluate it. */
|
||||
rv = elaborate_rval_(des, scope, lv_net_type, lv->expr_type(), count_lval_width(lv));
|
||||
@@ -2642,7 +2669,8 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||
return bl;
|
||||
}
|
||||
|
||||
if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) {
|
||||
if (lv->enumeration() &&
|
||||
! lv->enumeration()->matches(rv->enumeration())) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Enumeration type mismatch in assignment." << endl;
|
||||
des->errors += 1;
|
||||
@@ -2977,10 +3005,10 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
||||
context_width = 1;
|
||||
context_unsigned = false;
|
||||
|
||||
} else if (context_mode > PExpr::SIZED) {
|
||||
} else if (context_mode >= PExpr::LOSSLESS) {
|
||||
|
||||
/* Expressions may choose a different size if they are
|
||||
in an unsized context, so we need to run through the
|
||||
in a lossless context, so we need to run through the
|
||||
process again to get the final expression width. */
|
||||
|
||||
context_width = test_case_width(des, scope, expr_, context_mode);
|
||||
@@ -3043,7 +3071,7 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
||||
|
||||
/* Iterate over all the case items (guard/statement pairs)
|
||||
elaborating them. If the guard has no expression, then this
|
||||
is a "default" cause. Otherwise, the guard has one or more
|
||||
is a "default" case. Otherwise, the guard has one or more
|
||||
expressions, and each guard is a case. */
|
||||
unsigned inum = 0;
|
||||
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
||||
@@ -3084,6 +3112,8 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
}
|
||||
|
||||
res->prune();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -3413,6 +3443,17 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||
}
|
||||
assert(def);
|
||||
|
||||
/* In SystemVerilog a method calling another method in the
|
||||
* current class needs to be elaborated as a method with an
|
||||
* implicit this added. */
|
||||
if (gn_system_verilog() && (path_.size() == 1)) {
|
||||
const NetScope *c_scope = scope->get_class_scope();
|
||||
if (c_scope && (c_scope == task->get_class_scope())) {
|
||||
NetProc *tmp = elaborate_method_(des, scope, true);
|
||||
assert(tmp);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned parm_count = def->port_count();
|
||||
|
||||
@@ -3427,7 +3468,45 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||
return elaborate_build_call_(des, scope, task, 0);
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
|
||||
/*
|
||||
* This private method is called to elaborate built-in methods. The
|
||||
* method_name is the detected name of the built-in method, and the
|
||||
* sys_task_name is the internal system-task name to use.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const
|
||||
{
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
sig->set_line(*this);
|
||||
|
||||
/* If there is a single NULL argument then ignore it since it is
|
||||
* left over from the parser and is not needed by the method. */
|
||||
unsigned nparms = parms_.size();
|
||||
if ((nparms == 1) && (parms_[0] == 0)) nparms = 0;
|
||||
|
||||
vector<NetExpr*>argv (1 + nparms);
|
||||
argv[0] = sig;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
PExpr*ex = parms_[idx];
|
||||
if (ex != 0) {
|
||||
argv[idx+1] = elab_sys_task_arg(des, scope,
|
||||
method_name,
|
||||
idx, ex);
|
||||
} else {
|
||||
argv[idx+1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv);
|
||||
sys->set_line(*this);
|
||||
return sys;
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
||||
bool add_this_flag) const
|
||||
{
|
||||
pform_name_t use_path = path_;
|
||||
perm_string method_name = peek_tail_name(use_path);
|
||||
@@ -3438,6 +3517,12 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
|
||||
NetEvent *eve;
|
||||
const NetExpr *ex1, *ex2;
|
||||
|
||||
/* Add the implicit this reference when requested. */
|
||||
if (add_this_flag) {
|
||||
assert(use_path.empty());
|
||||
use_path.push_front(name_component_t(perm_string::literal("@")));
|
||||
}
|
||||
|
||||
// There is no signal to search for so this cannot be a method.
|
||||
if (use_path.empty()) return 0;
|
||||
|
||||
@@ -3453,15 +3538,20 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
|
||||
|
||||
// Is this a delete method for dynamic arrays?
|
||||
if (net->darray_type() && method_name=="delete") {
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
return elaborate_sys_task_method_(des, scope, net,
|
||||
method_name,
|
||||
"$ivl_darray_method$delete");
|
||||
}
|
||||
|
||||
vector<NetExpr*> argv (1);
|
||||
argv[0] = sig;
|
||||
|
||||
NetSTask*sys = new NetSTask("$ivl_darray_method$delete",
|
||||
IVL_SFUNC_AS_TASK_IGNORE, argv);
|
||||
sys->set_line(*this);
|
||||
return sys;
|
||||
if (net->queue_type()) {
|
||||
if (method_name=="push_back")
|
||||
return elaborate_sys_task_method_(des, scope, net,
|
||||
method_name,
|
||||
"$ivl_queue_method$push_back");
|
||||
if (method_name=="push_front")
|
||||
return elaborate_sys_task_method_(des, scope, net,
|
||||
method_name,
|
||||
"$ivl_queue_method$push_front");
|
||||
}
|
||||
|
||||
if (const netclass_t*class_type = net->class_type()) {
|
||||
@@ -4538,6 +4628,222 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void find_property_in_class(const LineInfo&loc, const NetScope*scope, perm_string name, const netclass_t*&found_in, int&property)
|
||||
{
|
||||
found_in = find_class_containing_scope(loc, scope);
|
||||
property = -1;
|
||||
|
||||
if (found_in==0) return;
|
||||
|
||||
property = found_in->property_idx_from_name(name);
|
||||
if (property < 0) {
|
||||
found_in = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The foreach statement can be written as a for statement like so:
|
||||
*
|
||||
* for (<idx> = $low(<array>) ; <idx> <= $high(<array>) ; <idx> += 1)
|
||||
* <statement_>
|
||||
*
|
||||
* The <idx> variable is already known to be in the containing named
|
||||
* block scope, which was created by the parser.
|
||||
*/
|
||||
NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
// Locate the signal for the array variable
|
||||
pform_name_t array_name;
|
||||
array_name.push_back(name_component_t(array_var_));
|
||||
NetNet*array_sig = des->find_signal(scope, array_name);
|
||||
|
||||
// And if necessary, look for the class property that is
|
||||
// referenced.
|
||||
const netclass_t*class_scope = 0;
|
||||
int class_property = -1;
|
||||
if (array_sig == 0)
|
||||
find_property_in_class(*this, scope, array_var_, class_scope, class_property);
|
||||
|
||||
if (debug_elaborate && array_sig) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||
<< "Found array_sig in " << scope_path(array_sig->scope()) << "." << endl;
|
||||
}
|
||||
|
||||
if (debug_elaborate && class_scope) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||
<< "Found array_sig property (" << class_property
|
||||
<< ") in class " << class_scope->get_name()
|
||||
<< " as " << *class_scope->get_prop_type(class_property) << "." << endl;
|
||||
}
|
||||
|
||||
if (class_scope!=0 && class_property >= 0) {
|
||||
ivl_type_t ptype = class_scope->get_prop_type(class_property);
|
||||
const netsarray_t*atype = dynamic_cast<const netsarray_t*> (ptype);
|
||||
if (atype == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "I can't handle the type of " << array_var_
|
||||
<< " as a foreach loop." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::vector<netrange_t>&dims = atype->static_dimensions();
|
||||
if (dims.size() < index_vars_.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "class " << class_scope->get_name()
|
||||
<< " property " << array_var_
|
||||
<< " has too few dimensions for foreach dimension list." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return elaborate_static_array_(des, scope, dims);
|
||||
}
|
||||
|
||||
if (array_sig == 0) {
|
||||
cerr << get_fileline() << ": error:"
|
||||
<< " Unable to find foreach array " << array_name
|
||||
<< " in scope " << scope_path(scope)
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_assert(*this, array_sig);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||
<< "Scan array " << array_sig->name()
|
||||
<< " of " << array_sig->data_type()
|
||||
<< " with " << array_sig->unpacked_dimensions() << " unpacked"
|
||||
<< " and " << array_sig->packed_dimensions()
|
||||
<< " packed dimensions." << endl;
|
||||
}
|
||||
|
||||
// Classic arrays are processed this way.
|
||||
if (array_sig->data_type()==IVL_VT_BOOL)
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
if (array_sig->data_type()==IVL_VT_LOGIC)
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
if (array_sig->unpacked_dimensions() >= index_vars_.size())
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
|
||||
|
||||
// At this point, we know that the array is dynamic so we
|
||||
// handle that slightly differently, using run-time tests.
|
||||
|
||||
if (index_vars_.size() != 1) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Multi-index foreach loops not supported." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
// Get the signal for the index variable.
|
||||
pform_name_t index_name;
|
||||
index_name.push_back(name_component_t(index_vars_[0]));
|
||||
NetNet*idx_sig = des->find_signal(scope, index_name);
|
||||
ivl_assert(*this, idx_sig);
|
||||
|
||||
NetESignal*array_exp = new NetESignal(array_sig);
|
||||
array_exp->set_line(*this);
|
||||
|
||||
NetESignal*idx_exp = new NetESignal(idx_sig);
|
||||
idx_exp->set_line(*this);
|
||||
|
||||
// Make an initialization expression for the index.
|
||||
NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1);
|
||||
init_expr->set_line(*this);
|
||||
init_expr->parm(0, array_exp);
|
||||
|
||||
// Make a condition expression: idx <= $high(array)
|
||||
NetESFunc*high_exp = new NetESFunc("$high", IVL_VT_BOOL, 32, 1);
|
||||
high_exp->set_line(*this);
|
||||
high_exp->parm(0, array_exp);
|
||||
|
||||
NetEBComp*cond_expr = new NetEBComp('L', idx_exp, high_exp);
|
||||
cond_expr->set_line(*this);
|
||||
|
||||
/* Elaborate the statement that is contained in the foreach
|
||||
loop. */
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
|
||||
/* Make a step statement: idx += 1 */
|
||||
NetAssign_*idx_lv = new NetAssign_(idx_sig);
|
||||
NetEConst*step_val = make_const_val(1);
|
||||
NetAssign*step = new NetAssign(idx_lv, '+', step_val);
|
||||
step->set_line(*this);
|
||||
|
||||
NetForLoop*stmt = new NetForLoop(idx_sig, init_expr, cond_expr, sub, step);
|
||||
stmt->set_line(*this);
|
||||
stmt->wrap_up();
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a variant of the PForeach::elaborate() method that handles
|
||||
* the case that the array has static dimensions. We can use constants
|
||||
* and possibly do some optimizations.
|
||||
*/
|
||||
NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
|
||||
const vector<netrange_t>&dims) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate_static_array_: "
|
||||
<< "Handle as array with static dimensions." << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, index_vars_.size() > 0);
|
||||
ivl_assert(*this, dims.size() == index_vars_.size());
|
||||
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
NetForLoop*stmt = 0;
|
||||
|
||||
for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) {
|
||||
const netrange_t&idx_range = dims[idx_idx];
|
||||
|
||||
// Get the $high and $low constant values for this slice
|
||||
// of the array.
|
||||
NetEConst*hig_expr = make_const_val_s(idx_range.get_msb());
|
||||
NetEConst*low_expr = make_const_val_s(idx_range.get_lsb());
|
||||
if (idx_range.get_msb() < idx_range.get_lsb()) {
|
||||
NetEConst*tmp = hig_expr;
|
||||
hig_expr = low_expr;
|
||||
low_expr = tmp;
|
||||
}
|
||||
|
||||
hig_expr->set_line(*this);
|
||||
low_expr->set_line(*this);
|
||||
|
||||
pform_name_t idx_name;
|
||||
idx_name.push_back(name_component_t(index_vars_[idx_idx]));
|
||||
NetNet*idx_sig = des->find_signal(scope, idx_name);
|
||||
ivl_assert(*this, idx_sig);
|
||||
|
||||
// Make the condition expression <idx> <= $high(slice)
|
||||
NetESignal*idx_expr = new NetESignal(idx_sig);
|
||||
idx_expr->set_line(*this);
|
||||
|
||||
NetEBComp*cond_expr = new NetEBComp('L', idx_expr, hig_expr);
|
||||
cond_expr->set_line(*this);
|
||||
|
||||
// Make the step statement: <idx> += 1
|
||||
NetAssign_*idx_lv = new NetAssign_(idx_sig);
|
||||
NetEConst*step_val = make_const_val_s(1);
|
||||
NetAssign*step = new NetAssign(idx_lv, '+', step_val);
|
||||
step->set_line(*this);
|
||||
|
||||
stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step);
|
||||
stmt->set_line(*this);
|
||||
stmt->wrap_up();
|
||||
|
||||
sub = stmt;
|
||||
}
|
||||
|
||||
return stmt? stmt : sub;
|
||||
}
|
||||
|
||||
/*
|
||||
* elaborate the for loop as the equivalent while loop. This eases the
|
||||
* task for the target code generator. The structure is:
|
||||
@@ -5252,6 +5558,9 @@ bool PPackage::elaborate(Design*des, NetScope*scope) const
|
||||
// Elaborate task methods.
|
||||
elaborate_tasks(des, scope, tasks);
|
||||
|
||||
// Elaborate class definitions.
|
||||
elaborate_classes(des, scope, classes);
|
||||
|
||||
return result_flag;
|
||||
}
|
||||
|
||||
@@ -5679,6 +5988,28 @@ bool Design::check_proc_delay() const
|
||||
return result_flag;
|
||||
}
|
||||
|
||||
void Design::root_elaborate(void)
|
||||
{
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++ cur) {
|
||||
netclass_t*cur_class = cur->second;
|
||||
PClass*cur_pclass = class_to_pclass_[cur_class];
|
||||
cur_class->elaborate(this, cur_pclass);
|
||||
}
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << cur->second->get_fileline() << ": Design::root_elaborate: "
|
||||
<< "Elaborate for root task/func " << scope_path(cur->first) << endl;
|
||||
}
|
||||
|
||||
cur->second->elaborate(this, cur->first);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the root of all elaboration. The input is the list
|
||||
* of root module names. The function locates the Module definitions
|
||||
@@ -5710,12 +6041,19 @@ Design* elaborate(list<perm_string>roots)
|
||||
// Elaborate enum sets in $root scope.
|
||||
elaborate_rootscope_enumerations(des);
|
||||
|
||||
// Elaborate tasks and functions in $root scope.
|
||||
elaborate_rootscope_tasks(des);
|
||||
|
||||
// Elaborate classes in $root scope.
|
||||
elaborate_rootscope_classes(des);
|
||||
|
||||
// Elaborate the packages. Package elaboration is simpler
|
||||
// because there are fewer sub-scopes involved.
|
||||
i = 0;
|
||||
for (map<perm_string,PPackage*>::iterator pac = pform_packages.begin()
|
||||
; pac != pform_packages.end() ; ++ pac) {
|
||||
|
||||
ivl_assert(*pac->second, pac->first == pac->second->pscope_name());
|
||||
NetScope*scope = des->make_package_scope(pac->first);
|
||||
scope->set_line(pac->second);
|
||||
|
||||
@@ -5807,6 +6145,11 @@ Design* elaborate(list<perm_string>roots)
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << "<toplevel>: elaborate: "
|
||||
<< "elaboration work list done. Start processing residual defparams." << endl;
|
||||
}
|
||||
|
||||
// Look for residual defparams (that point to a non-existent
|
||||
// scope) and clean them out.
|
||||
des->residual_defparams();
|
||||
@@ -5816,6 +6159,11 @@ Design* elaborate(list<perm_string>roots)
|
||||
if (des->errors > 0)
|
||||
return des;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << "<toplevel>: elaborate: "
|
||||
<< "Start calling Package elaborate_sig methods." << endl;
|
||||
}
|
||||
|
||||
// With the parameters evaluated down to constants, we have
|
||||
// what we need to elaborate signals and memories. This pass
|
||||
// creates all the NetNet and NetMemory objects for declared
|
||||
@@ -5834,6 +6182,18 @@ Design* elaborate(list<perm_string>roots)
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << "<toplevel>: elaborate: "
|
||||
<< "Start calling $root elaborate_sig methods." << endl;
|
||||
}
|
||||
|
||||
des->root_elaborate_sig();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << "<toplevel>: elaborate: "
|
||||
<< "Start calling root module elaborate_sig methods." << endl;
|
||||
}
|
||||
|
||||
for (i = 0; i < root_elems.size(); i++) {
|
||||
Module *rmod = root_elems[i].mod;
|
||||
NetScope *scope = root_elems[i].scope;
|
||||
@@ -5890,6 +6250,8 @@ Design* elaborate(list<perm_string>roots)
|
||||
rc &= pkg->elaborate(des, scope);
|
||||
}
|
||||
|
||||
des->root_elaborate();
|
||||
|
||||
for (i = 0; i < root_elems.size(); i++) {
|
||||
Module *rmod = root_elems[i].mod;
|
||||
NetScope *scope = root_elems[i].scope;
|
||||
|
||||
@@ -409,14 +409,13 @@ void NetRepeat::emit_recurse(struct target_t*tgt) const
|
||||
void netclass_t::emit_scope(struct target_t*tgt) const
|
||||
{
|
||||
class_scope_->emit_scope(tgt);
|
||||
class_scope_->emit_defs(tgt);
|
||||
}
|
||||
|
||||
void NetScope::emit_scope(struct target_t*tgt) const
|
||||
{
|
||||
if (debug_emit) {
|
||||
cerr << "NetScope::emit_scope: "
|
||||
<< "Emit scope basename=" << basename() << endl;
|
||||
<< "Emit scope " << scope_path(this) << endl;
|
||||
}
|
||||
|
||||
tgt->scope(this);
|
||||
@@ -461,12 +460,20 @@ bool NetScope::emit_defs(struct target_t*tgt) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
if (debug_emit) {
|
||||
cerr << "NetScope::emit_defs: "
|
||||
<< "Emit definitions for " << scope_path(this) << endl;
|
||||
}
|
||||
|
||||
switch (type_) {
|
||||
case PACKAGE:
|
||||
case MODULE:
|
||||
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
|
||||
; cur != children_.end() ; ++ cur )
|
||||
flag &= cur->second->emit_defs(tgt);
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++ cur)
|
||||
flag &= cur->second->emit_defs(tgt);
|
||||
break;
|
||||
|
||||
case FUNC:
|
||||
@@ -485,6 +492,11 @@ bool NetScope::emit_defs(struct target_t*tgt) const
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool netclass_t::emit_defs(struct target_t*tgt) const
|
||||
{
|
||||
return class_scope_->emit_defs(tgt);
|
||||
}
|
||||
|
||||
int Design::emit(struct target_t*tgt) const
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -492,12 +504,26 @@ int Design::emit(struct target_t*tgt) const
|
||||
if (tgt->start_design(this) == false)
|
||||
return -2;
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator scope = root_tasks_.begin()
|
||||
; scope != root_tasks_.end() ; ++ scope) {
|
||||
scope->first->emit_scope(tgt);
|
||||
scope->first->emit_defs(tgt);
|
||||
}
|
||||
|
||||
// enumerate package scopes
|
||||
for (map<perm_string,NetScope*>::const_iterator scope = packages_.begin()
|
||||
; scope != packages_.end() ; ++ scope) {
|
||||
scope->second->emit_scope(tgt);
|
||||
}
|
||||
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++cur) {
|
||||
const NetScope*use_scope = cur->second->class_scope();
|
||||
cur->second->emit_scope(tgt);
|
||||
tgt->class_type(use_scope, cur->second);
|
||||
cur->second->emit_defs(tgt);
|
||||
}
|
||||
|
||||
// enumerate root scopes
|
||||
for (list<NetScope*>::const_iterator scope = root_scopes_.begin()
|
||||
; scope != root_scopes_.end(); ++ scope ) {
|
||||
@@ -610,6 +636,11 @@ void NetEEvent::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_event(this);
|
||||
}
|
||||
|
||||
void NetELast::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_last(this);
|
||||
}
|
||||
|
||||
void NetENetenum::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_netenum(this);
|
||||
|
||||
@@ -2016,6 +2016,7 @@ static bool get_array_info(const NetExpr*arg, long dim,
|
||||
/* A string or dynamic array must be handled by the run time. */
|
||||
switch (sig->data_type()) {
|
||||
case IVL_VT_DARRAY:
|
||||
case IVL_VT_QUEUE:
|
||||
case IVL_VT_STRING:
|
||||
defer = true;
|
||||
return true;
|
||||
|
||||
@@ -440,6 +440,7 @@ typedef enum ivl_variable_type_e {
|
||||
IVL_VT_STRING = 5,
|
||||
IVL_VT_DARRAY = 6, /* Array (esp. dynamic array) */
|
||||
IVL_VT_CLASS = 7, /* SystemVerilog class instances */
|
||||
IVL_VT_QUEUE = 8, /* SystemVerilog queue instances */
|
||||
IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */
|
||||
} ivl_variable_type_t;
|
||||
|
||||
@@ -831,6 +832,10 @@ extern unsigned ivl_event_lineno(ivl_event_t net);
|
||||
* table. That number can be passed to ivl_type_prop_*() functions to
|
||||
* get details about the property.
|
||||
*
|
||||
* If the property is an array, then the ivl_expr_oper1() function
|
||||
* returns the canonical expression for accessing the element of the
|
||||
* property.
|
||||
*
|
||||
* - IVL_EX_NEW
|
||||
* This expression takes one or two operands. The first operand,
|
||||
* returned by ivl_expr_oper1() is the number of elements to create
|
||||
@@ -1498,6 +1503,11 @@ extern const char*ivl_lpm_string(ivl_lpm_t net);
|
||||
* then the ivl_lval_idx expression must *not* be present.
|
||||
*
|
||||
* For array words, the ivl_lval_width is the width of the word.
|
||||
*
|
||||
* - Arrayed properties
|
||||
* If the l-value is a class property, then the ivl_lval_idx function
|
||||
* will return an expression if the property is in fact arrayed. The
|
||||
* expression is the canonical index for elements in the property.
|
||||
*/
|
||||
|
||||
extern unsigned ivl_lval_width(ivl_lval_t net);
|
||||
|
||||
@@ -52,6 +52,7 @@ struct ivl_design_s {
|
||||
|
||||
// Keep arrays of root scopes.
|
||||
std::map<const NetScope*,ivl_scope_t> classes;
|
||||
std::map<const NetScope*,ivl_scope_t> root_tasks;
|
||||
std::vector<ivl_scope_t> packages;
|
||||
std::vector<ivl_scope_t> roots;
|
||||
|
||||
|
||||
+32
-13
@@ -2066,51 +2066,66 @@ void dump_precompiled_defines(FILE* out)
|
||||
|
||||
void load_precompiled_defines(FILE* src)
|
||||
{
|
||||
char buf[4096];
|
||||
char*buf = malloc(4096);
|
||||
size_t buf_len = 4096;
|
||||
int ch;
|
||||
|
||||
while ((ch = fgetc(src)) != EOF)
|
||||
{
|
||||
char* cp = buf;
|
||||
char* name = 0;
|
||||
char* value = 0;
|
||||
|
||||
int argc = 0;
|
||||
size_t len = 0;
|
||||
|
||||
name = cp;
|
||||
|
||||
*cp++ = ch;
|
||||
|
||||
while ((ch = fgetc(src)) != EOF && ch != ':')
|
||||
while ((ch = fgetc(src)) != EOF && ch != ':') {
|
||||
*cp++ = ch;
|
||||
assert( (size_t)(cp-buf) < buf_len );
|
||||
}
|
||||
|
||||
if (ch != ':')
|
||||
return;
|
||||
|
||||
/* Terminate the name string. */
|
||||
*cp++ = 0;
|
||||
assert( (size_t)(cp-buf) < buf_len );
|
||||
|
||||
/* Read the argc number */
|
||||
/* Read the argc number. (this doesn't need buffer space) */
|
||||
while (isdigit(ch = fgetc(src)))
|
||||
argc = 10*argc + ch-'0';
|
||||
|
||||
if (ch != ':')
|
||||
return;
|
||||
return;
|
||||
|
||||
/* Read the value len (this doesn't need buffer space) */
|
||||
while (isdigit(ch = fgetc(src)))
|
||||
len = 10*len + ch-'0';
|
||||
|
||||
if (ch != ':')
|
||||
return;
|
||||
return;
|
||||
|
||||
value = cp;
|
||||
/* Save the name, and start the buffer over. */
|
||||
name = strdup(buf);
|
||||
|
||||
/* We now know how big the value should be, so if necessary,
|
||||
reallocate the buffer to be sure we can hold it. */
|
||||
if ((len+4) >= buf_len) {
|
||||
buf = realloc(buf, len+8);
|
||||
assert(buf);
|
||||
}
|
||||
|
||||
cp = buf;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
ch = fgetc(src);
|
||||
if (ch == EOF)
|
||||
return;
|
||||
if (ch == EOF) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
|
||||
*cp++ = ch;
|
||||
len -= 1;
|
||||
@@ -2119,10 +2134,14 @@ void load_precompiled_defines(FILE* src)
|
||||
*cp++ = 0;
|
||||
|
||||
ch = fgetc(src);
|
||||
if (ch != '\n')
|
||||
return;
|
||||
if (ch != '\n') {
|
||||
free(name);
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
define_macro(name, value, 0, argc);
|
||||
define_macro(name, buf, 0, argc);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-2013 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2014 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
|
||||
@@ -137,8 +137,13 @@ TU [munpf]
|
||||
current line. These are very easy to handle. The meta-comments
|
||||
format is a little more tricky to handle, but do what we can. */
|
||||
|
||||
"//"{W}*"synthesis"{W}*"translate_on"{W}*\n { return K_MC_TRANSLATE_ON; }
|
||||
"//"{W}*"synthesis"{W}*"translate_off"{W}*\n { return K_MC_TRANSLATE_OFF; }
|
||||
/* The lexor detects "// synthesis translate_on/off" meta-comments,
|
||||
we handle them here by turning on/off a flag. The pform uses
|
||||
that flag to attach implicit attributes to "initial" and
|
||||
"always" statements. */
|
||||
|
||||
"//"{W}*"synthesis"{W}+"translate_on"{W}*\n { pform_mc_translate_on(true); }
|
||||
"//"{W}*"synthesis"{W}+"translate_off"{W}*\n { pform_mc_translate_on(false); }
|
||||
"//" { comment_enter = YY_START; BEGIN(LCOMMENT); }
|
||||
<LCOMMENT>. { yymore(); }
|
||||
<LCOMMENT>\n { yylloc.first_line += 1; BEGIN(comment_enter); }
|
||||
@@ -652,14 +657,14 @@ TU [munpf]
|
||||
|GN_KEYWORDS_1364_2005
|
||||
|GN_KEYWORDS_VAMS_2_3;
|
||||
} else {
|
||||
fprintf(stderr, "%s:%u: Ignoring unknown keywords string: %s\n",
|
||||
fprintf(stderr, "%s:%d: Ignoring unknown keywords string: %s\n",
|
||||
yylloc.text, yylloc.first_line, word);
|
||||
}
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
<PPBEGIN_KEYWORDS>.* {
|
||||
fprintf(stderr, "%s:%u: Malformed keywords specification: %s\n",
|
||||
fprintf(stderr, "%s:%d: Malformed keywords specification: %s\n",
|
||||
yylloc.text, yylloc.first_line, yytext);
|
||||
BEGIN(0);
|
||||
}
|
||||
@@ -669,7 +674,7 @@ TU [munpf]
|
||||
lexor_keyword_mask = keyword_mask_stack.front();
|
||||
keyword_mask_stack.pop_front();
|
||||
} else {
|
||||
fprintf(stderr, "%s:%u: Mismatched end_keywords directive\n",
|
||||
fprintf(stderr, "%s:%d: Mismatched end_keywords directive\n",
|
||||
yylloc.text, yylloc.first_line);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -3,9 +3,11 @@
|
||||
* tokenType values are not initialized for the empty table entries.
|
||||
*/
|
||||
%define initializer-suffix ,0,0
|
||||
%language=C++
|
||||
%define class-name Lkwd
|
||||
|
||||
%{
|
||||
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */
|
||||
/* Command-line: gperf -o -i 7 -C -k '1-4,6,9,$' -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf */
|
||||
|
||||
#include "config.h"
|
||||
#include "parse_misc.h"
|
||||
@@ -362,7 +364,7 @@ int lexor_keyword_mask = 0;
|
||||
|
||||
int lexor_keyword_code(const char*str, unsigned nstr)
|
||||
{
|
||||
const struct lexor_keyword*rc = check_identifier(str, nstr);
|
||||
const struct lexor_keyword*rc = Lkwd::check_identifier(str, nstr);
|
||||
if (rc == 0)
|
||||
return IDENTIFIER;
|
||||
else if ((rc->mask & lexor_keyword_mask) == 0)
|
||||
|
||||
@@ -210,3 +210,5 @@ ostream& operator << (ostream&out, perm_string that)
|
||||
out << that.str();
|
||||
return out;
|
||||
}
|
||||
|
||||
const perm_string empty_perm_string = perm_string::literal("");
|
||||
|
||||
@@ -52,6 +52,7 @@ class perm_string {
|
||||
const char*text_;
|
||||
};
|
||||
|
||||
extern const perm_string empty_perm_string;
|
||||
extern bool operator == (perm_string a, perm_string b);
|
||||
extern bool operator == (perm_string a, const char* b);
|
||||
extern bool operator != (perm_string a, perm_string b);
|
||||
|
||||
@@ -1019,6 +1019,16 @@ int main(int argc, char*argv[])
|
||||
; cur != disciplines.end() ; ++ cur ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP $ROOT TASKS/FUNCTIONS:" << endl;
|
||||
for (map<perm_string,PTaskFunc*>::iterator cur = pform_tasks.begin()
|
||||
; cur != pform_tasks.end() ; ++ cur) {
|
||||
pform_dump(out, cur->second);
|
||||
}
|
||||
out << "PFORM DUMP $ROOT CLASSES:" << endl;
|
||||
for (map<perm_string,PClass*>::iterator cur = pform_classes.begin()
|
||||
; cur != pform_classes.end() ; ++ cur) {
|
||||
pform_dump(out, cur->second);
|
||||
}
|
||||
out << "PFORM DUMP PACKAGES:" << endl;
|
||||
for (map<perm_string,PPackage*>::iterator pac = pform_packages.begin()
|
||||
; pac != pform_packages.end() ; ++ pac) {
|
||||
@@ -1142,6 +1152,12 @@ int main(int argc, char*argv[])
|
||||
(*idx).second = 0;
|
||||
}
|
||||
|
||||
for(map<perm_string,data_type_t*>::iterator it = pform_typedefs.begin()
|
||||
; it != pform_typedefs.end() ; ++it) {
|
||||
delete (*it).second;
|
||||
(*it).second = 0;
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
if (times_flag) {
|
||||
times(cycles+2);
|
||||
|
||||
@@ -135,6 +135,9 @@ ivl_variable_type_t NetAssign_::expr_type() const
|
||||
return darray->element_base_type();
|
||||
}
|
||||
|
||||
if (sig_ && sig_->data_type()==IVL_VT_STRING && base_!=0)
|
||||
return IVL_VT_BOOL;
|
||||
|
||||
if (ntype) return ntype->base_type();
|
||||
|
||||
ivl_assert(*this, sig_);
|
||||
|
||||
+64
-10
@@ -134,6 +134,21 @@ NetScope* Design::make_package_scope(perm_string name)
|
||||
return scope;
|
||||
}
|
||||
|
||||
void Design::add_class(netclass_t*cl, PClass*pclass)
|
||||
{
|
||||
Definitions::add_class(cl);
|
||||
class_to_pclass_[cl] = pclass;
|
||||
}
|
||||
|
||||
netclass_t* Design::find_class(perm_string name) const
|
||||
{
|
||||
map<perm_string,netclass_t*>::const_iterator cur = classes_.find(name);
|
||||
if (cur != classes_.end())
|
||||
return cur->second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetScope* Design::find_package(perm_string name) const
|
||||
{
|
||||
map<perm_string,NetScope*>::const_iterator cur = packages_.find(name);
|
||||
@@ -154,6 +169,17 @@ list<NetScope*> Design::find_package_scopes() const
|
||||
return res;
|
||||
}
|
||||
|
||||
list<NetScope*> Design::find_roottask_scopes() const
|
||||
{
|
||||
list<NetScope*>res;
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator cur = root_tasks_.begin()
|
||||
; cur != root_tasks_.end() ; ++ cur) {
|
||||
res.push_back (cur->first);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method locates a scope in the design, given its rooted
|
||||
* hierarchical name. Each component of the key is used to scan one
|
||||
@@ -182,7 +208,25 @@ NetScope* Design::find_scope(const std::list<hname_t>&path) const
|
||||
|
||||
tmp.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
for (map<NetScope*,PTaskFunc*>::const_iterator root = root_tasks_.begin()
|
||||
; root != root_tasks_.end() ; ++ root) {
|
||||
|
||||
NetScope*cur = root->first;
|
||||
if (path.front() != cur->fullname())
|
||||
continue;
|
||||
|
||||
std::list<hname_t> tmp = path;
|
||||
tmp.pop_front();
|
||||
|
||||
while (cur) {
|
||||
if (tmp.empty()) return cur;
|
||||
|
||||
cur = cur->child( tmp.front() );
|
||||
|
||||
tmp.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -483,6 +527,20 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the parameter has type or range information, then
|
||||
// make sure the type is set right. Note that if the
|
||||
// parameter doesn't have an explicit type or range,
|
||||
// then it will get the signedness from the expression itself.
|
||||
if (cur->second.type != IVL_VT_NO_TYPE) {
|
||||
expr->cast_signed(cur->second.signed_flag);
|
||||
} else if (cur->second.signed_flag) {
|
||||
expr->cast_signed(true);
|
||||
}
|
||||
|
||||
if (!range_flag && !expr->has_width()) {
|
||||
expr = pad_to_width(expr, integer_width, *expr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -492,17 +550,8 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
(*cur).second.val = expr;
|
||||
|
||||
/* If the parameter has type or range information, then make
|
||||
sure the type is set right. Note that if the parameter
|
||||
doesn't have an explicit type or range, then it will get
|
||||
the signedness from the expression itself. */
|
||||
if ((*cur).second.type != IVL_VT_NO_TYPE) {
|
||||
(*cur).second.val->cast_signed((*cur).second.signed_flag);
|
||||
} else if ((*cur).second.signed_flag) {
|
||||
(*cur).second.val->cast_signed(true);
|
||||
}
|
||||
cur->second.val = expr;
|
||||
|
||||
// If there are no value ranges to test the value against,
|
||||
// then we are done.
|
||||
@@ -816,6 +865,11 @@ NetScope* Design::find_task(NetScope*scope, const pform_name_t&name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Design::add_root_task(NetScope*tscope, PTaskFunc*tf)
|
||||
{
|
||||
root_tasks_[tscope] = tf;
|
||||
}
|
||||
|
||||
void Design::add_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
|
||||
+16
-2
@@ -321,6 +321,20 @@ const NetScope* NetECRealParam::scope() const
|
||||
}
|
||||
|
||||
|
||||
NetELast::NetELast(NetNet*s)
|
||||
: sig_(s)
|
||||
{
|
||||
}
|
||||
|
||||
NetELast::~NetELast()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetELast::expr_type() const
|
||||
{
|
||||
return IVL_VT_BOOL;
|
||||
}
|
||||
|
||||
NetENetenum::NetENetenum(const netenum_t*s)
|
||||
: netenum_(s)
|
||||
{
|
||||
@@ -362,8 +376,8 @@ NetENull::~NetENull()
|
||||
{
|
||||
}
|
||||
|
||||
NetEProperty::NetEProperty(NetNet*net, perm_string pnam)
|
||||
: net_(net)
|
||||
NetEProperty::NetEProperty(NetNet*net, perm_string pnam, NetExpr*idx)
|
||||
: net_(net), index_(idx)
|
||||
{
|
||||
const netclass_t*use_type = dynamic_cast<const netclass_t*>(net->net_type());
|
||||
assert(use_type);
|
||||
|
||||
@@ -106,6 +106,11 @@ NexusSet* NetEEvent::nex_input(bool)
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetELast::nex_input(bool)
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetENetenum::nex_input(bool)
|
||||
{
|
||||
return new NexusSet;
|
||||
|
||||
+70
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2014 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,8 +19,10 @@
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# include "compiler.h"
|
||||
# include "netlist.h"
|
||||
# include <cassert>
|
||||
# include "netmisc.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
NetBlock::NetBlock(Type t, NetScope*ss)
|
||||
: type_(t), subscope_(ss), last_(0)
|
||||
@@ -73,7 +75,7 @@ const NetProc* NetBlock::proc_next(const NetProc*cur) const
|
||||
NetCase::NetCase(NetCase::TYPE c, NetExpr*ex, unsigned cnt)
|
||||
: type_(c), expr_(ex), items_(cnt)
|
||||
{
|
||||
assert(expr_);
|
||||
ivl_assert(*this, expr_);
|
||||
}
|
||||
|
||||
NetCase::~NetCase()
|
||||
@@ -92,11 +94,73 @@ NetCase::TYPE NetCase::type() const
|
||||
|
||||
void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p)
|
||||
{
|
||||
assert(idx < items_.size());
|
||||
ivl_assert(*this, idx < items_.size());
|
||||
items_[idx].guard = e;
|
||||
items_[idx].statement = p;
|
||||
}
|
||||
|
||||
void NetCase::prune()
|
||||
{
|
||||
// Test whether the case expression has been padded out
|
||||
NetESelect*padded_expr = dynamic_cast<NetESelect*>(expr_);
|
||||
if ((padded_expr == 0) || (padded_expr->select() != 0))
|
||||
return;
|
||||
|
||||
// If so, run through the case item expressions to find
|
||||
// the minimum number of bits needed to unambiguously
|
||||
// select the correct case item.
|
||||
const NetExpr*unpadded_expr = padded_expr->sub_expr();
|
||||
unsigned padded_width = padded_expr->expr_width();
|
||||
unsigned prune_width = unpadded_expr->expr_width();
|
||||
for (unsigned idx = 0; idx < items_.size(); idx += 1) {
|
||||
// If there is no guard expression, this is the default
|
||||
// case, so skip it.
|
||||
if (items_[idx].guard == 0)
|
||||
continue;
|
||||
|
||||
// If the guard expression is not constant, assume
|
||||
// all bits are needed, so no pruning can be done.
|
||||
NetEConst*gc = dynamic_cast<NetEConst*>(items_[idx].guard);
|
||||
if (gc == 0)
|
||||
return;
|
||||
|
||||
unsigned sig_bits = gc->value().significant_bits();
|
||||
if (sig_bits > prune_width)
|
||||
prune_width = sig_bits;
|
||||
|
||||
// If all the padding bits are needed, no pruning
|
||||
// can be done.
|
||||
if (prune_width >= padded_width)
|
||||
return;
|
||||
}
|
||||
ivl_assert(*this, prune_width < padded_width);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: pruning case expressions to "
|
||||
<< prune_width << " bits." << endl;
|
||||
}
|
||||
|
||||
// Prune the case expression
|
||||
expr_ = pad_to_width(unpadded_expr->dup_expr(), prune_width, *expr_);
|
||||
delete padded_expr;
|
||||
|
||||
// Prune the case item expressions
|
||||
for (unsigned idx = 0; idx < items_.size(); idx += 1) {
|
||||
if (items_[idx].guard == 0)
|
||||
continue;
|
||||
|
||||
NetEConst*gc = dynamic_cast<NetEConst*>(items_[idx].guard);
|
||||
ivl_assert(*this, gc);
|
||||
|
||||
verinum value(gc->value(), prune_width);
|
||||
NetEConst*tmp = new NetEConst(value);
|
||||
tmp->set_line(*gc);
|
||||
delete gc;
|
||||
|
||||
items_[idx].guard = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
NetDisable::NetDisable(NetScope*tgt)
|
||||
: target_(tgt)
|
||||
{
|
||||
@@ -139,7 +203,7 @@ void NetForLoop::wrap_up()
|
||||
NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0);
|
||||
internal_block->set_line(*this);
|
||||
|
||||
internal_block->append(statement_);
|
||||
if (statement_) internal_block->append(statement_);
|
||||
internal_block->append(step_statement_);
|
||||
|
||||
NetWhile*wloop = new NetWhile(condition_, internal_block);
|
||||
@@ -175,7 +239,7 @@ NetPDelay::~NetPDelay()
|
||||
|
||||
uint64_t NetPDelay::delay() const
|
||||
{
|
||||
assert(expr_ == 0);
|
||||
ivl_assert(*this, expr_ == 0);
|
||||
return delay_;
|
||||
}
|
||||
|
||||
|
||||
+56
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2014 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
|
||||
@@ -96,6 +96,11 @@ const NetExpr* Definitions::enumeration_expr(perm_string key)
|
||||
}
|
||||
}
|
||||
|
||||
void Definitions::add_class(netclass_t*net_class)
|
||||
{
|
||||
classes_[net_class->get_name()] = net_class;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NetScope class keeps a scope tree organized. Each node of the
|
||||
* scope tree points to its parent, its right sibling and its leftmost
|
||||
@@ -130,7 +135,6 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bo
|
||||
time_unit_ = 0;
|
||||
time_prec_ = 0;
|
||||
time_from_timescale_ = false;
|
||||
assert(t==MODULE || t==PACKAGE || t==CLASS);
|
||||
}
|
||||
|
||||
switch (t) {
|
||||
@@ -189,6 +193,22 @@ void NetScope::set_line(perm_string file, perm_string def_file,
|
||||
def_lineno_ = def_lineno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for the enumeration in the current scope and any parent scopes.
|
||||
*/
|
||||
const netenum_t*NetScope::find_enumeration_for_name(perm_string name)
|
||||
{
|
||||
NetScope *cur_scope = this;
|
||||
while (cur_scope) {
|
||||
NetEConstEnum*tmp = cur_scope->enum_names_[name];
|
||||
if (tmp) break;
|
||||
cur_scope = cur_scope->parent();
|
||||
}
|
||||
|
||||
assert(cur_scope);
|
||||
return cur_scope->enum_names_[name]->enumeration();
|
||||
}
|
||||
|
||||
void NetScope::set_parameter(perm_string key, bool is_annotatable,
|
||||
PExpr*val, ivl_variable_type_t type__,
|
||||
PExpr*msb, PExpr*lsb, bool signed_flag,
|
||||
@@ -616,14 +636,9 @@ NetNet* NetScope::find_signal(perm_string key)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetScope::add_class(netclass_t*net_class)
|
||||
{
|
||||
classes_[net_class->get_name()] = net_class;
|
||||
}
|
||||
|
||||
netclass_t*NetScope::find_class(perm_string name)
|
||||
{
|
||||
// Special class: The scope itself is the class that we are
|
||||
// Special case: The scope itself is the class that we are
|
||||
// looking for. This may happen for example when elaborating
|
||||
// methods within the class.
|
||||
if (type_==CLASS && name_==hname_t(name))
|
||||
@@ -638,6 +653,13 @@ netclass_t*NetScope::find_class(perm_string name)
|
||||
if (type_==MODULE)
|
||||
return 0;
|
||||
|
||||
if (up_==0 && type_==CLASS) {
|
||||
assert(class_def_);
|
||||
|
||||
NetScope*def_parent = class_def_->definition_scope();
|
||||
return def_parent->find_class(name);
|
||||
}
|
||||
|
||||
// If there is no further to look, ...
|
||||
if (up_ == 0)
|
||||
return 0;
|
||||
@@ -668,6 +690,32 @@ const NetScope* NetScope::child(const hname_t&name) const
|
||||
return cur->second;
|
||||
}
|
||||
|
||||
/* Helper function to see if the given scope is defined in a class and if
|
||||
* so return the class scope. */
|
||||
const NetScope* NetScope::get_class_scope() const
|
||||
{
|
||||
const NetScope*scope = this;
|
||||
while (scope) {
|
||||
switch(scope->type()) {
|
||||
case NetScope::CLASS:
|
||||
return scope;
|
||||
case NetScope::TASK:
|
||||
case NetScope::FUNC:
|
||||
case NetScope::BEGIN_END:
|
||||
case NetScope::FORK_JOIN:
|
||||
break;
|
||||
case NetScope::MODULE:
|
||||
case NetScope::GENBLOCK:
|
||||
case NetScope::PACKAGE:
|
||||
return 0;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
scope = scope->parent();
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
const NetScope* NetScope::child_byname(perm_string name) const
|
||||
{
|
||||
hname_t hname (name);
|
||||
|
||||
+10
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2014 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,7 +24,7 @@
|
||||
using namespace std;
|
||||
|
||||
netclass_t::netclass_t(perm_string name, netclass_t*sup)
|
||||
: name_(name), super_(sup), class_scope_(0)
|
||||
: name_(name), super_(sup), class_scope_(0), definition_scope_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,10 +50,16 @@ bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_
|
||||
return true;
|
||||
}
|
||||
|
||||
void netclass_t::set_class_scope(NetScope*class_scope)
|
||||
void netclass_t::set_class_scope(NetScope*class_scope__)
|
||||
{
|
||||
assert(class_scope_ == 0);
|
||||
class_scope_ = class_scope;
|
||||
class_scope_ = class_scope__;
|
||||
}
|
||||
|
||||
void netclass_t::set_definition_scope(NetScope*use_definition_scope)
|
||||
{
|
||||
assert(definition_scope_ == 0);
|
||||
definition_scope_ = use_definition_scope;
|
||||
}
|
||||
|
||||
ivl_variable_type_t netclass_t::base_type() const
|
||||
|
||||
+25
-2
@@ -43,9 +43,21 @@ class netclass_t : public ivl_type_s {
|
||||
bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype);
|
||||
|
||||
// Set the scope for the class. The scope has no parents and
|
||||
// is used for the elaboration of methods (tasks/functions).
|
||||
// is used for the elaboration of methods
|
||||
// (tasks/functions). In other words, this is the class itself.
|
||||
void set_class_scope(NetScope*cscope);
|
||||
|
||||
inline const NetScope* class_scope(void) const { return class_scope_; }
|
||||
|
||||
// Set the scope for the class definition. This is the scope
|
||||
// where the class definition was encountered, and may be used
|
||||
// to locate symbols that the class definition may inherit
|
||||
// from its context. This can be nil, or a package or module
|
||||
// where a class is defined.
|
||||
void set_definition_scope(NetScope*dscope);
|
||||
|
||||
NetScope*definition_scope(void);
|
||||
|
||||
// As an ivl_type_s object, the netclass is always an
|
||||
// ivl_VT_CLASS object.
|
||||
ivl_variable_type_t base_type() const;
|
||||
@@ -74,7 +86,8 @@ class netclass_t : public ivl_type_s {
|
||||
|
||||
bool test_for_missing_initializers(void) const;
|
||||
|
||||
// Map the name of a property to its index.
|
||||
// Map the name of a property to its index. Return <0 if the
|
||||
// name is not a property in the class.
|
||||
int property_idx_from_name(perm_string pname) const;
|
||||
|
||||
// The task method scopes from the method name.
|
||||
@@ -94,7 +107,9 @@ class netclass_t : public ivl_type_s {
|
||||
void elaborate(Design*des, PClass*pclass);
|
||||
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
std::ostream& debug_dump(std::ostream&fd) const;
|
||||
void dump_scope(ostream&fd) const;
|
||||
|
||||
private:
|
||||
@@ -115,6 +130,14 @@ class netclass_t : public ivl_type_s {
|
||||
|
||||
// This holds task/function definitions for methods.
|
||||
NetScope*class_scope_;
|
||||
|
||||
// This holds the context for the class type definition.
|
||||
NetScope*definition_scope_;
|
||||
};
|
||||
|
||||
inline NetScope*netclass_t::definition_scope(void)
|
||||
{
|
||||
return definition_scope_;
|
||||
}
|
||||
|
||||
#endif /* IVL_netclass_H */
|
||||
|
||||
+18
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2010-2014 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,8 +24,10 @@
|
||||
using namespace std;
|
||||
|
||||
netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag,
|
||||
long msb, long lsb, size_t name_count)
|
||||
: base_type_(btype), signed_flag_(signed_flag), msb_(msb), lsb_(lsb),
|
||||
bool integer_flag, long msb, long lsb, size_t name_count,
|
||||
enum_type_t*enum_type)
|
||||
: base_type_(btype), enum_type_(enum_type), signed_flag_(signed_flag),
|
||||
integer_flag_(integer_flag), msb_(msb), lsb_(lsb),
|
||||
names_(name_count), bits_(name_count)
|
||||
{
|
||||
}
|
||||
@@ -39,6 +41,11 @@ bool netenum_t::get_signed() const
|
||||
return signed_flag_;
|
||||
}
|
||||
|
||||
bool netenum_t::get_isint() const
|
||||
{
|
||||
return integer_flag_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumerations are by definition always packed.
|
||||
*/
|
||||
@@ -84,6 +91,9 @@ bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val
|
||||
void netenum_t::insert_name_close(void)
|
||||
{
|
||||
for (size_t idx = 0 ; idx < names_.size() ; idx += 1) {
|
||||
// If we failed to elaborate the name then skip this step.
|
||||
if (names_[idx].nil()) continue;
|
||||
|
||||
netenum_t::iterator cur = names_map_.find(names_[idx]);
|
||||
|
||||
vector<char>str (cur->second.len() + 1);
|
||||
@@ -153,3 +163,8 @@ perm_string netenum_t::bits_at(size_t idx) const
|
||||
{
|
||||
return bits_[idx];
|
||||
}
|
||||
|
||||
bool netenum_t::matches(const netenum_t*other) const
|
||||
{
|
||||
return enum_type_ == other->enum_type_;
|
||||
}
|
||||
|
||||
@@ -29,11 +29,14 @@
|
||||
|
||||
class NetScope;
|
||||
|
||||
struct enum_type_t;
|
||||
|
||||
class netenum_t : public LineInfo, public ivl_type_s {
|
||||
|
||||
public:
|
||||
explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag,
|
||||
long msb, long lsb, size_t name_count);
|
||||
bool isint_flag, long msb, long lsb,
|
||||
size_t name_count, enum_type_t*enum_type);
|
||||
~netenum_t();
|
||||
|
||||
virtual ivl_variable_type_t base_type() const;
|
||||
@@ -41,6 +44,7 @@ class netenum_t : public LineInfo, public ivl_type_s {
|
||||
virtual long packed_width() const;
|
||||
std::vector<netrange_t> slice_dimensions() const;
|
||||
bool get_signed() const;
|
||||
bool get_isint() const;
|
||||
|
||||
// The size() is the number of enumeration literals.
|
||||
size_t size() const;
|
||||
@@ -65,9 +69,14 @@ class netenum_t : public LineInfo, public ivl_type_s {
|
||||
perm_string name_at(size_t idx) const;
|
||||
perm_string bits_at(size_t idx) const;
|
||||
|
||||
// Check if two enumerations have the same definition.
|
||||
bool matches(const netenum_t*other) const;
|
||||
|
||||
private:
|
||||
ivl_variable_type_t base_type_;
|
||||
enum_type_t*enum_type_;
|
||||
bool signed_flag_;
|
||||
bool integer_flag_;
|
||||
long msb_, lsb_;
|
||||
|
||||
std::map<perm_string,verinum> names_map_;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
# include "netdarray.h"
|
||||
# include "netenum.h"
|
||||
# include "netparray.h"
|
||||
# include "netqueue.h"
|
||||
# include "netstruct.h"
|
||||
# include "netvector.h"
|
||||
# include "ivl_assert.h"
|
||||
@@ -754,6 +755,11 @@ const netdarray_t* NetNet::darray_type(void) const
|
||||
return dynamic_cast<const netdarray_t*> (net_type_);
|
||||
}
|
||||
|
||||
const netqueue_t* NetNet::queue_type(void) const
|
||||
{
|
||||
return dynamic_cast<const netqueue_t*> (net_type_);
|
||||
}
|
||||
|
||||
const netclass_t* NetNet::class_type(void) const
|
||||
{
|
||||
return dynamic_cast<const netclass_t*> (net_type_);
|
||||
|
||||
@@ -74,12 +74,15 @@ class NetRamDq;
|
||||
class NetTaskDef;
|
||||
class NetEvTrig;
|
||||
class NetEvWait;
|
||||
class PClass;
|
||||
class PExpr;
|
||||
class PFunction;
|
||||
class PTaskFunc;
|
||||
struct enum_type_t;
|
||||
class netclass_t;
|
||||
class netdarray_t;
|
||||
class netparray_t;
|
||||
class netqueue_t;
|
||||
class netenum_t;
|
||||
class netstruct_t;
|
||||
class netvector_t;
|
||||
@@ -695,6 +698,7 @@ class NetNet : public NetObj, public PortType {
|
||||
const netenum_t*enumeration(void) const;
|
||||
const netstruct_t*struct_type(void) const;
|
||||
const netdarray_t*darray_type(void) const;
|
||||
const netqueue_t*queue_type(void) const;
|
||||
const netclass_t*class_type(void) const;
|
||||
|
||||
/* Attach a discipline to the net. */
|
||||
@@ -886,6 +890,9 @@ class Definitions {
|
||||
// value.
|
||||
const NetExpr* enumeration_expr(perm_string key);
|
||||
|
||||
// Definitions scopes can also hold classes, by name.
|
||||
void add_class(netclass_t*class_type);
|
||||
|
||||
protected:
|
||||
// Enumerations. The enum_sets_ is a list of all the
|
||||
// enumerations present in this scope. The enum_names_ is a
|
||||
@@ -894,6 +901,9 @@ class Definitions {
|
||||
std::map<const enum_type_t*,netenum_t*> enum_sets_;
|
||||
std::map<perm_string,NetEConstEnum*> enum_names_;
|
||||
|
||||
// This is a map of all the classes (by name) in this scope.
|
||||
std::map<perm_string,netclass_t*> classes_;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -917,6 +927,10 @@ class NetScope : public Definitions, public Attrib {
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* Routine to search for the enumeration given a name. It basically
|
||||
* does what enumeration_for_name() does but searched the hierarchy. */
|
||||
const netenum_t*find_enumeration_for_name(perm_string name);
|
||||
|
||||
/* Parameters exist within a scope, and these methods allow
|
||||
one to manipulate the set. In these cases, the name is the
|
||||
*simple* name of the parameter, the hierarchy is implicit in
|
||||
@@ -974,7 +988,6 @@ class NetScope : public Definitions, public Attrib {
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
void add_class(netclass_t*class_type);
|
||||
netclass_t* find_class(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
@@ -984,6 +997,9 @@ class NetScope : public Definitions, public Attrib {
|
||||
const NetScope* parent() const { return up_; }
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
/* A helper function to find the enclosing class scope. */
|
||||
const NetScope* get_class_scope() const;
|
||||
|
||||
// Look for a child scope by name. This ignores the number
|
||||
// part of the child scope name, so there may be multiple
|
||||
// matches. Only return one. This function is only really
|
||||
@@ -1233,8 +1249,6 @@ class NetScope : public Definitions, public Attrib {
|
||||
const PFunction*func_pform_;
|
||||
unsigned elab_stage_;
|
||||
|
||||
std::map<perm_string,netclass_t*> classes_;
|
||||
|
||||
NetScope*up_;
|
||||
map<hname_t,NetScope*> children_;
|
||||
|
||||
@@ -2027,7 +2041,7 @@ class NetEConst : public NetExpr {
|
||||
/* This method allows the constant value to be converted
|
||||
to an unsized value. This is used after evaluating a
|
||||
unsized constant expression. */
|
||||
virtual void trim();
|
||||
void trim();
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
@@ -2925,6 +2939,8 @@ class NetCase : public NetProc {
|
||||
|
||||
void set_case(unsigned idx, NetExpr*ex, NetProc*st);
|
||||
|
||||
void prune();
|
||||
|
||||
TYPE type() const;
|
||||
const NetExpr*expr() const { return expr_; }
|
||||
inline unsigned nitems() const { return items_.size(); }
|
||||
@@ -3611,6 +3627,31 @@ class NetTaskDef : public NetBaseDef {
|
||||
NetTaskDef& operator= (const NetTaskDef&);
|
||||
};
|
||||
|
||||
/*
|
||||
* The NetELast expression node takes as an argument a net, that is
|
||||
* intended to be a queue or dynamic array object. The return value is
|
||||
* the index of the last item in the node. This is intended to
|
||||
* implement the '$' is the expression "foo[$]".
|
||||
*/
|
||||
class NetELast : public NetExpr {
|
||||
|
||||
public:
|
||||
explicit NetELast(NetNet*sig);
|
||||
~NetELast();
|
||||
|
||||
inline const NetNet*sig() const { return sig_; }
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual void dump(std::ostream&) const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetELast*dup_expr() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
|
||||
private:
|
||||
NetNet*sig_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This node represents a function call in an expression. The object
|
||||
* contains a pointer to the function definition, which is used to
|
||||
@@ -4262,14 +4303,18 @@ class NetENull : public NetExpr {
|
||||
* The NetEProperty represents a SystemVerilog property select of a
|
||||
* class object. In SV, the expression would look like "a.b", where
|
||||
* the "a" is the signal (the NetNet) and "b" is the property name.
|
||||
*
|
||||
* The canon_index is an optional expression to address an element for
|
||||
* parameters that are arrays.
|
||||
*/
|
||||
class NetEProperty : public NetExpr {
|
||||
public:
|
||||
NetEProperty(NetNet*n, perm_string pname);
|
||||
NetEProperty(NetNet*n, perm_string pname, NetExpr*canon_index =0);
|
||||
~NetEProperty();
|
||||
|
||||
inline const NetNet* get_sig() const { return net_; }
|
||||
inline size_t property_idx() const { return pidx_; }
|
||||
inline const NetExpr*get_index() const { return index_; }
|
||||
|
||||
public: // Overridden methods
|
||||
ivl_variable_type_t expr_type() const;
|
||||
@@ -4282,6 +4327,7 @@ class NetEProperty : public NetExpr {
|
||||
private:
|
||||
NetNet*net_;
|
||||
size_t pidx_;
|
||||
NetExpr*index_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -4604,6 +4650,7 @@ class NetECast : public NetEUnary {
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
virtual NetECast* dup_expr() const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
virtual NetExpr* eval_arguments_(const NetExpr*ex) const;
|
||||
@@ -4754,6 +4801,11 @@ class Design : public Definitions {
|
||||
// Look for defparams that never matched, and print warnings.
|
||||
void residual_defparams();
|
||||
|
||||
// Do elaborate_sig for objects in $root scope.
|
||||
void root_elaborate_sig(void);
|
||||
|
||||
void root_elaborate(void);
|
||||
|
||||
/* This method locates a signal, starting at a given
|
||||
scope. The name parameter may be partially hierarchical, so
|
||||
this method, unlike the NetScope::find_signal method,
|
||||
@@ -4766,6 +4818,12 @@ class Design : public Definitions {
|
||||
|
||||
// Tasks
|
||||
NetScope* find_task(NetScope*scope, const pform_name_t&name);
|
||||
void add_root_task(NetScope*tscope, PTaskFunc*tf);
|
||||
std::list<NetScope*> find_roottask_scopes(void) const;
|
||||
|
||||
// Find a class in the $root scope.
|
||||
void add_class(netclass_t*cl, PClass*pclass);
|
||||
netclass_t* find_class(perm_string name) const;
|
||||
|
||||
// NODES
|
||||
void add_node(NetNode*);
|
||||
@@ -4801,6 +4859,12 @@ class Design : public Definitions {
|
||||
// packages do not nest.
|
||||
std::map<perm_string,NetScope*>packages_;
|
||||
|
||||
// Tasks in the $root scope
|
||||
std::map<NetScope*,PTaskFunc*>root_tasks_;
|
||||
|
||||
// Need this for elaboration of $root scope pclass objects.
|
||||
std::map<netclass_t*,PClass*> class_to_pclass_;
|
||||
|
||||
// List the nodes in the design.
|
||||
NetNode*nodes_;
|
||||
// These are in support of the node functor iterator.
|
||||
|
||||
+218
-25
@@ -20,7 +20,9 @@
|
||||
# include "config.h"
|
||||
|
||||
# include <cstdlib>
|
||||
# include <climits>
|
||||
# include "netlist.h"
|
||||
# include "netparray.h"
|
||||
# include "netvector.h"
|
||||
# include "netmisc.h"
|
||||
# include "PExpr.h"
|
||||
@@ -246,16 +248,26 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiple 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.
|
||||
*/
|
||||
static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val)
|
||||
{
|
||||
verinum val_v (val, expr->expr_width());
|
||||
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);
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBMult*res = new NetEBMult('*', expr, val_c, expr->expr_width(),
|
||||
expr->has_sign());
|
||||
// We know by definitions that the expr argument needs to be
|
||||
// padded to be the right argument width for this lossless multiply.
|
||||
expr = pad_to_width(expr, use_wid, *expr);
|
||||
|
||||
NetEBMult*res = new NetEBMult('*', expr, val_c, use_wid, expr->has_sign());
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
@@ -468,6 +480,8 @@ void indices_to_expressions(Design*des, NetScope*scope,
|
||||
const list<index_component_t>&src, unsigned count,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// Total words in target array
|
||||
unsigned need_addr,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices, list<long>&indices_const)
|
||||
@@ -488,7 +502,7 @@ void indices_to_expressions(Design*des, NetScope*scope,
|
||||
}
|
||||
ivl_assert(*loc, cur->msb);
|
||||
|
||||
NetExpr*word_index = elab_and_eval(des, scope, cur->msb, -1, need_const);
|
||||
NetExpr*word_index = elab_and_eval_lossless(des, scope, cur->msb, -2, need_const);
|
||||
|
||||
if (word_index == 0)
|
||||
flags.invalid = true;
|
||||
@@ -525,10 +539,8 @@ static void make_strides(const vector<netrange_t>&dims,
|
||||
* word. If any of the indices are out of bounds, return nil instead
|
||||
* of an expression.
|
||||
*/
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
|
||||
static NetExpr* normalize_variable_unpacked(const vector<netrange_t>&dims, list<long>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = net->unpacked_dims();
|
||||
|
||||
// Make strides for each index. The stride is the distance (in
|
||||
// words) to the next element in the canonical array.
|
||||
vector<long> stride (dims.size());
|
||||
@@ -558,10 +570,20 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
|
||||
return canonical_expr;
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = net->unpacked_dims();
|
||||
return normalize_variable_unpacked(dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const netsarray_t*stype, list<long>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = stype->static_dimensions();
|
||||
return normalize_variable_unpacked(dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const LineInfo&loc, const vector<netrange_t>&dims, list<NetExpr*>&indices)
|
||||
{
|
||||
// Make strides for each index. The stride is the distance (in
|
||||
// words) to the next element in the canonical array.
|
||||
vector<long> stride (dims.size());
|
||||
@@ -594,14 +616,14 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
||||
// losses. So calculate a min_wid width.
|
||||
unsigned tmp_wid;
|
||||
unsigned min_wid = tmp->expr_width();
|
||||
if (use_stride != 1 && ((tmp_wid = num_bits(use_stride)) >= min_wid))
|
||||
min_wid = tmp_wid + 1;
|
||||
if (use_base != 0 && ((tmp_wid = num_bits(use_base)) >= min_wid))
|
||||
min_wid = tmp_wid + 1;
|
||||
if ((tmp_wid = num_bits(dims[idx].width()+1)) >= min_wid)
|
||||
min_wid = tmp_wid + 1;
|
||||
if (use_stride != 1)
|
||||
min_wid += num_bits(use_stride);
|
||||
|
||||
tmp = pad_to_width(tmp, min_wid, *net);
|
||||
tmp = pad_to_width(tmp, min_wid, loc);
|
||||
|
||||
// Now generate the math to calculate the canonical address.
|
||||
NetExpr*tmp_scaled = 0;
|
||||
@@ -640,11 +662,54 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
||||
// If we don't have an expression at this point, all the indices were
|
||||
// constant zero. But this variant of normalize_variable_unpacked()
|
||||
// is only used when at least one index is not a constant.
|
||||
ivl_assert(*net, canonical_expr);
|
||||
ivl_assert(loc, canonical_expr);
|
||||
|
||||
return canonical_expr;
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = net->unpacked_dims();
|
||||
return normalize_variable_unpacked(*net, dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*stype, list<NetExpr*>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = stype->static_dimensions();
|
||||
return normalize_variable_unpacked(loc, dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* make_canonical_index(Design*des, NetScope*scope,
|
||||
const LineInfo*loc,
|
||||
const std::list<index_component_t>&src,
|
||||
const netsarray_t*stype,
|
||||
bool need_const)
|
||||
{
|
||||
NetExpr*canon_index = 0;
|
||||
|
||||
list<long> indices_const;
|
||||
list<NetExpr*> indices_expr;
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc,
|
||||
src, src.size(),
|
||||
need_const, stype->static_dimensions().size(),
|
||||
flags,
|
||||
indices_expr, indices_const);
|
||||
|
||||
if (flags.undefined) {
|
||||
cerr << loc->get_fileline() << ": warning: "
|
||||
<< "ignoring undefined value array access." << endl;
|
||||
|
||||
} else if (flags.variable) {
|
||||
canon_index = normalize_variable_unpacked(*loc, stype, indices_expr);
|
||||
|
||||
} else {
|
||||
canon_index = normalize_variable_unpacked(stype, indices_const);
|
||||
}
|
||||
|
||||
return canon_index;
|
||||
}
|
||||
|
||||
NetEConst* make_const_x(unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
@@ -666,6 +731,14 @@ NetEConst* make_const_val(unsigned long value)
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* make_const_val_s(long value)
|
||||
{
|
||||
verinum tmp (value, integer_width);
|
||||
tmp.has_sign(true);
|
||||
NetEConst*res = new NetEConst(tmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
@@ -730,13 +803,16 @@ NetExpr* condition_reduce(NetExpr*expr)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
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)
|
||||
{
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
if ((context_width == -2) && !gn_strict_expr_width_flag)
|
||||
mode = PExpr::EXPAND;
|
||||
if (force_expand)
|
||||
mode = PExpr::EXPAND;
|
||||
|
||||
pe->test_width(des, scope, mode);
|
||||
|
||||
@@ -755,8 +831,10 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
<< *pe << endl;
|
||||
cerr << pe->get_fileline() << ": : "
|
||||
<< "returns type=" << pe->expr_type()
|
||||
<< ", width=" << expr_width
|
||||
<< ", context_width=" << context_width
|
||||
<< ", signed=" << pe->has_sign()
|
||||
<< ", force_expand=" << force_expand
|
||||
<< ", expr_width=" << expr_width
|
||||
<< ", mode=" << PExpr::width_mode_name(mode) << endl;
|
||||
cerr << pe->get_fileline() << ": : "
|
||||
<< "cast_type=" << cast_type << endl;
|
||||
@@ -764,12 +842,14 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
|
||||
// If we can get the same result using a smaller expression
|
||||
// width, do so.
|
||||
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
|
||||
&& (expr_width > pos_context_width)) {
|
||||
expr_width = max(pe->min_width(), pos_context_width);
|
||||
|
||||
unsigned min_width = pe->min_width();
|
||||
if ((min_width != UINT_MAX) && (pe->expr_type() != IVL_VT_REAL)
|
||||
&& (pos_context_width > 0) && (expr_width > pos_context_width)) {
|
||||
expr_width = max(min_width, pos_context_width);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": "
|
||||
cerr << pe->get_fileline() << ": : "
|
||||
<< "pruned to width=" << expr_width << endl;
|
||||
}
|
||||
}
|
||||
@@ -789,6 +869,11 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
if (annotatable)
|
||||
flags |= PExpr::ANNOTATABLE;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": elab_and_eval: "
|
||||
<< "Calculated width is " << expr_width << "." << endl;
|
||||
}
|
||||
|
||||
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, flags);
|
||||
if (tmp == 0) return 0;
|
||||
|
||||
@@ -808,6 +893,13 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
}
|
||||
}
|
||||
|
||||
// If the context_width sent is is actually the minimim width,
|
||||
// then raise the context_width to be big enough for the
|
||||
// lossless expression.
|
||||
if (force_expand && context_width > 0) {
|
||||
context_width = max(context_width, (int)expr_width);
|
||||
}
|
||||
|
||||
eval_expr(tmp, context_width);
|
||||
|
||||
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {
|
||||
@@ -818,6 +910,27 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
{
|
||||
return do_elab_and_eval(des, scope, pe, context_width,
|
||||
need_const, annotatable, false, cast_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* This variant of elab_and_eval does the expression losslessly, no
|
||||
* 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,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
{
|
||||
return do_elab_and_eval(des, scope, pe, context_width,
|
||||
need_const, annotatable, true, cast_type);
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
ivl_type_t lv_net_type, bool need_const)
|
||||
{
|
||||
@@ -868,13 +981,59 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
|
||||
// determine the exact width required to hold the result.
|
||||
// But leave literal numbers exactly as the user supplied
|
||||
// them.
|
||||
if ((mode >= PExpr::LOSSLESS) && !dynamic_cast<PENumber*>(pe))
|
||||
if ((mode >= PExpr::LOSSLESS) && !dynamic_cast<PENumber*>(pe) && tmp->expr_width()>32)
|
||||
ce->trim();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
vector<netrange_t>&llist,
|
||||
const list<pform_range_t>&rlist)
|
||||
{
|
||||
bool bad_msb = false, bad_lsb = false;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = rlist.begin()
|
||||
; cur != rlist.end() ; ++cur) {
|
||||
long use_msb, use_lsb;
|
||||
|
||||
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
|
||||
if (! eval_as_long(use_msb, texpr)) {
|
||||
cerr << cur->first->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->first->get_fileline() << " : "
|
||||
"This MSB expression violates the rule: "
|
||||
<< *cur->first << endl;
|
||||
des->errors += 1;
|
||||
bad_msb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
texpr = elab_and_eval(des, scope, cur->second, -1, true);
|
||||
if (! eval_as_long(use_lsb, texpr)) {
|
||||
cerr << cur->second->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->second->get_fileline() << " : "
|
||||
"This LSB expression violates the rule: "
|
||||
<< *cur->second << endl;
|
||||
des->errors += 1;
|
||||
bad_lsb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
/* Error recovery */
|
||||
if (bad_lsb) use_lsb = 0;
|
||||
if (bad_msb) use_msb = use_lsb;
|
||||
|
||||
llist.push_back(netrange_t(use_msb, use_lsb));
|
||||
}
|
||||
|
||||
return bad_msb | bad_lsb;
|
||||
}
|
||||
|
||||
void eval_expr(NetExpr*&expr, int context_width)
|
||||
{
|
||||
assert(expr);
|
||||
@@ -1269,7 +1428,7 @@ NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc, indices,
|
||||
net->packed_dimensions(),
|
||||
false, flags, exprs, exprs_const);
|
||||
false, net->unpacked_count(), flags, exprs, exprs_const);
|
||||
ivl_assert(*loc, exprs.size() == net->packed_dimensions());
|
||||
|
||||
// Special Case: there is only 1 packed dimension, so the
|
||||
@@ -1285,11 +1444,12 @@ NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
NetExpr* base = 0;
|
||||
for (size_t idx = 0 ; idx < net->packed_dimensions() ; idx += 1, ++pcur, ++ecur) {
|
||||
unsigned cur_slice_width = net->slice_width(idx+1);
|
||||
long lsb = pcur->get_lsb();
|
||||
long msb = pcur->get_msb();
|
||||
// This normalizes the expression of this index based on
|
||||
// the msb/lsb values.
|
||||
NetExpr*tmp = normalize_variable_base(*ecur, pcur->get_msb(),
|
||||
pcur->get_lsb(),
|
||||
cur_slice_width, true);
|
||||
NetExpr*tmp = normalize_variable_base(*ecur, msb, lsb,
|
||||
cur_slice_width, msb > lsb);
|
||||
|
||||
// If this slice has width, then scale it.
|
||||
if (net->slice_width(idx+1) != 1) {
|
||||
@@ -1423,3 +1583,36 @@ NetPartSelect* detect_partselect_lval(Link&pin)
|
||||
|
||||
return found_ps;
|
||||
}
|
||||
|
||||
const netclass_t* find_class_containing_scope(const LineInfo&loc, const NetScope*scope)
|
||||
{
|
||||
while (scope && scope->type() != NetScope::CLASS)
|
||||
scope = scope->parent();
|
||||
|
||||
if (scope == 0)
|
||||
return 0;
|
||||
|
||||
const netclass_t*found_in = scope->class_def();
|
||||
ivl_assert(loc, found_in);
|
||||
return found_in;
|
||||
}
|
||||
/*
|
||||
* Find the scope that contains this scope, that is the method for a
|
||||
* class scope. Look for the scope whose PARENT is the scope for a
|
||||
* class. This is going to be a method.
|
||||
*/
|
||||
NetScope* find_method_containing_scope(const LineInfo&, NetScope*scope)
|
||||
{
|
||||
NetScope*up = scope->parent();
|
||||
|
||||
while (up && up->type() != NetScope::CLASS) {
|
||||
scope = up;
|
||||
up = up->parent();
|
||||
}
|
||||
|
||||
if (up == 0) return 0;
|
||||
|
||||
// Should I check if this scope is a TASK or FUNC?
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
class netsarray_t;
|
||||
|
||||
/*
|
||||
* Search for a symbol using the "start" scope as the starting
|
||||
* point. If the path includes a scope part, then locate the
|
||||
@@ -179,12 +181,27 @@ extern void indices_to_expressions(Design*des, NetScope*scope,
|
||||
const list<index_component_t>&src, unsigned count,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// Total array size, for sizing expressions
|
||||
unsigned need_addr,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices,list<long>&indices_const);
|
||||
|
||||
extern NetExpr*normalize_variable_unpacked(const NetNet*net, list<long>&indices);
|
||||
extern NetExpr*normalize_variable_unpacked(const netsarray_t*net, list<long>&indices);
|
||||
|
||||
extern NetExpr*normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices);
|
||||
extern NetExpr*normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*net, list<NetExpr*>&indices);
|
||||
|
||||
extern NetExpr*make_canonical_index(Design*des, NetScope*scope,
|
||||
// loc for error messages
|
||||
const LineInfo*loc,
|
||||
// src is the index list
|
||||
const std::list<index_component_t>&src,
|
||||
// This is the reference type
|
||||
const netsarray_t*stype,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const);
|
||||
|
||||
/*
|
||||
* This function takes as input a NetNet signal and adds a constant
|
||||
@@ -204,6 +221,7 @@ extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
|
||||
extern NetEConst*make_const_x(unsigned long wid);
|
||||
extern NetEConst*make_const_0(unsigned long wid);
|
||||
extern NetEConst*make_const_val(unsigned long val);
|
||||
extern NetEConst*make_const_val_s(long val);
|
||||
|
||||
/*
|
||||
* Make A const net
|
||||
@@ -244,6 +262,12 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
bool annotatable =false,
|
||||
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
|
||||
|
||||
extern NetExpr* elab_and_eval_lossless(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);
|
||||
|
||||
/*
|
||||
* This form of elab_and_eval uses the ivl_type_t to carry type
|
||||
* information instead of the piecemeal form. We should transition to
|
||||
@@ -277,6 +301,9 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
|
||||
unsigned lv_width, PExpr*expr,
|
||||
bool need_const =false);
|
||||
|
||||
extern bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
std::vector<netrange_t>&llist,
|
||||
const std::list<pform_range_t>&rlist);
|
||||
/*
|
||||
* This procedure evaluates an expression and if the evaluation is
|
||||
* successful the original expression is replaced with the new one.
|
||||
@@ -300,6 +327,13 @@ extern hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp,
|
||||
bool&error_flag);
|
||||
|
||||
/*
|
||||
* If this scope is contained within a class scope (i.e. a method of a
|
||||
* class) then return the class definition that contains it.
|
||||
*/
|
||||
extern const netclass_t*find_class_containing_scope(const LineInfo&loc,const NetScope*scope);
|
||||
extern NetScope* find_method_containing_scope(const LineInfo&log, NetScope*scope);
|
||||
|
||||
/*
|
||||
* Return true if the data type is a type that is normally available
|
||||
* in vector for. IVL_VT_BOOL and IVL_VT_LOGIC are vectorable,
|
||||
|
||||
+21
-6
@@ -22,6 +22,10 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
netsarray_t::~netsarray_t()
|
||||
{
|
||||
}
|
||||
|
||||
netparray_t::~netparray_t()
|
||||
{
|
||||
}
|
||||
@@ -34,8 +38,8 @@ long netparray_t::packed_width(void) const
|
||||
{
|
||||
long cur_width = element_type()->packed_width();
|
||||
|
||||
for (vector<netrange_t>::const_iterator cur = packed_dims_.begin()
|
||||
; cur != packed_dims_.end() ; ++cur) {
|
||||
for (vector<netrange_t>::const_iterator cur = static_dimensions().begin()
|
||||
; cur != static_dimensions().end() ; ++cur) {
|
||||
cur_width *= cur->width();
|
||||
}
|
||||
|
||||
@@ -44,14 +48,25 @@ long netparray_t::packed_width(void) const
|
||||
|
||||
vector<netrange_t> netparray_t::slice_dimensions() const
|
||||
{
|
||||
const vector<netrange_t>&packed_dims = static_dimensions();
|
||||
|
||||
vector<netrange_t> elem_dims = element_type()->slice_dimensions();
|
||||
|
||||
vector<netrange_t> res (packed_dims_.size() + elem_dims.size());
|
||||
vector<netrange_t> res (packed_dims.size() + elem_dims.size());
|
||||
|
||||
for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1)
|
||||
res[idx] = packed_dims_[idx];
|
||||
for (size_t idx = 0 ; idx < packed_dims.size() ; idx += 1)
|
||||
res[idx] = packed_dims[idx];
|
||||
for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1)
|
||||
res[idx+packed_dims_.size()] = elem_dims[idx];
|
||||
res[idx+packed_dims.size()] = elem_dims[idx];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
netuarray_t::~netuarray_t()
|
||||
{
|
||||
}
|
||||
|
||||
vector<netrange_t> netuarray_t::slice_dimensions() const
|
||||
{
|
||||
return static_dimensions();
|
||||
}
|
||||
|
||||
+52
-9
@@ -23,10 +23,39 @@
|
||||
# include "nettypes.h"
|
||||
# include <vector>
|
||||
|
||||
/*
|
||||
* Arrays with static dimensions (packed and unpacked) share this
|
||||
* common base type.
|
||||
*/
|
||||
class netsarray_t : public netarray_t {
|
||||
|
||||
public:
|
||||
explicit netsarray_t(const std::vector<netrange_t>&packed,
|
||||
ivl_type_t etype);
|
||||
~netsarray_t();
|
||||
|
||||
public:
|
||||
// Virtual methods from the ivl_type_s type...
|
||||
|
||||
public:
|
||||
inline const std::vector<netrange_t>& static_dimensions() const
|
||||
{ return dims_; }
|
||||
|
||||
private:
|
||||
std::vector<netrange_t> dims_;
|
||||
|
||||
};
|
||||
|
||||
inline netsarray_t::netsarray_t(const std::vector<netrange_t>&pd,
|
||||
ivl_type_t etype)
|
||||
: netarray_t(etype), dims_(pd)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Packed arrays.
|
||||
*/
|
||||
class netparray_t : public netarray_t {
|
||||
class netparray_t : public netsarray_t {
|
||||
|
||||
public:
|
||||
explicit netparray_t(const std::vector<netrange_t>&packed,
|
||||
@@ -38,18 +67,32 @@ class netparray_t : public netarray_t {
|
||||
long packed_width(void) const;
|
||||
std::vector<netrange_t> slice_dimensions() const;
|
||||
|
||||
public:
|
||||
inline const std::vector<netrange_t>& packed_dimensions() const
|
||||
{ return packed_dims_; }
|
||||
|
||||
private:
|
||||
std::vector<netrange_t> packed_dims_;
|
||||
|
||||
};
|
||||
|
||||
inline netparray_t::netparray_t(const std::vector<netrange_t>&pd,
|
||||
ivl_type_t etype)
|
||||
: netarray_t(etype), packed_dims_(pd)
|
||||
: netsarray_t(pd, etype)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpacked arrays are very similar, but lack packed slices.
|
||||
*/
|
||||
class netuarray_t : public netsarray_t {
|
||||
|
||||
public:
|
||||
explicit netuarray_t(const std::vector<netrange_t>&packed,
|
||||
ivl_type_t etype);
|
||||
~netuarray_t();
|
||||
|
||||
public:
|
||||
// Virtual methods from the ivl_type_s type...
|
||||
std::vector<netrange_t> slice_dimensions() const;
|
||||
};
|
||||
|
||||
inline netuarray_t::netuarray_t(const std::vector<netrange_t>&pd,
|
||||
ivl_type_t etype)
|
||||
: netsarray_t(pd, etype)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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 "netqueue.h"
|
||||
# include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
netqueue_t::netqueue_t(ivl_type_t vec)
|
||||
: netdarray_t(vec)
|
||||
{
|
||||
}
|
||||
|
||||
netqueue_t::~netqueue_t()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t netqueue_t::base_type() const
|
||||
{
|
||||
return IVL_VT_QUEUE;
|
||||
}
|
||||
|
||||
bool netqueue_t::test_compatibility(ivl_type_t that) const
|
||||
{
|
||||
const netqueue_t*that_q = dynamic_cast<const netqueue_t*>(that);
|
||||
if (that_q == 0)
|
||||
return false;
|
||||
|
||||
return element_type()->type_compatible(that_q->element_type());
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#ifndef IVL__netqueue_H
|
||||
#define IVL__netqueue_H
|
||||
/*
|
||||
* Copyright (c) 2014 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 "netdarray.h"
|
||||
# include "ivl_target.h"
|
||||
|
||||
/*
|
||||
* A queue type is actually a dynamic array with a few extra
|
||||
* methods. This will probably result in a different implementation at
|
||||
* run-time, but for the most part this applies during elaboration.
|
||||
*/
|
||||
class netqueue_t : public netdarray_t {
|
||||
|
||||
public:
|
||||
explicit netqueue_t(ivl_type_t vec);
|
||||
~netqueue_t();
|
||||
|
||||
// This is the "base_type()" virtual method of the
|
||||
// nettype_base_t. The ivl_target api expects this to return
|
||||
// IVL_VT_QUEUE for queues.
|
||||
ivl_variable_type_t base_type() const;
|
||||
|
||||
std::ostream& debug_dump(std::ostream&) const;
|
||||
|
||||
private:
|
||||
bool test_compatibility(ivl_type_t that) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -70,6 +70,8 @@ class netarray_t : public ivl_type_s {
|
||||
|
||||
public:
|
||||
// Some virtual methods have a common implementation for arrays.
|
||||
|
||||
// The base_type() for arrays is the base_Typeof the element.
|
||||
ivl_variable_type_t base_type() const;
|
||||
|
||||
public:
|
||||
|
||||
@@ -93,13 +93,26 @@ static list<named_pexpr_t>*attributes_in_context = 0;
|
||||
/* Recent version of bison expect that the user supply a
|
||||
YYLLOC_DEFAULT macro that makes up a yylloc value from existing
|
||||
values. I need to supply an explicit version to account for the
|
||||
text field, that otherwise won't be copied. */
|
||||
# define YYLLOC_DEFAULT(Current, Rhs, N) do { \
|
||||
(Current).first_line = (Rhs)[1].first_line; \
|
||||
(Current).first_column = (Rhs)[1].first_column; \
|
||||
(Current).last_line = (Rhs)[N].last_line; \
|
||||
(Current).last_column = (Rhs)[N].last_column; \
|
||||
(Current).text = (Rhs)[1].text; } while (0)
|
||||
text field, that otherwise won't be copied.
|
||||
|
||||
The YYLLOC_DEFAULT blends the file range for the tokens of Rhs
|
||||
rule, which has N tokens.
|
||||
*/
|
||||
# define YYLLOC_DEFAULT(Current, Rhs, N) do { \
|
||||
if (N) { \
|
||||
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
|
||||
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
|
||||
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
|
||||
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
|
||||
(Current).text = YYRHSLOC (Rhs, 1).text; \
|
||||
} else { \
|
||||
(Current).first_line = YYRHSLOC (Rhs, 0).last_line; \
|
||||
(Current).first_column = YYRHSLOC (Rhs, 0).last_column; \
|
||||
(Current).last_line = YYRHSLOC (Rhs, 0).last_line; \
|
||||
(Current).last_column = YYRHSLOC (Rhs, 0).last_column; \
|
||||
(Current).text = YYRHSLOC (Rhs, 0).text; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* These are some common strength pairs that are used as defaults when
|
||||
@@ -263,7 +276,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector<Statement*>*s)
|
||||
if (s == 0) {
|
||||
/* if the statement list is null, then the parser
|
||||
detected the case that there are no statements in the
|
||||
task. If this is System Verilog, handle it as an
|
||||
task. If this is SystemVerilog, handle it as an
|
||||
an empty block. */
|
||||
if (!gn_system_verilog()) {
|
||||
yyerror(loc, "error: Support for empty tasks requires SystemVerilog.");
|
||||
@@ -301,7 +314,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
||||
if (s == 0) {
|
||||
/* if the statement list is null, then the parser
|
||||
detected the case that there are no statements in the
|
||||
task. If this is System Verilog, handle it as an
|
||||
task. If this is SystemVerilog, handle it as an
|
||||
an empty block. */
|
||||
if (!gn_system_verilog()) {
|
||||
yyerror(loc, "error: Support for empty functions requires SystemVerilog.");
|
||||
@@ -532,8 +545,6 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
||||
%token K_resolveto K_sin K_sinh K_slew K_split K_sqrt K_tan K_tanh
|
||||
%token K_timer K_transition K_units K_white_noise K_wreal
|
||||
%token K_zi_nd K_zi_np K_zi_zd K_zi_zp
|
||||
/* Support some meta-comments as pragmas. */
|
||||
%token K_MC_TRANSLATE_ON K_MC_TRANSLATE_OFF
|
||||
|
||||
%type <flag> from_exclude block_item_decls_opt
|
||||
%type <number> number pos_neg_number
|
||||
@@ -833,6 +844,30 @@ class_item /* IEEE1800-2005: A.1.8 */
|
||||
| method_qualifier_opt function_declaration
|
||||
{ /* The function_declaration rule puts this into the class */ }
|
||||
|
||||
/* External class method definitions... */
|
||||
|
||||
| K_extern method_qualifier_opt K_function K_new ';'
|
||||
{ yyerror(@1, "sorry: External constructors are not yet supported."); }
|
||||
| K_extern method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';'
|
||||
{ yyerror(@1, "sorry: External constructors are not yet supported."); }
|
||||
| K_extern method_qualifier_opt K_function data_type_or_implicit_or_void
|
||||
IDENTIFIER ';'
|
||||
{ yyerror(@1, "sorry: External methods are not yet supported.");
|
||||
delete[] $5;
|
||||
}
|
||||
| K_extern method_qualifier_opt K_function data_type_or_implicit_or_void
|
||||
IDENTIFIER '(' tf_port_list_opt ')' ';'
|
||||
{ yyerror(@1, "sorry: External methods are not yet supported.");
|
||||
delete[] $5;
|
||||
}
|
||||
| K_extern method_qualifier_opt K_task IDENTIFIER ';'
|
||||
{ yyerror(@1, "sorry: External methods are not yet supported.");
|
||||
delete[] $4;
|
||||
}
|
||||
| K_extern method_qualifier_opt K_task IDENTIFIER '(' tf_port_list_opt ')' ';'
|
||||
{ yyerror(@1, "sorry: External methods are not yet supported.");
|
||||
delete[] $4;
|
||||
}
|
||||
|
||||
/* Class constraints... */
|
||||
|
||||
@@ -1020,8 +1055,11 @@ data_type /* IEEE1800-2005: A.2.2.1 */
|
||||
$$ = tmp;
|
||||
}
|
||||
| TYPE_IDENTIFIER dimensions_opt
|
||||
{ if ($2) $$ = new parray_type_t($1.type, $2);
|
||||
else $$ = $1.type;
|
||||
{ if ($2) {
|
||||
parray_type_t*tmp = new parray_type_t($1.type, $2);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
} else $$ = $1.type;
|
||||
delete[]$1.text;
|
||||
}
|
||||
| PACKAGE_IDENTIFIER K_SCOPE_RES
|
||||
@@ -1162,7 +1200,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@11, "error: Function end label require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$11;
|
||||
}
|
||||
@@ -1196,7 +1234,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@14, "error: Function end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$14;
|
||||
}
|
||||
@@ -1223,7 +1261,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@8, "error: Function end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$8;
|
||||
}
|
||||
@@ -1378,12 +1416,29 @@ loop_statement /* IEEE1800-2005: A.6.8 */
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null
|
||||
{ yyerror(@1, "sorry: foreach loops not supported");
|
||||
delete[]$3;
|
||||
delete $5;
|
||||
delete $8;
|
||||
$$ = 0;
|
||||
// When matching a foreach loop, implicitly create a named block
|
||||
// to hold the definitions for the index variables.
|
||||
| K_foreach '(' IDENTIFIER '[' loop_variables ']' ')'
|
||||
{ static unsigned foreach_counter = 0;
|
||||
char for_block_name[64];
|
||||
snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter);
|
||||
foreach_counter += 1;
|
||||
|
||||
PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
|
||||
FILE_NAME(tmp, @1);
|
||||
current_block_stack.push(tmp);
|
||||
|
||||
pform_make_foreach_declarations(@1, $5);
|
||||
}
|
||||
statement_or_null
|
||||
{ PForeach*tmp_for = pform_make_foreach(@1, $3, $5, $9);
|
||||
|
||||
pform_pop_scope();
|
||||
vector<Statement*>tmp_for_list(1);
|
||||
tmp_for_list[0] = tmp_for;
|
||||
PBlock*tmp_blk = current_block_stack.top();
|
||||
tmp_blk->set_statement(tmp_for_list);
|
||||
$$ = tmp_blk;
|
||||
}
|
||||
|
||||
/* Error forms for loop statements. */
|
||||
@@ -1574,6 +1629,7 @@ package_item /* IEEE1800-2005 A.1.10 */
|
||||
| function_declaration
|
||||
| task_declaration
|
||||
| data_declaration
|
||||
| class_declaration
|
||||
;
|
||||
|
||||
package_item_list
|
||||
@@ -1739,7 +1795,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@10, "error: Task end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$10;
|
||||
}
|
||||
@@ -1773,7 +1829,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@13, "error: Task end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$13;
|
||||
}
|
||||
@@ -1813,7 +1869,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@12, "error: Task end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$12;
|
||||
}
|
||||
@@ -1836,7 +1892,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@7, "error: Task end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$7;
|
||||
}
|
||||
@@ -2043,11 +2099,9 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
|
||||
| '[' '$' ']'
|
||||
{ // SystemVerilog queue
|
||||
list<pform_range_t> *tmp = new list<pform_range_t>;
|
||||
pform_range_t index (0,0);
|
||||
if (gn_system_verilog()) {
|
||||
yyerror("sorry: Dynamic array ranges not supported.");
|
||||
} else {
|
||||
yyerror("error: Queue declarations require System Verilog.");
|
||||
pform_range_t index (new PENull,0);
|
||||
if (!gn_system_verilog()) {
|
||||
yyerror("error: Queue declarations require SystemVerilog.");
|
||||
}
|
||||
tmp->push_back(index);
|
||||
$$ = tmp;
|
||||
@@ -2058,9 +2112,11 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
|
||||
variety of different objects. The syntax inside the (* *) is a
|
||||
comma separated list of names or names with assigned values. */
|
||||
attribute_list_opt
|
||||
: attribute_instance_list
|
||||
| { $$ = 0; }
|
||||
;
|
||||
: attribute_instance_list
|
||||
{ $$ = $1; }
|
||||
|
|
||||
{ $$ = 0; }
|
||||
;
|
||||
|
||||
attribute_instance_list
|
||||
: K_PSTAR K_STARP { $$ = 0; }
|
||||
@@ -2243,6 +2299,7 @@ enum_data_type
|
||||
enum_type->names .reset($3);
|
||||
enum_type->base_type = IVL_VT_BOOL;
|
||||
enum_type->signed_flag = true;
|
||||
enum_type->integer_flag = false;
|
||||
enum_type->range.reset(make_range_from_width(32));
|
||||
$$ = enum_type;
|
||||
}
|
||||
@@ -2252,6 +2309,7 @@ enum_data_type
|
||||
enum_type->names .reset($5);
|
||||
enum_type->base_type = IVL_VT_BOOL;
|
||||
enum_type->signed_flag = $3;
|
||||
enum_type->integer_flag = false;
|
||||
enum_type->range.reset(make_range_from_width($2));
|
||||
$$ = enum_type;
|
||||
}
|
||||
@@ -2261,6 +2319,7 @@ enum_data_type
|
||||
enum_type->names .reset($5);
|
||||
enum_type->base_type = IVL_VT_LOGIC;
|
||||
enum_type->signed_flag = $3;
|
||||
enum_type->integer_flag = true;
|
||||
enum_type->range.reset(make_range_from_width(integer_width));
|
||||
$$ = enum_type;
|
||||
}
|
||||
@@ -2270,6 +2329,7 @@ enum_data_type
|
||||
enum_type->names .reset($6);
|
||||
enum_type->base_type = IVL_VT_LOGIC;
|
||||
enum_type->signed_flag = $3;
|
||||
enum_type->integer_flag = false;
|
||||
enum_type->range.reset($4);
|
||||
$$ = enum_type;
|
||||
}
|
||||
@@ -2279,6 +2339,7 @@ enum_data_type
|
||||
enum_type->names .reset($6);
|
||||
enum_type->base_type = IVL_VT_LOGIC;
|
||||
enum_type->signed_flag = $3;
|
||||
enum_type->integer_flag = false;
|
||||
enum_type->range.reset($4);
|
||||
$$ = enum_type;
|
||||
}
|
||||
@@ -2288,6 +2349,7 @@ enum_data_type
|
||||
enum_type->names .reset($6);
|
||||
enum_type->base_type = IVL_VT_BOOL;
|
||||
enum_type->signed_flag = $3;
|
||||
enum_type->integer_flag = false;
|
||||
enum_type->range.reset($4);
|
||||
$$ = enum_type;
|
||||
}
|
||||
@@ -3182,7 +3244,7 @@ expr_primary
|
||||
|
||||
/* An identifier followed by an expression list in parentheses is a
|
||||
function call. If a system identifier, then a system function
|
||||
call. */
|
||||
call. It can also be a call to a class method (functino). */
|
||||
|
||||
| hierarchy_identifier '(' expression_list_with_nuls ')'
|
||||
{ list<PExpr*>*expr_list = $3;
|
||||
@@ -3191,6 +3253,19 @@ expr_primary
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')'
|
||||
{ pform_name_t*t_name = $1;
|
||||
while (! $3->empty()) {
|
||||
t_name->push_back($3->front());
|
||||
$3->pop_front();
|
||||
}
|
||||
list<PExpr*>*expr_list = $5;
|
||||
strip_tail_items(expr_list);
|
||||
PECallFunction*tmp = pform_make_call_function(@1, *t_name, *expr_list);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
|
||||
{ perm_string tn = lex_strings.make($1);
|
||||
PECallFunction*tmp = new PECallFunction(tn, *$3);
|
||||
@@ -3225,12 +3300,12 @@ expr_primary
|
||||
}
|
||||
|
||||
| implicit_class_handle '.' hierarchy_identifier
|
||||
{ pform_name_t*nam = $1;
|
||||
{ pform_name_t*t_name = $1;
|
||||
while (! $3->empty()) {
|
||||
nam->push_back($3->front());
|
||||
t_name->push_back($3->front());
|
||||
$3->pop_front();
|
||||
}
|
||||
PEIdent*tmp = new PEIdent(*nam);
|
||||
PEIdent*tmp = new PEIdent(*t_name);
|
||||
FILE_NAME(tmp,@1);
|
||||
delete $1;
|
||||
delete $3;
|
||||
@@ -3443,11 +3518,14 @@ expr_primary
|
||||
| '{' '}'
|
||||
{ // This is the empty queue syntax.
|
||||
if (gn_system_verilog()) {
|
||||
yyerror(@1, "sorry: Expty queue expressions not supported.");
|
||||
list<PExpr*> empty_list;
|
||||
PEConcat*tmp = new PEConcat(empty_list);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
} else {
|
||||
yyerror(@1, "error: Concatenations are not allowed to be empty.");
|
||||
$$ = 0;
|
||||
}
|
||||
$$ = 0;
|
||||
}
|
||||
|
||||
/* Cast expressions are primaries */
|
||||
@@ -3465,6 +3543,18 @@ expr_primary
|
||||
}
|
||||
}
|
||||
|
||||
| data_type '\'' '(' expression ')'
|
||||
{ PExpr*base = $4;
|
||||
if (gn_system_verilog()) {
|
||||
PECastType*tmp = new PECastType($1, base);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
} else {
|
||||
yyerror(@1, "error: Type cast requires SystemVerilog.");
|
||||
$$ = base;
|
||||
}
|
||||
}
|
||||
|
||||
/* Aggregate literals are primaries. */
|
||||
|
||||
| assignment_pattern
|
||||
@@ -3704,6 +3794,20 @@ hierarchy_identifier
|
||||
tail.index.push_back(itmp);
|
||||
$$ = tmp;
|
||||
}
|
||||
| hierarchy_identifier '[' '$' ']'
|
||||
{ pform_name_t * tmp = $1;
|
||||
name_component_t&tail = tmp->back();
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@3, "error: Last element expression ($) "
|
||||
"requires SystemVerilog. Try enabling SystemVerilog.");
|
||||
}
|
||||
index_component_t itmp;
|
||||
itmp.sel = index_component_t::SEL_BIT_LAST;
|
||||
itmp.msb = 0;
|
||||
itmp.lsb = 0;
|
||||
tail.index.push_back(itmp);
|
||||
$$ = tmp;
|
||||
}
|
||||
| hierarchy_identifier '[' expression ':' expression ']'
|
||||
{ pform_name_t * tmp = $1;
|
||||
name_component_t&tail = tmp->back();
|
||||
@@ -4020,15 +4124,15 @@ lpvalue
|
||||
}
|
||||
|
||||
| implicit_class_handle '.' hierarchy_identifier
|
||||
{ pform_name_t*tmp1 = $1;
|
||||
{ pform_name_t*t_name = $1;
|
||||
while (!$3->empty()) {
|
||||
tmp1->push_back($3->front());
|
||||
t_name->push_back($3->front());
|
||||
$3->pop_front();
|
||||
}
|
||||
PEIdent*tmp = new PEIdent(*tmp1);
|
||||
PEIdent*tmp = new PEIdent(*t_name);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
delete tmp1;
|
||||
delete $1;
|
||||
delete $3;
|
||||
}
|
||||
|
||||
@@ -4185,7 +4289,7 @@ module
|
||||
}
|
||||
if (($2 == K_module) && (! gn_system_verilog())) {
|
||||
yyerror(@8, "error: Module end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$16;
|
||||
}
|
||||
@@ -4248,13 +4352,6 @@ module_item
|
||||
/* Modules can contain further sub-module definitions. */
|
||||
: module
|
||||
|
||||
/* The lexor detects "// synthesis translate_on/off" meta-comments,
|
||||
we handle them here by turning on/off a flag. The pform uses
|
||||
that flag to attach implicit attributes to "initial" and
|
||||
"always" statements. */
|
||||
| K_MC_TRANSLATE_OFF { pform_mc_translate_on(false); }
|
||||
| K_MC_TRANSLATE_ON { pform_mc_translate_on(true); }
|
||||
|
||||
| attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';'
|
||||
|
||||
{ data_type_t*data_type = $3;
|
||||
@@ -4620,7 +4717,7 @@ module_item
|
||||
if ($4) {
|
||||
if (!gn_system_verilog()) {
|
||||
yyerror(@4, "error: Function end names require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$4;
|
||||
}
|
||||
@@ -4692,7 +4789,7 @@ generate_block
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@6, "error: Begin end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$6;
|
||||
}
|
||||
@@ -5684,7 +5781,7 @@ statement_item /* This is roughly statement_item in the LRM */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@8, "error: Begin end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$8;
|
||||
}
|
||||
@@ -5759,7 +5856,7 @@ statement_item /* This is roughly statement_item in the LRM */
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@8, "error: Fork end labels require "
|
||||
"System Verilog.");
|
||||
"SystemVerilog.");
|
||||
}
|
||||
delete[]$8;
|
||||
}
|
||||
@@ -6006,12 +6103,12 @@ statement_item /* This is roughly statement_item in the LRM */
|
||||
}
|
||||
|
||||
| implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';'
|
||||
{ pform_name_t*nam = $1;
|
||||
{ pform_name_t*t_name = $1;
|
||||
while (! $3->empty()) {
|
||||
nam->push_back($3->front());
|
||||
t_name->push_back($3->front());
|
||||
$3->pop_front();
|
||||
}
|
||||
PCallTask*tmp = new PCallTask(*nam, *$5);
|
||||
PCallTask*tmp = new PCallTask(*t_name, *$5);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
delete $3;
|
||||
@@ -6036,6 +6133,7 @@ statement_item /* This is roughly statement_item in the LRM */
|
||||
| implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';'
|
||||
{ PChainConstructor*tmp = new PChainConstructor(*$5);
|
||||
FILE_NAME(tmp, @3);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| hierarchy_identifier '(' error ')' ';'
|
||||
@@ -6428,7 +6526,7 @@ udp_primitive
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@11, "error: Primitive end labels "
|
||||
"require System Verilog.");
|
||||
"require SystemVerilog.");
|
||||
}
|
||||
delete[]$11;
|
||||
}
|
||||
@@ -6455,7 +6553,7 @@ udp_primitive
|
||||
}
|
||||
if (! gn_system_verilog()) {
|
||||
yyerror(@14, "error: Primitive end labels "
|
||||
"require System Verilog.");
|
||||
"require SystemVerilog.");
|
||||
}
|
||||
delete[]$14;
|
||||
}
|
||||
|
||||
+9
-1
@@ -28,7 +28,9 @@
|
||||
|
||||
class Design;
|
||||
class Module;
|
||||
class PClass;
|
||||
class PPackage;
|
||||
class PTaskFunc;
|
||||
class PUdp;
|
||||
class data_type_t;
|
||||
struct enum_type_t;
|
||||
@@ -42,11 +44,17 @@ extern std::map<perm_string,Module*> pform_modules;
|
||||
extern std::map<perm_string,PUdp*> pform_primitives;
|
||||
extern std::map<perm_string,data_type_t*> pform_typedefs;
|
||||
extern std::set<enum_type_t*> pform_enum_sets;
|
||||
|
||||
extern std::map<perm_string,PTaskFunc*> pform_tasks;
|
||||
extern std::map<perm_string,PClass*> pform_classes;
|
||||
extern std::map<perm_string,PPackage*> pform_packages;
|
||||
|
||||
extern void pform_dump(std::ostream&out, const PClass*pac);
|
||||
extern void pform_dump(std::ostream&out, const PPackage*pac);
|
||||
extern void pform_dump(std::ostream&out, const PTaskFunc*tf);
|
||||
|
||||
extern void elaborate_rootscope_enumerations(Design*des);
|
||||
extern void elaborate_rootscope_classes(Design*des);
|
||||
extern void elaborate_rootscope_tasks(Design*des);
|
||||
|
||||
/*
|
||||
* This code actually invokes the parser to make modules. The first
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2014 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,8 +51,9 @@ void VLerror(const YYLTYPE&loc, const char*msg, ...)
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
|
||||
fprintf(stderr, "%s:%u: ", loc.text, loc.first_line);
|
||||
fprintf(stderr, "%s:%d: ", loc.text, loc.first_line);
|
||||
vfprintf(stderr, msg, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
error_count += 1;
|
||||
|
||||
@@ -66,6 +66,16 @@ map<perm_string,PUdp*> pform_primitives;
|
||||
map<perm_string,data_type_t*>pform_typedefs;
|
||||
set<enum_type_t*>pform_enum_sets;
|
||||
|
||||
/*
|
||||
* Class definitions in the $root scope go here.
|
||||
*/
|
||||
map<perm_string,PClass*> pform_classes;
|
||||
|
||||
/*
|
||||
* Task and function definitions in the $root scope go here.
|
||||
*/
|
||||
map<perm_string,PTaskFunc*> pform_tasks;
|
||||
|
||||
std::string vlltype::get_fileline() const
|
||||
{
|
||||
ostringstream buf;
|
||||
@@ -328,9 +338,17 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
|
||||
|
||||
assert(!pform_cur_generate);
|
||||
|
||||
/* If no scope was found then this is being defined in the
|
||||
* compilation unit scope. */
|
||||
if (scopex == 0) {
|
||||
pform_classes[name] = class_scope;
|
||||
lexical_scope = class_scope;
|
||||
return class_scope;
|
||||
}
|
||||
|
||||
if (scopex->classes.find(name) != scopex->classes.end()) {
|
||||
cerr << class_scope->get_fileline() << ": error: duplicate "
|
||||
" definition for class '" << name << "' in '"
|
||||
"definition for class '" << name << "' in '"
|
||||
<< scopex->pscope_name() << "'." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
@@ -358,16 +376,11 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
|
||||
FILE_NAME(task, loc);
|
||||
|
||||
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
||||
if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) {
|
||||
if ((scopex == 0) && !gn_system_verilog()) {
|
||||
cerr << task->get_fileline() << ": error: task declarations "
|
||||
"must be contained within a module." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
if ((scopex == 0) && (generation_flag >= GN_VER2005_SV)) {
|
||||
cerr << task->get_fileline() << ": sorry: task declarations "
|
||||
"in the compilation unit scope are not yet supported." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
if (pform_cur_generate) {
|
||||
// Check if the task is already in the dictionary.
|
||||
@@ -389,6 +402,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
|
||||
error_count += 1;
|
||||
}
|
||||
scopex->tasks[task->pscope_name()] = task;
|
||||
|
||||
} else {
|
||||
if (pform_tasks.find(task_name) != pform_tasks.end()) {
|
||||
cerr << task->get_fileline() << ": error: "
|
||||
<< "Duplicate definition for task '" << name
|
||||
<< "' in $root scope." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
pform_tasks[task_name] = task;
|
||||
}
|
||||
|
||||
lexical_scope = task;
|
||||
@@ -410,11 +432,6 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
|
||||
"must be contained within a module." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
if ((scopex == 0) && (generation_flag >= GN_VER2005_SV)) {
|
||||
cerr << func->get_fileline() << ": sorry: function declarations "
|
||||
"in the compilation unit scope are not yet supported." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
if (pform_cur_generate) {
|
||||
// Check if the function is already in the dictionary.
|
||||
@@ -427,6 +444,7 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
|
||||
error_count += 1;
|
||||
}
|
||||
pform_cur_generate->funcs[func->pscope_name()] = func;
|
||||
|
||||
} else if (scopex != 0) {
|
||||
// Check if the function is already in the dictionary.
|
||||
if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) {
|
||||
@@ -436,7 +454,17 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
|
||||
error_count += 1;
|
||||
}
|
||||
scopex->funcs[func->pscope_name()] = func;
|
||||
|
||||
} else {
|
||||
if (pform_tasks.find(func_name) != pform_tasks.end()) {
|
||||
cerr << func->get_fileline() << ": error: "
|
||||
<< "Duplicate definition for function '" << name
|
||||
<< "' in $root scope." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
pform_tasks[func_name] = func;
|
||||
}
|
||||
|
||||
lexical_scope = func;
|
||||
|
||||
return func;
|
||||
@@ -539,6 +567,9 @@ PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetN
|
||||
cur = new PWire(name, net_type, port_type, vt_type);
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
} else {
|
||||
// If this is a duplicate wire, the data type has already
|
||||
// been set, then return NULL.
|
||||
if (cur->get_data_type() != IVL_VT_NO_TYPE) return 0;
|
||||
bool rc = cur->set_wire_type(net_type);
|
||||
assert(rc);
|
||||
rc = cur->set_data_type(vt_type);
|
||||
@@ -704,6 +735,45 @@ PCallTask* pform_make_call_task(const struct vlltype&loc,
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void pform_make_foreach_declarations(const struct vlltype&loc,
|
||||
std::list<perm_string>*loop_vars)
|
||||
{
|
||||
static const struct str_pair_t str = { IVL_DR_STRONG, IVL_DR_STRONG };
|
||||
|
||||
list<decl_assignment_t*>assign_list;
|
||||
for (list<perm_string>::const_iterator cur = loop_vars->begin()
|
||||
; cur != loop_vars->end() ; ++ cur) {
|
||||
decl_assignment_t*tmp_assign = new decl_assignment_t;
|
||||
tmp_assign->name = lex_strings.make(*cur);
|
||||
assign_list.push_back(tmp_assign);
|
||||
}
|
||||
|
||||
pform_makewire(loc, 0, str, &assign_list, NetNet::REG, &size_type);
|
||||
}
|
||||
|
||||
PForeach* pform_make_foreach(const struct vlltype&loc,
|
||||
char*name,
|
||||
list<perm_string>*loop_vars,
|
||||
Statement*stmt)
|
||||
{
|
||||
perm_string use_name = lex_strings.make(name);
|
||||
delete[]name;
|
||||
|
||||
if (loop_vars==0 || loop_vars->empty()) {
|
||||
cerr << loc.get_fileline() << ": error: "
|
||||
<< "No loop variables at all in foreach index." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
ivl_assert(loc, loop_vars);
|
||||
PForeach*fe = new PForeach(use_name, *loop_vars, stmt);
|
||||
FILE_NAME(fe, loc);
|
||||
|
||||
delete loop_vars;
|
||||
|
||||
return fe;
|
||||
}
|
||||
|
||||
static void pform_put_behavior_in_scope(PProcess*pp)
|
||||
{
|
||||
lexical_scope->behaviors.push_back(pp);
|
||||
@@ -1845,7 +1915,6 @@ static void pform_set_net_range(list<perm_string>*names,
|
||||
}
|
||||
|
||||
delete names;
|
||||
delete range;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3078,6 +3147,7 @@ template <class T> static void pform_set2_data_type(const struct vlltype&li, T*d
|
||||
}
|
||||
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
|
||||
assert(net);
|
||||
net->set_data_type(data_type);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
@@ -3094,9 +3164,14 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
|
||||
perm_string name, NetNet::Type net_type,
|
||||
std::list<named_pexpr_t>*attr)
|
||||
{
|
||||
(void) li; // The line information is not currently needed.
|
||||
PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, enum_type->base_type);
|
||||
assert(cur);
|
||||
// A NULL is returned for a duplicate enumeration.
|
||||
if (! cur) {
|
||||
cerr << li.get_fileline() << ": error: Found duplicate "
|
||||
<< "enumeration named " << name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
cur->set_signed(enum_type->signed_flag);
|
||||
|
||||
@@ -3104,6 +3179,11 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
|
||||
assert(enum_type->range->size() == 1);
|
||||
//XXXXcur->set_range(*enum_type->range, SR_NET);
|
||||
cur->set_data_type(enum_type);
|
||||
// If this is an integer enumeration switch the wire to an integer.
|
||||
if (enum_type->integer_flag) {
|
||||
bool res = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(res);
|
||||
}
|
||||
pform_bind_attributes(cur->attributes, attr, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,12 @@ extern PCallTask* pform_make_call_task(const struct vlltype&loc,
|
||||
const pform_name_t&name,
|
||||
const std::list<PExpr*>&parms);
|
||||
|
||||
extern void pform_make_foreach_declarations(const struct vlltype&loc,
|
||||
std::list<perm_string>*loop_vars);
|
||||
extern PForeach* pform_make_foreach(const struct vlltype&loc,
|
||||
char*ident,
|
||||
std::list<perm_string>*loop_vars,
|
||||
Statement*stmt);
|
||||
|
||||
/*
|
||||
* The makewire functions announce to the pform code new wires. These
|
||||
@@ -349,7 +355,7 @@ extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list<perm
|
||||
|
||||
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_string_type(string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
extern void pform_set_string_type(const string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_class_type(class_type_t*class_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*addr);
|
||||
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Picture Elements, Inc.
|
||||
* Copyright (c) 2012-2014 Picture Elements, Inc.
|
||||
* Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -25,6 +25,7 @@
|
||||
static void pform_set_class_type(class_type_t*class_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS);
|
||||
assert(net);
|
||||
net->set_data_type(class_type);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
+56
-17
@@ -31,6 +31,7 @@
|
||||
# include "PGenerate.h"
|
||||
# include "PPackage.h"
|
||||
# include "PSpec.h"
|
||||
# include "PTask.h"
|
||||
# include "discipline.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include <iostream>
|
||||
@@ -62,6 +63,9 @@ ostream& operator<< (ostream&out, const index_component_t&that)
|
||||
case index_component_t::SEL_BIT:
|
||||
out << *that.msb;
|
||||
break;
|
||||
case index_component_t::SEL_BIT_LAST:
|
||||
out << "$";
|
||||
break;
|
||||
case index_component_t::SEL_PART:
|
||||
out << *that.msb << ":" << *that.lsb;
|
||||
break;
|
||||
@@ -184,9 +188,11 @@ void uarray_type_t::pform_dump(ostream&out, unsigned indent) const
|
||||
void vector_type_t::pform_dump(ostream&fd, unsigned indent) const
|
||||
{
|
||||
fd << setw(indent) << "" << "vector of " << base_type;
|
||||
for (list<pform_range_t>::iterator cur = pdims->begin()
|
||||
; cur != pdims->end() ; ++cur) {
|
||||
fd << "[" << *(cur->first) << ":" << *(cur->second) << "]";
|
||||
if (pdims.get()) {
|
||||
for (list<pform_range_t>::iterator cur = pdims->begin()
|
||||
; cur != pdims->end() ; ++cur) {
|
||||
fd << "[" << *(cur->first) << ":" << *(cur->second) << "]";
|
||||
}
|
||||
}
|
||||
fd << endl;
|
||||
}
|
||||
@@ -317,6 +323,14 @@ void PECastSize::dump(ostream &out) const
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void PECastType::dump(ostream &out) const
|
||||
{
|
||||
target_->pform_dump(out, 0);
|
||||
out << "'(";
|
||||
base_->dump(out);
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void PEEvent::dump(ostream&out) const
|
||||
{
|
||||
switch (type_) {
|
||||
@@ -964,6 +978,20 @@ void PForce::dump(ostream&out, unsigned ind) const
|
||||
<< "; /* " << get_fileline() << " */" << endl;
|
||||
}
|
||||
|
||||
void PForeach::dump(ostream&fd, unsigned ind) const
|
||||
{
|
||||
fd << setw(ind) << "" << "foreach "
|
||||
<< "variable=" << array_var_
|
||||
<< ", indices=[";
|
||||
for (size_t idx = 0 ; idx < index_vars_.size() ; idx += 1) {
|
||||
if (idx > 0) fd << ",";
|
||||
fd << index_vars_[idx];
|
||||
}
|
||||
|
||||
fd << "] /* " << get_fileline() << " */" << endl;
|
||||
statement_->dump(fd, ind+3);
|
||||
}
|
||||
|
||||
void PForever::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "forever /* " << get_fileline() << " */" << endl;
|
||||
@@ -992,20 +1020,20 @@ void PFunction::dump(ostream&out, unsigned ind) const
|
||||
else
|
||||
out << setw(ind+8) << "" << "<implicit type>" << endl;
|
||||
|
||||
dump_ports_(out, ind);
|
||||
dump_ports_(out, ind+2);
|
||||
|
||||
dump_parameters_(out, ind);
|
||||
dump_parameters_(out, ind+2);
|
||||
|
||||
dump_localparams_(out, ind);
|
||||
dump_localparams_(out, ind+2);
|
||||
|
||||
dump_events_(out, ind);
|
||||
dump_events_(out, ind+2);
|
||||
|
||||
dump_wires_(out, ind);
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(out, ind);
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
out << setw(ind+2) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PRelease::dump(ostream&out, unsigned ind) const
|
||||
@@ -1034,20 +1062,20 @@ void PTask::dump(ostream&out, unsigned ind) const
|
||||
out << pscope_name() << ";" << endl;
|
||||
if (method_of())
|
||||
out << setw(ind) << "" << "method of " << method_of()->name << ";" << endl;
|
||||
dump_ports_(out, ind);
|
||||
dump_ports_(out, ind+2);
|
||||
|
||||
dump_parameters_(out, ind);
|
||||
dump_parameters_(out, ind+2);
|
||||
|
||||
dump_localparams_(out, ind);
|
||||
dump_localparams_(out, ind+2);
|
||||
|
||||
dump_events_(out, ind);
|
||||
dump_events_(out, ind+2);
|
||||
|
||||
dump_wires_(out, ind);
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(out, ind);
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
out << setw(ind+2) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PTaskFunc::dump_ports_(std::ostream&out, unsigned ind) const
|
||||
@@ -1620,6 +1648,11 @@ void pform_dump(std::ostream&out, const ivl_discipline_s*dis)
|
||||
out << "enddiscipline" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&fd, const PClass*cl)
|
||||
{
|
||||
cl->dump(fd, 0);
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const PPackage*pac)
|
||||
{
|
||||
pac->pform_dump(out);
|
||||
@@ -1630,7 +1663,13 @@ void PPackage::pform_dump(std::ostream&out) const
|
||||
out << "package " << pscope_name() << endl;
|
||||
dump_localparams_(out, 4);
|
||||
dump_parameters_(out, 4);
|
||||
dump_enumerations_(out, 4);
|
||||
dump_tasks_(out, 4);
|
||||
dump_funcs_(out, 4);
|
||||
out << "endpackage" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&fd, const PTaskFunc*obj)
|
||||
{
|
||||
obj->dump(fd, 0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -21,13 +21,14 @@
|
||||
# include "parse_misc.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static void pform_set_string_type(string_type_t*, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
static void pform_set_string_type(const string_type_t*, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING);
|
||||
assert(net);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
void pform_set_string_type(string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
void pform_set_string_type(const string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ cur) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2011-2014 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
|
||||
@@ -67,6 +67,7 @@ static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name,
|
||||
ivl_variable_type_t base_type = struct_type->figure_packed_base_type();
|
||||
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
|
||||
assert(net);
|
||||
net->set_data_type(struct_type);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
@@ -99,6 +100,7 @@ static void pform_makewire(const struct vlltype&li,
|
||||
ivl_variable_type_t base_type = struct_type->figure_packed_base_type();
|
||||
|
||||
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type);
|
||||
assert(cur);
|
||||
FILE_NAME(cur, li);
|
||||
cur->set_data_type(struct_type);
|
||||
}
|
||||
|
||||
@@ -42,3 +42,5 @@ ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const
|
||||
{
|
||||
return base_type;
|
||||
}
|
||||
|
||||
atom2_type_t size_type (32, true);
|
||||
|
||||
+44
-3
@@ -39,17 +39,49 @@
|
||||
|
||||
class Design;
|
||||
class NetScope;
|
||||
class Definitions;
|
||||
class PExpr;
|
||||
class PWire;
|
||||
class Statement;
|
||||
class ivl_type_s;
|
||||
class netclass_t;
|
||||
class netenum_t;
|
||||
typedef named<verinum> named_number_t;
|
||||
typedef named<PExpr*> named_pexpr_t;
|
||||
|
||||
/*
|
||||
* The pform_range_t holds variable diimensions for type
|
||||
* declarations. The two expressions are interpreted as the first and
|
||||
* last values of the range. For example:
|
||||
*
|
||||
* [<expr1> : <expr2>] -- Normal array range
|
||||
* first == <expr1>
|
||||
* second = <expr2>
|
||||
*
|
||||
* [<expr>] -- SystemVerilog canonical range
|
||||
* first = PENumber(0)
|
||||
* second = <expr> - 1;
|
||||
*
|
||||
* [ ] -- Dynamic array
|
||||
* first = 0
|
||||
* second = 0
|
||||
*
|
||||
* [ $ ] -- Queue type
|
||||
* first = PENull
|
||||
* second = 0
|
||||
*/
|
||||
typedef std::pair<PExpr*,PExpr*> pform_range_t;
|
||||
|
||||
/*
|
||||
* Semantic NOTES:
|
||||
* - The SEL_BIT is a single expression. This might me a bit select
|
||||
* of a vector, or a word select of an array.
|
||||
*
|
||||
* - The SEL_BIT_LAST index component is an array/queue [$] index,
|
||||
* that is the last item in the variable.
|
||||
*/
|
||||
struct index_component_t {
|
||||
enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO };
|
||||
enum ctype_t { SEL_NONE, SEL_BIT, SEL_BIT_LAST, SEL_PART, SEL_IDX_UP, SEL_IDX_DO };
|
||||
|
||||
index_component_t() : sel(SEL_NONE), msb(0), lsb(0) { };
|
||||
~index_component_t() { }
|
||||
@@ -103,7 +135,7 @@ class data_type_t : public LineInfo {
|
||||
virtual ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const;
|
||||
|
||||
// Keep per-scope elaboration results cached.
|
||||
std::map<NetScope*,ivl_type_s*> cache_type_elaborate_;
|
||||
std::map<Definitions*,ivl_type_s*> cache_type_elaborate_;
|
||||
};
|
||||
|
||||
struct void_type_t : public data_type_t {
|
||||
@@ -122,6 +154,7 @@ 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;
|
||||
LineInfo li;
|
||||
@@ -152,6 +185,8 @@ struct atom2_type_t : public data_type_t {
|
||||
ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
extern atom2_type_t size_type;
|
||||
|
||||
/*
|
||||
* The vector_type_t class represents types in the old Verilog
|
||||
* way. Some typical examples:
|
||||
@@ -208,6 +243,7 @@ struct parray_type_t : public array_base_t {
|
||||
|
||||
virtual ivl_variable_type_t figure_packed_base_type(void)const;
|
||||
virtual void pform_dump(std::ostream&out, unsigned indent) const;
|
||||
virtual ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -240,7 +276,7 @@ struct string_type_t : public data_type_t {
|
||||
struct class_type_t : public data_type_t {
|
||||
|
||||
inline explicit class_type_t(perm_string n)
|
||||
: name(n), base_type(0) { }
|
||||
: name(n), base_type(0), save_elaborated_type(0) { }
|
||||
|
||||
void pform_dump(std::ostream&out, unsigned indent) const;
|
||||
void pform_dump_init(std::ostream&out, unsigned indent) const;
|
||||
@@ -275,6 +311,11 @@ struct class_type_t : public data_type_t {
|
||||
std::vector<Statement*> initialize_static;
|
||||
|
||||
ivl_type_s* elaborate_type_raw(Design*, NetScope*) const;
|
||||
// The save_elaborated_type member must be set to the pointer
|
||||
// to the netclass_t object that is created to represent this
|
||||
// type. The elaborate_type_raw() method uses this pointer,
|
||||
// and it is used in some other situations as well.
|
||||
netclass_t* save_elaborated_type;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#
|
||||
# NOTE: DO NOT INSTALL THIS FILE.
|
||||
|
||||
./ivl -v -Ctgt-stub/stub-s.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl |& tee foo.log
|
||||
./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl | tee foo.log 2>&1
|
||||
|
||||
echo "*** ivl command completed"
|
||||
|
||||
@@ -44,6 +44,11 @@ EXTERN_C_START
|
||||
|
||||
/********* OBJECT TYPES ***********/
|
||||
#define vpiPackage 600
|
||||
#define vpiArrayType 606
|
||||
#define vpiStaticArray 1
|
||||
#define vpiDynamicArray 2
|
||||
#define vpiAssocArray 3
|
||||
#define vpiQueueArray 4
|
||||
#define vpiLongIntVar 610
|
||||
#define vpiShortIntVar 611
|
||||
#define vpiIntVar 612
|
||||
|
||||
+8
-2
@@ -1,7 +1,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2000-2014 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
|
||||
@@ -100,7 +100,13 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk,
|
||||
NetNet*ce, NetAssign_*a, unsigned rval_pinoffset)
|
||||
{
|
||||
|
||||
assert(rval_pinoffset == 0);
|
||||
if (rval_pinoffset != 0) {
|
||||
cerr << a->get_fileline() << ": sorry: "
|
||||
<< "unable to hook up an R-value with offset "
|
||||
<< rval_pinoffset << " to signal " << a->name()
|
||||
<< "." << endl;
|
||||
return;
|
||||
}
|
||||
// a->sig() is a *NetNet, which doesn't have the loff_ and
|
||||
// lwid_ context. Add the correction for loff_ ourselves.
|
||||
|
||||
|
||||
@@ -82,7 +82,15 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
assert(lval_->more == 0);
|
||||
if (lval_->more) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "NetAssignBase::synth_async does not support an "
|
||||
<< "L-value concatenation ";
|
||||
dump_lval(cerr);
|
||||
cerr << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetAssignBase::synth_async: "
|
||||
@@ -330,6 +338,103 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to fix up a MUX selector to be no longer than
|
||||
* it needs to be. The general idea is that if the selector needs to
|
||||
* be only N bits, but is actually M bits, we translate it to this:
|
||||
*
|
||||
* osig = { |esig[M-1:N-1], esig[N-2:0] }
|
||||
*
|
||||
* This obviously implies that (N >= 2) and (M >= N). In the code
|
||||
* below, N is sel_need, and M is sel_got (= esig->vector_width()).
|
||||
*/
|
||||
static NetNet* mux_selector_reduce_width(Design*des, NetScope*scope,
|
||||
const LineInfo&loc,
|
||||
NetNet*esig, unsigned sel_need)
|
||||
{
|
||||
const unsigned sel_got = esig->vector_width();
|
||||
|
||||
ivl_assert(*esig, sel_got >= sel_need);
|
||||
|
||||
// If the actual width matches the desired width (M==N) then
|
||||
// osig is esig itself. We're done.
|
||||
if (sel_got == sel_need)
|
||||
return esig;
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << loc.get_fileline() << ": mux_selector_reduce_width: "
|
||||
<< "Reduce selector width=" << sel_got
|
||||
<< " to " << sel_need << " bits." << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*esig, sel_need >= 2);
|
||||
|
||||
// This is the output signal, osig.
|
||||
ivl_variable_type_t osig_data_type = IVL_VT_LOGIC;
|
||||
netvector_t*osig_vec = new netvector_t(osig_data_type, sel_need-1, 0);
|
||||
NetNet*osig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, osig_vec);
|
||||
osig->local_flag(true);
|
||||
osig->set_line(loc);
|
||||
|
||||
// Create the concat: osig = {...,...}
|
||||
NetConcat*osig_cat = new NetConcat(scope, scope->local_symbol(),
|
||||
sel_need, 2, true);
|
||||
osig_cat->set_line(loc);
|
||||
des->add_node(osig_cat);
|
||||
connect(osig_cat->pin(0), osig->pin(0));
|
||||
|
||||
// Create the part select esig[N-2:0]...
|
||||
NetPartSelect*ps0 = new NetPartSelect(esig, 0, sel_need-1,
|
||||
NetPartSelect::VP);
|
||||
ps0->set_line(loc);
|
||||
des->add_node(ps0);
|
||||
connect(ps0->pin(1), esig->pin(0));
|
||||
|
||||
netvector_t*ps0_vec = new netvector_t(osig_data_type, sel_need-2, 0);
|
||||
NetNet*ps0_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, ps0_vec);
|
||||
ps0_sig->local_flag(true);
|
||||
ps0_sig->set_line(loc);
|
||||
connect(ps0_sig->pin(0), ps0->pin(0));
|
||||
|
||||
// osig = {..., esig[N-2:0]}
|
||||
connect(osig_cat->pin(1), ps0_sig->pin(0));
|
||||
|
||||
// Create the part select esig[M-1:N-1]
|
||||
NetPartSelect*ps1 = new NetPartSelect(esig, sel_need-1,
|
||||
sel_got-sel_need,
|
||||
NetPartSelect::VP);
|
||||
ps1->set_line(loc);
|
||||
des->add_node(ps1);
|
||||
connect(ps1->pin(1), esig->pin(0));
|
||||
|
||||
netvector_t*ps1_vec = new netvector_t(osig_data_type, sel_got-sel_need-1, 0);
|
||||
NetNet*ps1_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, ps1_vec);
|
||||
ps1_sig->local_flag(true);
|
||||
ps1_sig->set_line(loc);
|
||||
connect(ps1_sig->pin(0), ps1->pin(0));
|
||||
|
||||
// Create the reduction OR: | esig[M-1:N-1]
|
||||
NetUReduce*ered = new NetUReduce(scope, scope->local_symbol(),
|
||||
NetUReduce::OR, sel_got-sel_need);
|
||||
ered->set_line(loc);
|
||||
des->add_node(ered);
|
||||
connect(ered->pin(1), ps1_sig->pin(0));
|
||||
|
||||
NetNet*ered_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, &netvector_t::scalar_logic);
|
||||
ered_sig->local_flag(true);
|
||||
ered_sig->set_line(loc);
|
||||
connect(ered->pin(0), ered_sig->pin(0));
|
||||
|
||||
// osig = { |esig[M-1:N-1], esig[N-2:0] }
|
||||
connect(osig_cat->pin(2), ered_sig->pin(0));
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
NetBus&accumulated_nex_out)
|
||||
@@ -344,12 +449,22 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
if (dynamic_cast<NetEConst*> (expr_))
|
||||
return synth_async_casez_(des, scope, nex_map, nex_out, accumulated_nex_out);
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "Selector expression: " << *expr_ << endl;
|
||||
}
|
||||
|
||||
/* Synthesize the select expression. */
|
||||
NetNet*esig = expr_->synthesize(des, scope, expr_);
|
||||
|
||||
unsigned sel_width = esig->vector_width();
|
||||
ivl_assert(*this, sel_width > 0);
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "selector width (sel_width) = " << sel_width << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, nex_map.size() == nex_out.pin_count());
|
||||
|
||||
vector<unsigned> mux_width (nex_out.pin_count());
|
||||
@@ -387,28 +502,72 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
|
||||
if (ge == 0) {
|
||||
cerr << items_[item].guard->get_fileline() << ": sorry: "
|
||||
<< "variable case item expressions with a variable "
|
||||
<< "case select expression are not supported in "
|
||||
<< "synthesis. " << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
ivl_assert(*this, ge);
|
||||
verinum gval = ge->value();
|
||||
|
||||
unsigned sel_idx = gval.as_ulong();
|
||||
unsigned long sel_idx = gval.as_ulong();
|
||||
|
||||
assert(items_[item].statement);
|
||||
statement_map[sel_idx] = items_[item].statement;
|
||||
if (statement_map[sel_idx]) {
|
||||
cerr << ge->get_fileline() << ": warning: duplicate case "
|
||||
<< "value '" << sel_idx << "' detected. This case is "
|
||||
<< "unreachable." << endl;
|
||||
delete items_[item].statement;
|
||||
items_[item].statement = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sel_idx > max_guard_value)
|
||||
max_guard_value = sel_idx;
|
||||
|
||||
ivl_assert(*this, items_[item].statement);
|
||||
statement_map[sel_idx] = items_[item].statement;
|
||||
}
|
||||
|
||||
// The mux_size is the number of inputs that are selected.
|
||||
unsigned mux_size = max_guard_value + 1;
|
||||
unsigned sel_need = ceil(log2(mux_size));
|
||||
|
||||
// If the sel_width can select more than just the explicit
|
||||
// guard values, and there is a default statement, then adjust
|
||||
// the mux size to allow for the implicit selections.
|
||||
if (statement_default && ((1U<<sel_width) > mux_size)) {
|
||||
mux_size = 1<<sel_width;
|
||||
if (statement_default && (sel_width > sel_need)) {
|
||||
sel_need += 1;
|
||||
ivl_assert(*this, sel_need < sizeof mux_size);
|
||||
mux_size = 1<<sel_need;
|
||||
}
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "Adjusted mux_size is " << mux_size
|
||||
<< " (max_guard_value=" << max_guard_value
|
||||
<< ", sel_need=" << sel_need
|
||||
<< ", sel_width=" << sel_width << ")." << endl;
|
||||
}
|
||||
|
||||
if (sel_width > sel_need) {
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "Selector is " << sel_width << " bits, "
|
||||
<< "need only " << sel_need << " bits." << endl;
|
||||
}
|
||||
esig = mux_selector_reduce_width(des, scope, *this, esig, sel_need);
|
||||
}
|
||||
|
||||
if (!statement_default && (statement_map.size() != ((size_t)1 << sel_width))) {
|
||||
cerr << get_fileline() << ": sorry: Latch inferred from "
|
||||
<< "incomplete case statement. This is not supported "
|
||||
<< "in synthesis." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If there is a default clause, synthesize it once and we'll
|
||||
link it in wherever it is needed. */
|
||||
@@ -437,7 +596,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
vector<NetMux*> mux (mux_width.size());
|
||||
for (size_t mdx = 0 ; mdx < mux_width.size() ; mdx += 1) {
|
||||
mux[mdx] = new NetMux(scope, scope->local_symbol(),
|
||||
mux_width[mdx], mux_size, sel_width);
|
||||
mux_width[mdx], mux_size, sel_need);
|
||||
des->add_node(mux[mdx]);
|
||||
|
||||
// The select signal is already synthesized, and is
|
||||
@@ -473,12 +632,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
|
||||
continue;
|
||||
}
|
||||
if (stmt == 0) {
|
||||
cerr << get_fileline() << ": error: case " << idx
|
||||
<< " is not accounted for in asynchronous mux." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
ivl_assert(*this, stmt);
|
||||
|
||||
NetBus accumulated_tmp (scope, nex_map.size());
|
||||
for (unsigned pin = 0 ; pin < nex_map.size() ; pin += 1)
|
||||
@@ -1308,7 +1462,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
||||
NetBus tmp_out(scope, nex_out.pin_count());
|
||||
NetBus accumulated_tmp_out(scope, nex_out.pin_count());
|
||||
flag = if_->synth_async(des, scope, nex_map, tmp_out, accumulated_tmp_out);
|
||||
ivl_assert(*this, flag);
|
||||
if (! flag) return false;
|
||||
|
||||
ivl_assert(*this, tmp_out.pin_count() == ff_aclr.pin_count());
|
||||
ivl_assert(*this, tmp_out.pin_count() == ff_aset.pin_count());
|
||||
@@ -1777,9 +1931,9 @@ void synth2_f::process(Design*des, NetProcTop*top)
|
||||
}
|
||||
|
||||
if (! top->synth_async(des)) {
|
||||
cerr << top->get_fileline() << ": internal error: "
|
||||
<< "is_asynchronous does not match "
|
||||
<< "sync_async results." << endl;
|
||||
cerr << top->get_fileline() << ": error: "
|
||||
<< "failed to synthesize asynchronous "
|
||||
<< "logic for this process." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,6 +193,17 @@ int load_sys_func_table(const char*path)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(stype,"vpiSysFuncVoid") == 0) {
|
||||
cell = new struct sfunc_return_type_cell;
|
||||
cell->name = lex_strings.add(name);
|
||||
cell->type = IVL_VT_VOID;
|
||||
cell->wid = 0;
|
||||
cell->signed_flag = false;
|
||||
cell->next = sfunc_stack;
|
||||
sfunc_stack = cell;
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s:%s: Unknown type: %s\n",
|
||||
path, name, stype);
|
||||
}
|
||||
|
||||
+11
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -84,7 +84,11 @@ extern "C" void ivl_design_roots(ivl_design_t des, ivl_scope_t **scopes,
|
||||
assert (nscopes && scopes);
|
||||
if (des->root_scope_list.size() == 0) {
|
||||
size_t fill = 0;
|
||||
des->root_scope_list.resize(des->packages.size() + des->roots.size() + des->classes.size());
|
||||
des->root_scope_list.resize(des->root_tasks.size() + des->packages.size() + des->roots.size() + des->classes.size());
|
||||
for (map<const NetScope*,ivl_scope_t>::iterator idx = des->root_tasks.begin()
|
||||
; idx != des->root_tasks.end() ; ++ idx)
|
||||
des->root_scope_list[fill++] = idx->second;
|
||||
|
||||
for (map<const NetScope*,ivl_scope_t>::iterator idx = des->classes.begin()
|
||||
; idx != des->classes.end() ; ++ idx)
|
||||
des->root_scope_list[fill++] = idx->second;
|
||||
@@ -485,6 +489,9 @@ extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net)
|
||||
case IVL_EX_BINARY:
|
||||
return net->u_.binary_.lef_;
|
||||
|
||||
case IVL_EX_PROPERTY:
|
||||
return net->u_.property_.index;
|
||||
|
||||
case IVL_EX_SELECT:
|
||||
return net->u_.select_.expr_;
|
||||
|
||||
@@ -2426,6 +2433,8 @@ extern "C" int ivl_signal_integer(ivl_signal_t net)
|
||||
{
|
||||
if (const netvector_t*vec = dynamic_cast<const netvector_t*> (net->net_type))
|
||||
return vec->get_isint()? 1 : 0;
|
||||
else if (const netenum_t*enm = dynamic_cast<const netenum_t*> (net->net_type))
|
||||
return enm->get_isint()? 1 : 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -343,6 +343,38 @@ void dll_target::expr_creal(const NetECReal*net)
|
||||
expr_->u_.real_.value = net->value().as_double();
|
||||
}
|
||||
|
||||
void dll_target::expr_last(const NetELast*net)
|
||||
{
|
||||
assert(expr_ == 0);
|
||||
ivl_expr_t expr = new struct ivl_expr_s;
|
||||
expr->type_ = IVL_EX_SFUNC;
|
||||
expr->value_ = IVL_VT_LOGIC;
|
||||
expr->width_ = 32;
|
||||
expr->signed_ = 1;
|
||||
expr->sized_ = 1;
|
||||
expr->net_type = 0;
|
||||
FILE_NAME(expr, net);
|
||||
|
||||
expr->u_.sfunc_.name_ = "$high";
|
||||
|
||||
ivl_signal_t sig = find_signal(des_, net->sig());
|
||||
|
||||
ivl_expr_t esig = new struct ivl_expr_s;
|
||||
esig->type_ = IVL_EX_SIGNAL;
|
||||
esig->value_ = IVL_VT_DARRAY;
|
||||
esig->net_type= sig->net_type;
|
||||
esig->width_ = 1;
|
||||
FILE_NAME(esig, net);
|
||||
esig->u_.signal_.word = 0;
|
||||
esig->u_.signal_.sig = sig;
|
||||
|
||||
expr->u_.sfunc_.parms = 1;
|
||||
expr->u_.sfunc_.parm = new ivl_expr_t[1];
|
||||
expr->u_.sfunc_.parm[0] = esig;
|
||||
|
||||
expr_ = expr;
|
||||
}
|
||||
|
||||
void dll_target::expr_new(const NetENew*net)
|
||||
{
|
||||
ivl_expr_t size = 0;
|
||||
@@ -388,6 +420,12 @@ void dll_target::expr_null(const NetENull*net)
|
||||
|
||||
void dll_target::expr_property(const NetEProperty*net)
|
||||
{
|
||||
ivl_expr_t index = 0;
|
||||
if (const NetExpr*index_expr = net->get_index()) {
|
||||
index_expr->expr_scan(this);
|
||||
index = expr_;
|
||||
expr_ = 0;
|
||||
}
|
||||
assert(expr_ == 0);
|
||||
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
|
||||
expr_->width_ = net->expr_width();
|
||||
@@ -399,6 +437,7 @@ void dll_target::expr_property(const NetEProperty*net)
|
||||
expr_->net_type= net->net_type();
|
||||
expr_->u_.property_.sig = find_signal(des_, net->get_sig());
|
||||
expr_->u_.property_.prop_idx = net->property_idx();
|
||||
expr_->u_.property_.index = index;
|
||||
}
|
||||
|
||||
void dll_target::expr_event(const NetEEvent*net)
|
||||
@@ -619,6 +658,11 @@ void dll_target::expr_ufunc(const NetEUFunc*net)
|
||||
FILE_NAME(expr, net);
|
||||
|
||||
expr->u_.ufunc_.def = lookup_scope_(net->func());
|
||||
if (expr->u_.ufunc_.def == 0) {
|
||||
cerr << net->get_fileline() << ": internal error: "
|
||||
<< "dll_target::expr_ufunc: "
|
||||
<< "Unable to match scope " << scope_path(net->func()) << endl;
|
||||
}
|
||||
ivl_assert(*net, expr->u_.ufunc_.def);
|
||||
ivl_assert(*net, expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION);
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ void dll_target::task_def(const NetScope*net)
|
||||
ivl_scope_t scop = lookup_scope_(net);
|
||||
const NetTaskDef*def = net->task_def();
|
||||
|
||||
assert(def);
|
||||
assert(def->proc());
|
||||
assert(stmt_cur_ == 0);
|
||||
stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_);
|
||||
def->proc()->emit_proc(this);
|
||||
@@ -102,6 +104,8 @@ bool dll_target::func_def(const NetScope*net)
|
||||
ivl_scope_t scop = lookup_scope_(net);
|
||||
const NetFuncDef*def = net->func_def();
|
||||
|
||||
assert(def);
|
||||
assert(def->proc());
|
||||
assert(stmt_cur_ == 0);
|
||||
stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_);
|
||||
def->proc()->emit_proc(this);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -261,6 +261,12 @@ ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (cur->type()==NetScope::TASK || cur->type()==NetScope::FUNC) {
|
||||
map<const NetScope*,ivl_scope_t>::const_iterator idx = des.root_tasks.find(cur);
|
||||
if (idx != des.root_tasks.end())
|
||||
return idx->second;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0; idx < des.roots.size(); idx += 1) {
|
||||
assert(des.roots[idx]);
|
||||
ivl_scope_t scope = find_scope_from_root(des.roots[idx], cur);
|
||||
@@ -605,6 +611,13 @@ void dll_target::add_root(const NetScope *s)
|
||||
root_->lpm_ = 0;
|
||||
root_->def = 0;
|
||||
make_scope_parameters(root_, s);
|
||||
root_->tname_ = root_->name_;
|
||||
root_->time_precision = s->time_precision();
|
||||
root_->time_units = s->time_unit();
|
||||
root_->nattr = s->attr_cnt();
|
||||
root_->attr = fill_in_attributes(s);
|
||||
root_->is_auto = 0;
|
||||
root_->is_cell = s->is_cell();
|
||||
switch (s->type()) {
|
||||
case NetScope::PACKAGE:
|
||||
root_->type_ = IVL_SCT_PACKAGE;
|
||||
@@ -615,16 +628,25 @@ void dll_target::add_root(const NetScope *s)
|
||||
case NetScope::CLASS:
|
||||
root_->type_ = IVL_SCT_CLASS;
|
||||
break;
|
||||
case NetScope::TASK: {
|
||||
const NetTaskDef*def = s->task_def();
|
||||
if (def == 0) {
|
||||
cerr << "?:?" << ": internal error: "
|
||||
<< "task " << root_->name_
|
||||
<< " has no definition." << endl;
|
||||
}
|
||||
assert(def);
|
||||
root_->type_ = IVL_SCT_TASK;
|
||||
root_->tname_ = def->scope()->basename();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetScope::FUNC:
|
||||
root_->type_ = IVL_SCT_FUNCTION;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
root_->tname_ = root_->name_;
|
||||
root_->time_precision = s->time_precision();
|
||||
root_->time_units = s->time_unit();
|
||||
root_->nattr = s->attr_cnt();
|
||||
root_->attr = fill_in_attributes(s);
|
||||
root_->is_auto = 0;
|
||||
root_->is_cell = s->is_cell();
|
||||
|
||||
switch (s->type()) {
|
||||
case NetScope::MODULE:
|
||||
@@ -650,6 +672,11 @@ void dll_target::add_root(const NetScope *s)
|
||||
des_.classes[s] = root_;
|
||||
break;
|
||||
|
||||
case NetScope::TASK:
|
||||
case NetScope::FUNC:
|
||||
des_.root_tasks[s] = root_;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
@@ -691,16 +718,22 @@ bool dll_target::start_design(const Design*des)
|
||||
}
|
||||
assert(idx == des_.disciplines.size());
|
||||
|
||||
list<NetScope *> package_scopes = des->find_package_scopes();
|
||||
for (list<NetScope*>::const_iterator scop = package_scopes.begin()
|
||||
; scop != package_scopes.end(); ++ scop ) {
|
||||
add_root(*scop);
|
||||
list<NetScope *> scope_list = des->find_roottask_scopes();
|
||||
for (list<NetScope*>::const_iterator cur = scope_list.begin()
|
||||
; cur != scope_list.end() ; ++ cur) {
|
||||
add_root(*cur);
|
||||
}
|
||||
|
||||
list<NetScope *> root_scopes = des->find_root_scopes();
|
||||
for (list<NetScope*>::const_iterator scop = root_scopes.begin()
|
||||
; scop != root_scopes.end(); ++ scop ) {
|
||||
add_root(*scop);
|
||||
scope_list = des->find_package_scopes();
|
||||
for (list<NetScope*>::const_iterator cur = scope_list.begin()
|
||||
; cur != scope_list.end(); ++ cur ) {
|
||||
add_root(*cur);
|
||||
}
|
||||
|
||||
scope_list = des->find_root_scopes();
|
||||
for (list<NetScope*>::const_iterator cur = scope_list.begin()
|
||||
; cur != scope_list.end(); ++ cur ) {
|
||||
add_root(*cur);
|
||||
}
|
||||
|
||||
target_ = (target_design_f)ivl_dlsym(dll_, LU "target_design" TU);
|
||||
@@ -2411,6 +2444,11 @@ void dll_target::scope(const NetScope*net)
|
||||
{
|
||||
if (net->parent()==0 && net->type()==NetScope::CLASS) {
|
||||
|
||||
if (debug_emit) {
|
||||
cerr << "dll_target::scope: "
|
||||
<< "Add class " << scope_path(net)
|
||||
<< " as a root scope." << endl;
|
||||
}
|
||||
add_root(net);
|
||||
|
||||
} if (net->parent() == 0) {
|
||||
|
||||
@@ -141,6 +141,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
void expr_concat(const NetEConcat*);
|
||||
void expr_const(const NetEConst*);
|
||||
void expr_creal(const NetECReal*);
|
||||
void expr_last(const NetELast*);
|
||||
void expr_new(const NetENew*);
|
||||
void expr_null(const NetENull*);
|
||||
void expr_param(const NetEConstParam*);
|
||||
@@ -345,6 +346,7 @@ struct ivl_expr_s {
|
||||
struct {
|
||||
ivl_signal_t sig;
|
||||
unsigned prop_idx;
|
||||
ivl_expr_t index;
|
||||
} property_;
|
||||
} u_;
|
||||
};
|
||||
@@ -482,7 +484,7 @@ struct ivl_lval_s {
|
||||
* structural context.
|
||||
*/
|
||||
struct ivl_net_const_s {
|
||||
ivl_variable_type_t type : 3;
|
||||
ivl_variable_type_t type : 4;
|
||||
unsigned width_ : 24;
|
||||
unsigned signed_ : 1;
|
||||
perm_string file;
|
||||
|
||||
@@ -471,6 +471,12 @@ void expr_scan_t::expr_const(const NetEConst*)
|
||||
"unhandled expr_const." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_last(const NetELast*exp)
|
||||
{
|
||||
cerr << exp->get_fileline() << ": expr_scan_t(" << typeid(*this).name() << "): "
|
||||
<< "unhandled expr_last." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_new(const NetENew*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
|
||||
@@ -159,6 +159,7 @@ struct expr_scan_t {
|
||||
virtual void expr_access_func(const NetEAccess*);
|
||||
virtual void expr_array_pattern(const NetEArrayPattern*);
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_last(const NetELast*);
|
||||
virtual void expr_new(const NetENew*);
|
||||
virtual void expr_null(const NetENull*);
|
||||
virtual void expr_param(const NetEConstParam*);
|
||||
|
||||
@@ -21,7 +21,7 @@ code. To convert a design to blif, use this command:
|
||||
|
||||
iverilog -tblif -o<path>.blif <source files>...
|
||||
|
||||
The source files can be Verilog, System Verilog, VHDL, whatever Icarus
|
||||
The source files can be Verilog, SystemVerilog, VHDL, whatever Icarus
|
||||
Verilog supports, so long as it elaborates down to the limited subset
|
||||
that the code generator supports. In other words, the files must be
|
||||
structural.
|
||||
|
||||
@@ -378,7 +378,7 @@ static void edif_show_logic(ivl_net_logic_t net)
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "UNSUPPORT LOGIC TYPE: %u\n", ivl_logic_type(net));
|
||||
fprintf(stderr, "UNSUPPORT LOGIC TYPE: %d\n", ivl_logic_type(net));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ static void generic_show_logic(ivl_net_logic_t net)
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "fpga.tgt: unknown logic type %u\n",
|
||||
fprintf(stderr, "fpga.tgt: unknown logic type %d\n",
|
||||
ivl_logic_type(net));
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -396,7 +396,7 @@ static void lpm_logic(ivl_net_logic_t net)
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n",
|
||||
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %d\n",
|
||||
ivl_logic_type(net));
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2014 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
|
||||
@@ -148,7 +148,7 @@ static void show_gate_lpm(ivl_lpm_t net)
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "fpga.tgt: unknown LPM type %u\n",
|
||||
fprintf(stderr, "fpga.tgt: unknown LPM type %d\n",
|
||||
ivl_lpm_type(net));
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -694,7 +694,7 @@ void xilinx_logic(ivl_net_logic_t net)
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n",
|
||||
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %d\n",
|
||||
ivl_logic_type(net));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
unusedFunction:null.c:50
|
||||
|
||||
// target_query()
|
||||
unusedFunction:null.c:56
|
||||
unusedFunction:null.c:57
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// are not used here.
|
||||
|
||||
// target_design()
|
||||
unusedFunction:stub.c:1731
|
||||
unusedFunction:stub.c:1770
|
||||
|
||||
// target_query()
|
||||
unusedFunction:stub.c:1795
|
||||
unusedFunction:stub.c:1834
|
||||
|
||||
@@ -232,6 +232,7 @@ static void show_property_expression(ivl_expr_t net, unsigned ind)
|
||||
ivl_signal_t sig = ivl_expr_signal(net);
|
||||
const char* pnam = ivl_expr_name(net);
|
||||
const char*signed_flag = ivl_expr_signed(net)? "signed" : "unsigned";
|
||||
ivl_expr_t index;
|
||||
|
||||
if (ivl_expr_value(net) == IVL_VT_REAL) {
|
||||
fprintf(out, "%*s<property base=%s, prop=%s, real>\n", ind, "",
|
||||
@@ -243,6 +244,9 @@ static void show_property_expression(ivl_expr_t net, unsigned ind)
|
||||
fprintf(out, "%*s<property base=%s, prop=%s, width=%u, %s>\n", ind, "",
|
||||
ivl_signal_basename(sig), pnam, ivl_expr_width(net), signed_flag);
|
||||
}
|
||||
if ( (index=ivl_expr_oper1(net)) ) {
|
||||
show_expression(index, ind+3);
|
||||
}
|
||||
if (ivl_signal_data_type(sig) != IVL_VT_CLASS) {
|
||||
fprintf(out, "%*sERROR: Property signal must be IVL_VT_CLASS, got %s.\n",
|
||||
ind+3, "", data_type_string(ivl_signal_data_type(sig)));
|
||||
|
||||
@@ -73,6 +73,12 @@ static unsigned show_assign_lval_class(ivl_lval_t lval, unsigned ind)
|
||||
fprintf(out, "%*s{name=%s.<property-%d> l-value width=%u}\n",
|
||||
ind, "", ivl_signal_name(sig), sig_prop, ivl_lval_width(lval));
|
||||
|
||||
if (ivl_lval_idx(lval)) {
|
||||
ivl_expr_t mux = ivl_lval_idx(lval);
|
||||
fprintf(out, "%*sAddress-0 select expression:\n", ind+4, "");
|
||||
show_expression(mux, ind+6);
|
||||
}
|
||||
|
||||
return ivl_lval_width(lval);
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -175,6 +175,9 @@ const char*data_type_string(ivl_variable_type_t vtype)
|
||||
case IVL_VT_CLASS:
|
||||
vt = "class";
|
||||
break;
|
||||
case IVL_VT_QUEUE:
|
||||
vt = "queue";
|
||||
break;
|
||||
}
|
||||
|
||||
return vt;
|
||||
@@ -264,7 +267,7 @@ static void show_lpm_abs(ivl_lpm_t net)
|
||||
}
|
||||
|
||||
if (width_of_nexus(nex) != width) {
|
||||
fprintf(out, " ERROR: D width (%d) is wrong\n",
|
||||
fprintf(out, " ERROR: D width (%u) is wrong\n",
|
||||
width_of_nexus(nex));
|
||||
stub_errors += 1;
|
||||
}
|
||||
@@ -1656,7 +1659,7 @@ static int show_scope(ivl_scope_t net, void*x)
|
||||
fprintf(out, " class %s", ivl_scope_tname(net));
|
||||
break;
|
||||
default:
|
||||
fprintf(out, " type(%u) %s", ivl_scope_type(net),
|
||||
fprintf(out, " type(%d) %s", ivl_scope_type(net),
|
||||
ivl_scope_tname(net));
|
||||
break;
|
||||
}
|
||||
@@ -1794,6 +1797,12 @@ int target_design(ivl_design_t des)
|
||||
|
||||
ivl_scope_t cur = root_scopes[idx];
|
||||
switch (ivl_scope_type(cur)) {
|
||||
case IVL_SCT_TASK:
|
||||
fprintf(out, "task = %s\n", ivl_scope_name(cur));
|
||||
break;
|
||||
case IVL_SCT_FUNCTION:
|
||||
fprintf(out, "function = %s\n", ivl_scope_name(cur));
|
||||
break;
|
||||
case IVL_SCT_CLASS:
|
||||
fprintf(out, "class = %s\n", ivl_scope_name(cur));
|
||||
break;
|
||||
|
||||
@@ -30,6 +30,15 @@ static void show_net_type_darray(ivl_type_t net_type)
|
||||
show_net_type(element_type);
|
||||
}
|
||||
|
||||
static void show_net_type_queue(ivl_type_t net_type)
|
||||
{
|
||||
/* Dynamic arrays have a single element type. */
|
||||
ivl_type_t element_type = ivl_type_element(net_type);
|
||||
|
||||
fprintf(out, "queue of ");
|
||||
show_net_type(element_type);
|
||||
}
|
||||
|
||||
void show_net_type(ivl_type_t net_type)
|
||||
{
|
||||
ivl_variable_type_t data_type = ivl_type_base(net_type);
|
||||
@@ -57,6 +66,9 @@ void show_net_type(ivl_type_t net_type)
|
||||
case IVL_VT_CLASS:
|
||||
fprintf(out, "class");
|
||||
break;
|
||||
case IVL_VT_QUEUE:
|
||||
show_net_type_queue(net_type);
|
||||
break;
|
||||
case IVL_VT_VOID:
|
||||
fprintf(out, "void");
|
||||
break;
|
||||
@@ -112,6 +124,12 @@ void show_type_of_signal(ivl_signal_t net)
|
||||
fprintf(out, "ERROR-DARRAY");
|
||||
stub_errors += 1;
|
||||
break;
|
||||
case IVL_VT_QUEUE:
|
||||
/* The QUEUE type MUST be described by an
|
||||
ivl_signal_net_type object. */
|
||||
fprintf(out, "ERROR-QUEUE");
|
||||
stub_errors += 1;
|
||||
break;
|
||||
case IVL_VT_VOID:
|
||||
fprintf(out, "void");
|
||||
break;
|
||||
|
||||
@@ -78,7 +78,7 @@ else
|
||||
endif
|
||||
|
||||
vlog95.tgt: $O $(TGTDEPLIBS)
|
||||
$(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
|
||||
$(CC) @shared@ $(LDFLAGS) -o $@ $O -lm $(TGTLDFLAGS)
|
||||
|
||||
install: all installdirs $(libdir)/ivl$(suffix)/vlog95.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/vlog95.conf $(libdir)/ivl$(suffix)/vlog95-s.conf
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
unusedFunction:vlog95.c:59
|
||||
|
||||
// target_query()
|
||||
unusedFunction:vlog95.c:226
|
||||
unusedFunction:vlog95.c:251
|
||||
|
||||
+4
-2
@@ -855,9 +855,11 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
ivl_expr_t sig_expr = ivl_expr_oper1(expr);
|
||||
ivl_select_type_t sel_type = ivl_expr_sel_type(expr);
|
||||
(void)wid; /* Parameter is not used. */
|
||||
/* If this is a dynamic array select, translate it differently. */
|
||||
/* If this is a dynamic array or queue select, translate the
|
||||
* select differently. */
|
||||
if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) &&
|
||||
(ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_DARRAY)) {
|
||||
((ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_DARRAY) ||
|
||||
(ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_QUEUE))) {
|
||||
assert(sel_expr);
|
||||
emit_select_name(scope, sig_expr);
|
||||
fprintf(vlog_out, "[");
|
||||
|
||||
@@ -1979,7 +1979,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
assert(! nlogic);
|
||||
assert(! sig);
|
||||
fprintf(stderr, "LPM: ");
|
||||
fprintf(stderr, "{%s:%d} ", ivl_lpm_file(lpm),
|
||||
fprintf(stderr, "{%s:%u} ", ivl_lpm_file(lpm),
|
||||
ivl_lpm_lineno(lpm));
|
||||
if (scope != lpm_scope) fprintf(stderr, "(%s) ",
|
||||
ivl_scope_name(lpm_scope));
|
||||
@@ -2038,7 +2038,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
ivl_logic_t logic_type = ivl_logic_type(nlogic);
|
||||
assert(! sig);
|
||||
fprintf(stderr, "Logic: ");
|
||||
fprintf(stderr, "{%s:%d} ", ivl_logic_file(nlogic),
|
||||
fprintf(stderr, "{%s:%u} ", ivl_logic_file(nlogic),
|
||||
ivl_logic_lineno(nlogic));
|
||||
if (scope != logic_scope) {
|
||||
fprintf(stderr, "(%s) ", ivl_scope_name(logic_scope));
|
||||
@@ -2100,7 +2100,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
fprintf(stderr, "\"");
|
||||
// HERE: Do we need to add support for an array word or is that an LPM.
|
||||
if (ivl_signal_local(sig)) fprintf(stderr, " {local}");
|
||||
else fprintf(stderr, " {%s:%d}", ivl_signal_file(sig),
|
||||
else fprintf(stderr, " {%s:%u}", ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig));
|
||||
switch (ivl_signal_port(sig)) {
|
||||
case IVL_SIP_INPUT: fprintf(stderr, " input"); break;
|
||||
@@ -2127,6 +2127,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
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;
|
||||
}
|
||||
if (ivl_signal_signed(sig)) fprintf(stderr, " <signed>");
|
||||
|
||||
+17
-4
@@ -816,8 +816,12 @@ void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
* references for variables, etc. */
|
||||
void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
{
|
||||
ivl_scope_t mod_scope = get_module_scope(scope);
|
||||
ivl_scope_t call_mod_scope = get_module_scope(call_scope);
|
||||
ivl_scope_t mod_scope, call_mod_scope;
|
||||
|
||||
if (scope == call_scope) return;
|
||||
|
||||
mod_scope = get_module_scope(scope);
|
||||
call_mod_scope = get_module_scope(call_scope);
|
||||
|
||||
if (mod_scope != call_mod_scope) {
|
||||
emit_scope_piece(mod_scope, call_mod_scope);
|
||||
@@ -864,8 +868,17 @@ static void emit_scope_path_piece(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
*/
|
||||
void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
{
|
||||
ivl_scope_t mod_scope = get_module_scope(scope);
|
||||
ivl_scope_t call_mod_scope = get_module_scope(call_scope);
|
||||
ivl_scope_t mod_scope, call_mod_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.");
|
||||
mod_scope = 0;
|
||||
call_mod_scope = 0;
|
||||
} else {
|
||||
mod_scope = get_module_scope(scope);
|
||||
call_mod_scope = get_module_scope(call_scope);
|
||||
}
|
||||
|
||||
if (mod_scope == call_mod_scope) {
|
||||
emit_id(ivl_scope_basename(call_scope));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2014 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
|
||||
@@ -16,6 +16,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
# include <math.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include "config.h"
|
||||
@@ -168,18 +169,19 @@ void emit_number(const char *bits, unsigned nbits, unsigned is_signed,
|
||||
void emit_real_number(double value)
|
||||
{
|
||||
/* Check for NaN. */
|
||||
if (value != value) {
|
||||
if (isnan(value)) {
|
||||
fprintf(vlog_out, "(0.0/0.0)");
|
||||
return;
|
||||
}
|
||||
/* Check for the infinities. */
|
||||
if (value && value == 0.5*value) {
|
||||
if (value > 0) fprintf(vlog_out, "(1.0/0.0)");
|
||||
else fprintf(vlog_out, "(-1.0/0.0)");
|
||||
if (isinf(value)) {
|
||||
if (signbit(value)) fprintf(vlog_out, "(-1.0/0.0)");
|
||||
else fprintf(vlog_out, "(1.0/0.0)");
|
||||
return;
|
||||
}
|
||||
/* Check for +/- zero. */
|
||||
if (value == 0.0) {
|
||||
if (1.0/value < 0.0) fprintf(vlog_out, "-0.0");
|
||||
if (signbit(value)) fprintf(vlog_out, "-0.0");
|
||||
else fprintf(vlog_out, "0.0");
|
||||
} else {
|
||||
char buffer[32];
|
||||
|
||||
@@ -125,6 +125,14 @@ static void emit_var_def(ivl_signal_t sig)
|
||||
ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig), ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
} else if (ivl_signal_data_type(sig) == IVL_VT_QUEUE) {
|
||||
fprintf(vlog_out, "<queue> ");
|
||||
emit_sig_id(sig);
|
||||
fprintf(stderr, "%s:%u: vlog95 error: SystemVerilog queues "
|
||||
"(%s) are not supported.\n",
|
||||
ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig), ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
} else {
|
||||
int msb, lsb;
|
||||
get_sig_msb_lsb(sig, &msb, &lsb);
|
||||
@@ -1047,6 +1055,8 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
||||
emit_module_ports(scope);
|
||||
break;
|
||||
case IVL_SCT_FUNCTION:
|
||||
/* Root scope functions have already been emitted. */
|
||||
if (! parent) return 0;
|
||||
assert(indent != 0);
|
||||
fprintf(vlog_out, "\n%*cfunction", indent, ' ');
|
||||
if (ivl_scope_ports(scope) < 1) {
|
||||
@@ -1069,6 +1079,8 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
||||
}
|
||||
break;
|
||||
case IVL_SCT_TASK:
|
||||
/* Root scope tasks have already been emitted. */
|
||||
if (! parent) return 0;
|
||||
assert(indent != 0);
|
||||
fprintf(vlog_out, "\n%*ctask ", indent, ' ');
|
||||
emit_id(ivl_scope_tname(scope));
|
||||
|
||||
+4
-2
@@ -1384,14 +1384,16 @@ static void emit_stmt_stask(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
fprintf(vlog_out, "%*c%s", get_indent(), ' ', ivl_stmt_name(stmt));
|
||||
if (count != 0) {
|
||||
unsigned idx;
|
||||
ivl_expr_t expr;
|
||||
fprintf(vlog_out, "(");
|
||||
count -= 1;
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_expr_t expr = ivl_stmt_parm(stmt, idx);
|
||||
expr = ivl_stmt_parm(stmt, idx);
|
||||
if (expr) emit_expr(scope, expr, 0, 0, 0, 0);
|
||||
fprintf(vlog_out, ", ");
|
||||
}
|
||||
emit_expr(scope, ivl_stmt_parm(stmt, count), 0, 0, 0, 0);
|
||||
expr = ivl_stmt_parm(stmt, count);
|
||||
if (expr) emit_expr(scope, expr, 0, 0, 0, 0);
|
||||
fprintf(vlog_out, ")");
|
||||
}
|
||||
fprintf(vlog_out, ";");
|
||||
|
||||
@@ -60,6 +60,7 @@ 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. */
|
||||
@@ -184,6 +185,30 @@ int target_design(ivl_design_t des)
|
||||
|
||||
/* Get all the root modules and then convert each one. */
|
||||
ivl_design_roots(des, &roots, &nroots);
|
||||
/* Emit any root scope tasks or functions first. */
|
||||
for (idx = 0; idx < nroots; idx += 1) {
|
||||
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;
|
||||
}
|
||||
/* Say this task/function has a parent so the
|
||||
* definition is emitted correctly. */
|
||||
emit_scope(roots[idx], 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 objets. */
|
||||
for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0);
|
||||
|
||||
free_emitted_scope_list();
|
||||
|
||||
+4
-1
@@ -49,7 +49,10 @@ 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 \
|
||||
eval_bool.o eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_bool.o \
|
||||
eval_condit.o \
|
||||
eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_vec4.o \
|
||||
modpath.o stmt_assign.o vector.o \
|
||||
vvp_process.o vvp_scope.o
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ static void show_prop_type_vector(ivl_type_t ptype)
|
||||
static void show_prop_type(ivl_type_t ptype)
|
||||
{
|
||||
ivl_variable_type_t data_type = ivl_type_base(ptype);
|
||||
unsigned packed_dimensions = ivl_type_packed_dimensions(ptype);
|
||||
|
||||
switch (data_type) {
|
||||
case IVL_VT_REAL:
|
||||
@@ -64,6 +65,15 @@ static void show_prop_type(ivl_type_t ptype)
|
||||
case IVL_VT_DARRAY:
|
||||
case IVL_VT_CLASS:
|
||||
fprintf(vvp_out, "\"o\"");
|
||||
if (packed_dimensions > 0) {
|
||||
unsigned idx;
|
||||
fprintf(vvp_out, " ");
|
||||
for (idx = 0 ; idx < packed_dimensions ; idx += 1) {
|
||||
fprintf(vvp_out, "[%d:%d]",
|
||||
ivl_type_packed_msb(ptype,idx),
|
||||
ivl_type_packed_lsb(ptype,idx));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(vvp_out, "\"<ERROR-no-type>\"");
|
||||
|
||||
+6
-43
@@ -24,7 +24,6 @@
|
||||
|
||||
static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
|
||||
{
|
||||
struct vector_info res;
|
||||
unsigned ewidth, pwidth;
|
||||
|
||||
/* ports cannot be arrays. */
|
||||
@@ -32,16 +31,12 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
|
||||
|
||||
ewidth = ivl_expr_width(expr);
|
||||
pwidth = ivl_signal_width(port);
|
||||
/* Just like a normal assignment the function arguments need to
|
||||
* be evaluated at either their width or the argument width if
|
||||
* it is larger. */
|
||||
if (ewidth < pwidth) ewidth = pwidth;
|
||||
res = draw_eval_expr_wid(expr, ewidth, 0);
|
||||
|
||||
/* We could have extra bits so only select the ones we need. */
|
||||
fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, pwidth);
|
||||
draw_eval_vec4(expr);
|
||||
if (ewidth < pwidth)
|
||||
fprintf(vvp_out, " %%pad/u %u;\n", pwidth);
|
||||
|
||||
clr_vector(res);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", port, pwidth);
|
||||
}
|
||||
|
||||
static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
|
||||
@@ -153,50 +148,18 @@ static void draw_ufunc_epilogue(ivl_expr_t expr)
|
||||
* parameter 0 of the function definition.
|
||||
*/
|
||||
|
||||
struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid)
|
||||
void draw_ufunc_vec4(ivl_expr_t expr)
|
||||
{
|
||||
unsigned swid = ivl_expr_width(expr);
|
||||
ivl_scope_t def = ivl_expr_def(expr);
|
||||
ivl_signal_t retval = ivl_scope_port(def, 0);
|
||||
struct vector_info res;
|
||||
unsigned load_wid;
|
||||
|
||||
/* Take in arguments to function and call function code. */
|
||||
draw_ufunc_preamble(expr);
|
||||
|
||||
/* Fresh basic block starts after the join. */
|
||||
clear_expression_lookaside();
|
||||
|
||||
/* The return value is in a signal that has the name of the
|
||||
expression. Load that into the thread and return the
|
||||
vector result. */
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for function result.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr), wid);
|
||||
vvp_errors += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(res.base != 0);
|
||||
|
||||
load_wid = swid;
|
||||
if (load_wid > ivl_signal_width(retval))
|
||||
load_wid = ivl_signal_width(retval);
|
||||
|
||||
assert(ivl_signal_dimensions(retval) == 0);
|
||||
fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n",
|
||||
res.base, retval, load_wid);
|
||||
|
||||
/* Pad the signal value with zeros. */
|
||||
if (load_wid < wid)
|
||||
pad_expr_in_place(expr, res, swid);
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", retval);
|
||||
|
||||
draw_ufunc_epilogue(expr);
|
||||
return res;
|
||||
}
|
||||
|
||||
void draw_ufunc_real(ivl_expr_t expr)
|
||||
|
||||
+44
-59
@@ -29,14 +29,16 @@
|
||||
|
||||
struct args_info {
|
||||
char*text;
|
||||
int vec_flag; /* True if the vec must be released. */
|
||||
struct vector_info vec;
|
||||
/* True ('s' or 'u' if this argument is a calculated vec4. */
|
||||
char vec_flag;
|
||||
/* True if this argument is a calculated string. */
|
||||
char str_flag;
|
||||
/* True if this argument is a calculated real. */
|
||||
char real_flag;
|
||||
/* Stack position if this argument is a calculated string. */
|
||||
/* Stack position if this argument is a calculated value. */
|
||||
unsigned stack;
|
||||
/* Expression width: Only used of vec_flag is true. */
|
||||
unsigned vec_wid;
|
||||
struct args_info *child; /* Arguments can be nested. */
|
||||
};
|
||||
|
||||
@@ -156,14 +158,9 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||
return 0;
|
||||
}
|
||||
} else if (word_ex) {
|
||||
/* Fallback case: evaluate expression. */
|
||||
struct vector_info av;
|
||||
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u %u \"%s\">",
|
||||
sig, av.base, av.wid,
|
||||
(ivl_expr_signed(word_ex) ? "s" : "u"));
|
||||
result->vec = av;
|
||||
result->vec_flag = 1;
|
||||
/* Fallback case: Give up and evaluate expression. */
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
assert(use_word_defined);
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>",
|
||||
@@ -247,17 +244,8 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Fallback case: evaluate the expression. */
|
||||
struct vector_info rv;
|
||||
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"&PV<v%p_0, %u %u \"%s\", %u>",
|
||||
ivl_expr_signal(vexpr),
|
||||
rv.base, rv.wid,
|
||||
(ivl_expr_signed(bexpr) ? "s" : "u"),
|
||||
ivl_expr_width(expr));
|
||||
result->vec = rv;
|
||||
result->vec_flag = 1;
|
||||
/* Fallback case: Punt and let caller handle it. */
|
||||
return 0;
|
||||
}
|
||||
result->text = strdup(buffer);
|
||||
return 1;
|
||||
@@ -286,6 +274,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
/* Keep track of how much string stack this function call is
|
||||
going to need. We'll need this for making stack references,
|
||||
and also to clean out the stack when done. */
|
||||
unsigned vec4_stack_need = 0;
|
||||
unsigned str_stack_need = 0;
|
||||
unsigned real_stack_need = 0;
|
||||
|
||||
@@ -377,9 +366,18 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
case IVL_EX_SELECT:
|
||||
if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) continue;
|
||||
else break;
|
||||
|
||||
args[idx].stack = vec4_stack_need;
|
||||
if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) {
|
||||
if (args[idx].vec_flag) {
|
||||
vec4_stack_need += 1;
|
||||
} else {
|
||||
args[idx].stack = 0;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
args[idx].stack = 0;
|
||||
break;
|
||||
}
|
||||
/* Everything else will need to be evaluated and
|
||||
passed as a constant to the vpi task. */
|
||||
default:
|
||||
@@ -389,17 +387,18 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
switch (ivl_expr_value(expr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
args[idx].vec_flag = 1;
|
||||
args[idx].vec = draw_eval_expr(expr, 0);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid,
|
||||
ivl_expr_signed(expr)? "s" : "u");
|
||||
draw_eval_vec4(expr);
|
||||
args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u';
|
||||
args[idx].str_flag = 0;
|
||||
args[idx].real_flag = 0;
|
||||
args[idx].stack = vec4_stack_need;
|
||||
args[idx].vec_wid = ivl_expr_width(expr);
|
||||
vec4_stack_need += 1;
|
||||
buffer[0] = 0;
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(expr);
|
||||
args[idx].vec_flag = 0;
|
||||
args[idx].vec.base = 0;
|
||||
args[idx].vec.wid = 0;
|
||||
args[idx].str_flag = 0;
|
||||
args[idx].real_flag = 1;
|
||||
args[idx].stack = real_stack_need;
|
||||
@@ -411,9 +410,8 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
about the stack position. */
|
||||
draw_eval_string(expr);
|
||||
args[idx].vec_flag = 0;
|
||||
args[idx].vec.base = 0;
|
||||
args[idx].vec.wid = 0;
|
||||
args[idx].str_flag = 1;
|
||||
args[idx].real_flag = 0;
|
||||
args[idx].stack = str_stack_need;
|
||||
args[idx].real_flag = 0;
|
||||
str_stack_need += 1;
|
||||
@@ -434,7 +432,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
struct args_info*ptr;
|
||||
|
||||
if (args[idx].str_flag) {
|
||||
/* If this is a string stack reference, then
|
||||
/* If this is a stack reference, then
|
||||
calculate the stack depth and use that to
|
||||
generate the completed string. */
|
||||
unsigned pos = str_stack_need - args[idx].stack - 1;
|
||||
@@ -442,18 +440,16 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
} else if (args[idx].real_flag) {
|
||||
unsigned pos = real_stack_need - args[idx].stack - 1;
|
||||
fprintf(vvp_out, ", W<%u,r>",pos);
|
||||
} else if (args[idx].vec_flag) {
|
||||
unsigned pos = vec4_stack_need - args[idx].stack - 1;
|
||||
char sign_flag = args[idx].vec_flag;
|
||||
unsigned wid = args[idx].vec_wid;
|
||||
fprintf(vvp_out, ", S<%u,vec4,%c%u>",pos, sign_flag, wid);
|
||||
} else {
|
||||
fprintf(vvp_out, ", %s", args[idx].text);
|
||||
}
|
||||
|
||||
free(args[idx].text);
|
||||
/* Clear the nested children vectors. */
|
||||
for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) {
|
||||
if (ptr->vec_flag) {
|
||||
if (ptr->vec.wid > 0) clr_vector(ptr->vec);
|
||||
else clr_word(ptr->vec.base);
|
||||
}
|
||||
}
|
||||
/* Free the nested children. */
|
||||
ptr = args[idx].child;
|
||||
while (ptr != NULL) {
|
||||
@@ -465,7 +461,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
|
||||
free(args);
|
||||
|
||||
fprintf(vvp_out, " {%u %u}", real_stack_need, str_stack_need);
|
||||
fprintf(vvp_out, " {%u %u %u}", vec4_stack_need, real_stack_need, str_stack_need);
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
|
||||
@@ -487,7 +483,7 @@ void draw_vpi_task_call(ivl_statement_t tnet)
|
||||
}
|
||||
|
||||
if (parm_count == 0) {
|
||||
fprintf(vvp_out, " %s %u %u \"%s\" {0 0};\n", command,
|
||||
fprintf(vvp_out, " %s %u %u \"%s\" {0 0 0};\n", command,
|
||||
ivl_file_table_index(ivl_stmt_file(tnet)),
|
||||
ivl_stmt_lineno(tnet), ivl_stmt_name(tnet));
|
||||
} else {
|
||||
@@ -499,27 +495,16 @@ void draw_vpi_task_call(ivl_statement_t tnet)
|
||||
}
|
||||
}
|
||||
|
||||
struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
|
||||
void draw_vpi_func_call(ivl_expr_t fnet)
|
||||
{
|
||||
char call_string[1024];
|
||||
struct vector_info res;
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for system function result.\n",
|
||||
ivl_expr_file(fnet), ivl_expr_lineno(fnet), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
sprintf(call_string, " %%vpi_func %u %u \"%s\", %u, %u",
|
||||
sprintf(call_string, " %%vpi_func %u %u \"%s\" %u",
|
||||
ivl_file_table_index(ivl_expr_file(fnet)),
|
||||
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res.base, res.wid);
|
||||
ivl_expr_lineno(fnet), ivl_expr_name(fnet),
|
||||
ivl_expr_width(fnet));
|
||||
|
||||
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void draw_vpi_rfunc_call(ivl_expr_t fnet)
|
||||
|
||||
+2
-5
@@ -46,17 +46,14 @@
|
||||
static int eval_bool64_logic(ivl_expr_t expr)
|
||||
{
|
||||
int res;
|
||||
struct vector_info tmp;
|
||||
const char*s_flag = "";
|
||||
|
||||
tmp = draw_eval_expr(expr, STUFF_OK_XZ);
|
||||
draw_eval_vec4(expr);
|
||||
res = allocate_word();
|
||||
if (ivl_expr_signed(expr))
|
||||
s_flag = "/s";
|
||||
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res,
|
||||
tmp.base, tmp.wid);
|
||||
clr_vector(tmp);
|
||||
fprintf(vvp_out, " %%ix/vec4%s %d;\n", s_flag, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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 <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static int draw_condition_fallback(ivl_expr_t expr)
|
||||
{
|
||||
int use_flag = allocate_flag();
|
||||
|
||||
/* Evaluate the condition expression, including optionally
|
||||
reducing it to a single bit. Put the result into a flag bit
|
||||
for use by all the tests. */
|
||||
draw_eval_vec4(expr);
|
||||
if (ivl_expr_width(expr) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
|
||||
return use_flag;
|
||||
}
|
||||
|
||||
static int draw_condition_binary_compare(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
|
||||
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
||||
|| (ivl_expr_value(re) == IVL_VT_REAL)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_type(re)==IVL_EX_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_type(le)==IVL_EX_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_CLASS)
|
||||
&& (ivl_expr_value(re)==IVL_VT_CLASS)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
unsigned use_wid = ivl_expr_width(le);
|
||||
if (ivl_expr_width(re) > use_wid)
|
||||
use_wid = ivl_expr_width(re);
|
||||
|
||||
/* If the le is constant, then swap the operands so that we
|
||||
can possibly take advantage of the immediate version of the
|
||||
%cmp instruction. */
|
||||
if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) {
|
||||
ivl_expr_t tmp = le;
|
||||
re = le;
|
||||
le = tmp;
|
||||
}
|
||||
|
||||
draw_eval_vec4(le);
|
||||
resize_vec4_wid(le, use_wid);
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
|
||||
|
||||
if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) {
|
||||
/* Special case: If the right operand can be handled as
|
||||
an immediate operand, then use that instead. */
|
||||
if (use_opcode=='n' || use_opcode=='N')
|
||||
draw_immediate_vec4(re, "%cmpi/ne");
|
||||
else
|
||||
draw_immediate_vec4(re, "%cmpi/e");
|
||||
} else {
|
||||
draw_eval_vec4(re);
|
||||
resize_vec4_wid(re, use_wid);
|
||||
if (use_opcode=='n' || use_opcode=='N')
|
||||
fprintf(vvp_out, " %%cmp/ne;\n");
|
||||
else
|
||||
fprintf(vvp_out, " %%cmp/e;\n");
|
||||
}
|
||||
|
||||
switch (ivl_expr_opcode(expr)) {
|
||||
case 'n': /* != */
|
||||
case 'e': /* == */
|
||||
return 4;
|
||||
break;
|
||||
case 'N': /* !== */
|
||||
case 'E': /* === */
|
||||
return 6;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int draw_condition_binary_real_le(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
ivl_expr_t tmp;
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
|
||||
/* If this is a > or >=, then convert it to < or <= by
|
||||
swapping the operands. Adjust the opcode to match. */
|
||||
switch (use_opcode) {
|
||||
case 'G':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = 'L';
|
||||
break;
|
||||
case '>':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = '<';
|
||||
break;
|
||||
}
|
||||
|
||||
draw_eval_real(le);
|
||||
draw_eval_real(re);
|
||||
|
||||
fprintf(vvp_out, " %%cmp/wr;\n");
|
||||
|
||||
switch (use_opcode) {
|
||||
case '<':
|
||||
return 5;
|
||||
case 'L':
|
||||
fprintf(vvp_out, " %%flag_or 5, 4;\n");
|
||||
return 5;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int draw_condition_binary_le(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
ivl_expr_t tmp;
|
||||
|
||||
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
||||
|| (ivl_expr_value(re) == IVL_VT_REAL)) {
|
||||
return draw_condition_binary_real_le(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_type(re)==IVL_EX_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_type(le)==IVL_EX_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
char s_flag = (ivl_expr_signed(le) && ivl_expr_signed(re)) ? 's' : 'u';
|
||||
|
||||
/* If this is a > or >=, then convert it to < or <= by
|
||||
swapping the operands. Adjust the opcode to match. */
|
||||
switch (use_opcode) {
|
||||
case 'G':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = 'L';
|
||||
break;
|
||||
case '>':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = '<';
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTE: I think I would rather the elaborator handle the
|
||||
operand widths. When that happens, take this code out. */
|
||||
|
||||
unsigned use_wid = ivl_expr_width(le);
|
||||
if (ivl_expr_width(re) > use_wid)
|
||||
use_wid = ivl_expr_width(re);
|
||||
|
||||
draw_eval_vec4(le);
|
||||
resize_vec4_wid(le, use_wid);
|
||||
|
||||
if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) {
|
||||
/* Special case: If the right operand can be handled as
|
||||
an immediate operand, then use that instead. */
|
||||
char opcode[8];
|
||||
snprintf(opcode, sizeof opcode, "%%cmpi/%c", s_flag);
|
||||
draw_immediate_vec4(re, opcode);
|
||||
|
||||
} else {
|
||||
draw_eval_vec4(re);
|
||||
resize_vec4_wid(re, use_wid);
|
||||
|
||||
fprintf(vvp_out, " %%cmp/%c;\n", s_flag);
|
||||
}
|
||||
|
||||
switch (use_opcode) {
|
||||
case '<':
|
||||
return 5;
|
||||
case 'L':
|
||||
fprintf(vvp_out, " %%flag_or 5, 4;\n");
|
||||
return 5;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_condition_binary_lor(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
|
||||
int lx = draw_eval_condition(le);
|
||||
|
||||
if (lx < 8) {
|
||||
int tmp = allocate_flag();
|
||||
fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp, lx);
|
||||
lx = tmp;
|
||||
}
|
||||
|
||||
int rx = draw_eval_condition(re);
|
||||
|
||||
fprintf(vvp_out, " %%flag_or %d, %d;\n", rx, lx);
|
||||
clr_flag(lx);
|
||||
return rx;
|
||||
}
|
||||
|
||||
static int draw_condition_binary(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_opcode(expr)) {
|
||||
case 'e': /* == */
|
||||
case 'E': /* === */
|
||||
case 'n': /* != */
|
||||
case 'N': /* !== */
|
||||
return draw_condition_binary_compare(expr);
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L': /* <= */
|
||||
case 'G': /* >= */
|
||||
return draw_condition_binary_le(expr);
|
||||
case 'o': /* Logical or (||) */
|
||||
return draw_condition_binary_lor(expr);
|
||||
default:
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
}
|
||||
|
||||
int draw_eval_condition(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_BINARY:
|
||||
return draw_condition_binary(expr);
|
||||
default:
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
}
|
||||
+20
-3402
File diff suppressed because it is too large
Load Diff
+41
-19
@@ -58,7 +58,8 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
int wid = msb>=lsb? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
fprintf(vvp_out, " %%new/darray %u, \"sb%d\";\n", size_reg, wid);
|
||||
fprintf(vvp_out, " %%new/darray %u, \"%sb%d\";\n", size_reg,
|
||||
ivl_type_signed(element_type) ? "s" : "", wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -68,18 +69,13 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
|
||||
if (init_expr && ivl_expr_type(init_expr)==IVL_EX_ARRAY_PATTERN) {
|
||||
unsigned idx;
|
||||
struct vector_info rvec;
|
||||
unsigned wid;
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
wid = width_of_packed_type(element_type);
|
||||
for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
|
||||
rvec = draw_eval_expr_wid(ivl_expr_parm(init_expr,idx),
|
||||
wid, STUFF_OK_XZ);
|
||||
draw_eval_vec4(ivl_expr_parm(init_expr,idx));
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||
fprintf(vvp_out, " %%set/dar/obj 3, %u, %u;\n",
|
||||
rvec.base, rvec.wid);
|
||||
if (rvec.base >= 4) clr_vector(rvec);
|
||||
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
|
||||
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
||||
}
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
@@ -110,18 +106,16 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
a constant. Generate an unrolled set of assignments. */
|
||||
long idx;
|
||||
long cnt = get_number_immediate(size_expr);
|
||||
struct vector_info rvec;
|
||||
unsigned wid;
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
wid = width_of_packed_type(element_type);
|
||||
rvec = draw_eval_expr_wid(init_expr, wid, STUFF_OK_XZ);
|
||||
draw_eval_vec4(init_expr);
|
||||
resize_vec4_wid(init_expr, wid);
|
||||
for (idx = 0 ; idx < cnt ; idx += 1) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx);
|
||||
fprintf(vvp_out, " %%set/dar/obj 3, %u, %u;\n",
|
||||
rvec.base, rvec.wid);
|
||||
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
|
||||
}
|
||||
if (rvec.base >= 4) clr_vector(rvec);
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(init_expr);
|
||||
@@ -172,9 +166,22 @@ static int eval_object_property(ivl_expr_t expr)
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned pidx = ivl_expr_property_idx(expr);
|
||||
|
||||
int idx = 0;
|
||||
ivl_expr_t idx_expr = 0;
|
||||
|
||||
/* If there is an array index expression, then this is an
|
||||
array'ed property, and we need to calculate the index for
|
||||
the expression. */
|
||||
if ( (idx_expr = ivl_expr_oper1(expr)) ) {
|
||||
idx = allocate_word();
|
||||
draw_eval_expr_into_integer(idx_expr, idx);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%prop/obj %u;\n", pidx);
|
||||
fprintf(vvp_out, " %%prop/obj %u, %d; eval_object_property\n", pidx, idx);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
|
||||
|
||||
if (idx != 0) clr_word(idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,10 +202,25 @@ static int eval_object_shallowcopy(ivl_expr_t ex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eval_object_signal(ivl_expr_t ex)
|
||||
static int eval_object_signal(ivl_expr_t expr)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(ex);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
||||
/* Simple case: This is a simple variable. Generate a load
|
||||
statement to load the string into the stack. */
|
||||
if (ivl_signal_dimensions(sig) == 0) {
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There is a word select expression, so load the index into a
|
||||
register and load from the array. */
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
int word_ix = allocate_word();
|
||||
draw_eval_expr_into_integer(word_ex, word_ix);
|
||||
fprintf(vvp_out, " %%load/obja v%p, %d;\n", sig, word_ix);
|
||||
clr_word(word_ix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -240,7 +262,7 @@ int draw_eval_object(ivl_expr_t ex)
|
||||
return eval_object_ufunc(ex);
|
||||
|
||||
default:
|
||||
fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %u\n", ivl_expr_type(ex));
|
||||
fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %d\n", ivl_expr_type(ex));
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
+25
-42
@@ -243,18 +243,16 @@ static void draw_realnum_real(ivl_expr_t expr)
|
||||
* The real value of a logic expression is the integer value of the
|
||||
* expression converted to real.
|
||||
*/
|
||||
static void draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
|
||||
static void draw_real_logic_expr(ivl_expr_t expr)
|
||||
{
|
||||
struct vector_info sv = draw_eval_expr(expr, stuff_ok_flag);
|
||||
draw_eval_vec4(expr);
|
||||
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
|
||||
|
||||
if (sv.wid > 64) {
|
||||
fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n",
|
||||
sign_flag, sv.base, sv.wid);
|
||||
if (ivl_expr_width(expr) > 64) {
|
||||
fprintf(vvp_out, " %%cvt/rv%s;\n", sign_flag);
|
||||
} else {
|
||||
int res = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
|
||||
sign_flag, res, sv.base, sv.wid);
|
||||
fprintf(vvp_out, " %%ix/vec4%s %d;\n", sign_flag, res);
|
||||
|
||||
if (ivl_expr_signed(expr))
|
||||
fprintf(vvp_out, " %%cvt/rs %d;\n", res);
|
||||
@@ -262,8 +260,6 @@ static void draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
|
||||
fprintf(vvp_out, " %%cvt/ru %d;\n", res);
|
||||
clr_word(res);
|
||||
}
|
||||
|
||||
clr_vector(sv);
|
||||
}
|
||||
|
||||
static void draw_select_real(ivl_expr_t expr)
|
||||
@@ -287,7 +283,7 @@ static void draw_sfunc_real(ivl_expr_t expr)
|
||||
|
||||
case IVL_VT_REAL:
|
||||
if (ivl_expr_parms(expr) == 0) {
|
||||
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0};\n",
|
||||
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0 0};\n",
|
||||
ivl_file_table_index(ivl_expr_file(expr)),
|
||||
ivl_expr_lineno(expr), ivl_expr_name(expr));
|
||||
|
||||
@@ -300,7 +296,7 @@ static void draw_sfunc_real(ivl_expr_t expr)
|
||||
/* If the value of the sfunc is a vector, then evaluate
|
||||
it as a vector, then convert the result to a real
|
||||
(via an index register) for the result. */
|
||||
draw_real_logic_expr(expr, 0);
|
||||
draw_real_logic_expr(expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -330,7 +326,7 @@ static void draw_signal_real(ivl_expr_t expr)
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
switch (ivl_signal_data_type(sig)) {
|
||||
case IVL_VT_LOGIC:
|
||||
draw_real_logic_expr(expr, 0);
|
||||
draw_real_logic_expr(expr);
|
||||
return;
|
||||
case IVL_VT_REAL:
|
||||
draw_signal_real_real(expr);
|
||||
@@ -352,35 +348,27 @@ static void draw_ternary_real(ivl_expr_t expr)
|
||||
ivl_expr_t true_ex = ivl_expr_oper2(expr);
|
||||
ivl_expr_t false_ex = ivl_expr_oper3(expr);
|
||||
|
||||
struct vector_info tst;
|
||||
|
||||
unsigned lab_true = local_count++;
|
||||
unsigned lab_out = local_count++;
|
||||
|
||||
int cond_flag = allocate_flag();
|
||||
|
||||
/* Evaluate the ternary condition. */
|
||||
tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
|
||||
if ((tst.base >= 4) && (tst.wid > 1)) {
|
||||
struct vector_info tmp;
|
||||
draw_eval_vec4(cond);
|
||||
if (ivl_expr_width(cond) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n",
|
||||
tst.base, tst.base, tst.wid);
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", cond_flag);
|
||||
|
||||
tmp = tst;
|
||||
tmp.base += 1;
|
||||
tmp.wid -= 1;
|
||||
clr_vector(tmp);
|
||||
|
||||
tst.wid = 1;
|
||||
}
|
||||
|
||||
/* Evaluate the true expression second. */
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n",
|
||||
thread_count, lab_true, tst.base);
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %d;\n",
|
||||
thread_count, lab_true, cond_flag);
|
||||
|
||||
/* Evaluate the false expression. */
|
||||
draw_eval_real(false_ex);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %u; End of false expr.\n",
|
||||
thread_count, lab_out, tst.base);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d; End of false expr.\n",
|
||||
thread_count, lab_out, cond_flag);
|
||||
|
||||
/* If the conditional is undefined then blend the real words. */
|
||||
draw_eval_real(true_ex);
|
||||
@@ -395,7 +383,7 @@ static void draw_ternary_real(ivl_expr_t expr)
|
||||
/* This is the out label. */
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
||||
|
||||
clr_vector(tst);
|
||||
clr_flag(cond_flag);
|
||||
}
|
||||
|
||||
static void increment(ivl_expr_t e, bool pre)
|
||||
@@ -428,20 +416,18 @@ static void draw_unary_real(ivl_expr_t expr)
|
||||
* a real expression, so use vector evaluation and then convert
|
||||
* that result to a real value. */
|
||||
if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) {
|
||||
draw_real_logic_expr(expr, STUFF_OK_XZ);
|
||||
draw_real_logic_expr(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
sube = ivl_expr_oper1(expr);
|
||||
|
||||
if (ivl_expr_opcode(expr) == 'r') { /* Cast an integer value to a real. */
|
||||
struct vector_info res;
|
||||
const char *suffix = "";
|
||||
assert(ivl_expr_value(sube) != IVL_VT_REAL);
|
||||
res = draw_eval_expr(sube, 1);
|
||||
draw_eval_vec4(sube);
|
||||
if (ivl_expr_signed(sube)) suffix = "/s";
|
||||
fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n", suffix, res.base, res.wid);
|
||||
clr_vector(res);
|
||||
fprintf(vvp_out, " %%cvt/rv%s;\n", suffix);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -499,7 +485,7 @@ void draw_eval_real(ivl_expr_t expr)
|
||||
* result to a real value. This is required to get integer
|
||||
* division to work correctly. */
|
||||
if (ivl_expr_value(expr) != IVL_VT_REAL) {
|
||||
draw_real_logic_expr(expr, STUFF_OK_XZ);
|
||||
draw_real_logic_expr(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -547,15 +533,12 @@ void draw_eval_real(ivl_expr_t expr)
|
||||
|
||||
default:
|
||||
if (ivl_expr_value(expr) == IVL_VT_VECTOR) {
|
||||
struct vector_info sv = draw_eval_expr(expr, 0);
|
||||
draw_eval_vec4(expr);
|
||||
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
|
||||
|
||||
clr_vector(sv);
|
||||
int res = allocate_word();
|
||||
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
|
||||
sign_flag, res, sv.base, sv.wid);
|
||||
|
||||
fprintf(vvp_out, " %%ix/vec4%s %d;\n", sign_flag, res);
|
||||
fprintf(vvp_out, " %%cvt/rs %d;\n", res);
|
||||
|
||||
clr_word(res);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user