mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-23 22:36:54 +02:00
Compare commits
577
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb1d4fd278 | ||
|
|
e1deba51ab | ||
|
|
d53014a07f | ||
|
|
7865264de0 | ||
|
|
86661c1538 | ||
|
|
e2dd7425bd | ||
|
|
e01b16e586 | ||
|
|
6adc3c9f13 | ||
|
|
2c1426a44d | ||
|
|
1f5b11246e | ||
|
|
d3caa547ba | ||
|
|
026d941734 | ||
|
|
a577ee447b | ||
|
|
d7b85c42a0 | ||
|
|
dea54df71b | ||
|
|
a3929330b0 | ||
|
|
c404b761b7 | ||
|
|
9b1f2d5971 | ||
|
|
9d7e4ac15f | ||
|
|
d55a3a073a | ||
|
|
01bf741983 | ||
|
|
bf3734110e | ||
|
|
6dcf936807 | ||
|
|
8e0bf3ebff | ||
|
|
380e3a8121 | ||
|
|
1f8ff7ff8d | ||
|
|
b1f1c11441 | ||
|
|
c918cf4a46 | ||
|
|
f835c7569e | ||
|
|
5aecd044c5 | ||
|
|
2a389a9abe | ||
|
|
6527262348 | ||
|
|
79e1273814 | ||
|
|
709c850e69 | ||
|
|
7ed8c0915d | ||
|
|
eef1c968dc | ||
|
|
0985158090 | ||
|
|
090ae5fa56 | ||
|
|
13cb81f4bb | ||
|
|
ef66ca6498 | ||
|
|
d43452f88d | ||
|
|
e719dc250a | ||
|
|
bb0efda526 | ||
|
|
e4d0a92d7c | ||
|
|
28d782e13c | ||
|
|
6f5f700cb9 | ||
|
|
a17924f819 | ||
|
|
893aae2ca4 | ||
|
|
4cbec1c817 | ||
|
|
d84771428a | ||
|
|
484d3ea36b | ||
|
|
c71e930ffa | ||
|
|
15584a4f81 | ||
|
|
f86f454956 | ||
|
|
e01e038cf9 | ||
|
|
c849dfeec4 | ||
|
|
8d7b03576c | ||
|
|
72019959a8 | ||
|
|
9565ea1034 | ||
|
|
49a2693357 | ||
|
|
10a5ca199d | ||
|
|
c2f622327f | ||
|
|
0e2628a3fb | ||
|
|
45dfa28dba | ||
|
|
c8cbac58f5 | ||
|
|
c1b5424ca6 | ||
|
|
c706c94e38 | ||
|
|
fad8abee34 | ||
|
|
9448c5939c | ||
|
|
752a90dc2f | ||
|
|
a60216ec15 | ||
|
|
5d0df8d880 | ||
|
|
1cd13ecdbd | ||
|
|
aeec93a322 | ||
|
|
61930c3b6e | ||
|
|
296f1bacc1 | ||
|
|
bb80b432e6 | ||
|
|
be551a6b68 | ||
|
|
e0834f7f38 | ||
|
|
a26d91557b | ||
|
|
3f73c9bb54 | ||
|
|
09f3eb4a36 | ||
|
|
33885ed891 | ||
|
|
d21277f1b9 | ||
|
|
7b0f675785 | ||
|
|
db339b8fc3 | ||
|
|
4ca7f2a9bd | ||
|
|
3191b3efcb | ||
|
|
1a41ac3145 | ||
|
|
6d4dd5ae3b | ||
|
|
6cb3d86d15 | ||
|
|
7a4f85d382 | ||
|
|
5207be0778 | ||
|
|
2ceb0539af | ||
|
|
f9c67e21b2 | ||
|
|
baa2363e85 | ||
|
|
e5b8abfb23 | ||
|
|
9f6f711f8d | ||
|
|
9a5b7bb0b0 | ||
|
|
eaf1cc9120 | ||
|
|
3bcd42dc8f | ||
|
|
744fbed783 | ||
|
|
c9454b346e | ||
|
|
5ec2c37e7e | ||
|
|
25602e487d | ||
|
|
e037ffd952 | ||
|
|
48c1a7982c | ||
|
|
a842b327c7 | ||
|
|
f8034d69ef | ||
|
|
d94dac28a8 | ||
|
|
680c6f0503 | ||
|
|
39717989a8 | ||
|
|
c26b7ce675 | ||
|
|
c6f6ea7358 | ||
|
|
c0c838f1bc | ||
|
|
1a45e9164f | ||
|
|
8a5f129e56 | ||
|
|
65c2ceb89d | ||
|
|
7a2e9c02cd | ||
|
|
f88415b1d7 | ||
|
|
1250010696 | ||
|
|
506a0ba7d6 | ||
|
|
1d4914c590 | ||
|
|
3e28a10676 | ||
|
|
78028a3310 | ||
|
|
b9cecbef64 | ||
|
|
8b32096e2a | ||
|
|
ba462eb8b7 | ||
|
|
5a09819729 | ||
|
|
d3296d4895 | ||
|
|
39c9c54760 | ||
|
|
8bee5b1108 | ||
|
|
e4c2400eb2 | ||
|
|
1409207def | ||
|
|
30fdadc525 | ||
|
|
a5db0297b0 | ||
|
|
e25f946ac0 | ||
|
|
2f4f075005 | ||
|
|
3ca85491ee | ||
|
|
d8351ec1b2 | ||
|
|
77508b9afa | ||
|
|
38de6ebf3a | ||
|
|
af3ee49f57 | ||
|
|
0cb6ea34d7 | ||
|
|
b6df73d3b9 | ||
|
|
2d79e1a2e0 | ||
|
|
7b311b6adb | ||
|
|
df4a380e42 | ||
|
|
6ff80e80a4 | ||
|
|
8b6b111541 | ||
|
|
fd8f01e317 | ||
|
|
00317dd47f | ||
|
|
e9637f6d11 | ||
|
|
1f9ed2c5ec | ||
|
|
7677b59650 | ||
|
|
9cf4792d53 | ||
|
|
4d9f029000 | ||
|
|
9916686c24 | ||
|
|
c86377790f | ||
|
|
2a791bfb38 | ||
|
|
1d3ac6bc1f | ||
|
|
3fa5a04947 | ||
|
|
7c5b0f737c | ||
|
|
c116808fdb | ||
|
|
553f3d77a9 | ||
|
|
642fbe9fc5 | ||
|
|
395a2248d8 | ||
|
|
be67cae29f | ||
|
|
f62a00bedb | ||
|
|
646a6056a2 | ||
|
|
4504c2bceb | ||
|
|
d343db34fd | ||
|
|
b5e12077b2 | ||
|
|
f3753ea9ad | ||
|
|
45e289d32d | ||
|
|
40cabff44f | ||
|
|
a9c98ad5f2 | ||
|
|
b8e758edf0 | ||
|
|
0b48f69b4e | ||
|
|
d1e7e325b7 | ||
|
|
75b1db0add | ||
|
|
6e965523a1 | ||
|
|
8589c0691b | ||
|
|
99ef8ec4f1 | ||
|
|
d22c9a8b05 | ||
|
|
f84f50842c | ||
|
|
65720f49fe | ||
|
|
6243736481 | ||
|
|
e331e4831b | ||
|
|
78ee61558d | ||
|
|
07c4ff7ea7 | ||
|
|
e5422dddd2 | ||
|
|
6af201ea03 | ||
|
|
27a40cfdcd | ||
|
|
3bd480a375 | ||
|
|
aa951af2b7 | ||
|
|
55747bf79d | ||
|
|
1cd7689d03 | ||
|
|
bd5cc96956 | ||
|
|
a0dbb1aa5d | ||
|
|
4777966b4c | ||
|
|
860a74ddd8 | ||
|
|
2bb645e0bc | ||
|
|
47db80315c | ||
|
|
0348664512 | ||
|
|
3987e0753d | ||
|
|
6b73cc39a5 | ||
|
|
b0de1a8d7e | ||
|
|
37fe6e4219 | ||
|
|
89cdbf63be | ||
|
|
7f955cc070 | ||
|
|
4db5b9d7ed | ||
|
|
dadd145d09 | ||
|
|
bdf5ee7ab7 | ||
|
|
ebaa4c7d5d | ||
|
|
c33600bcc3 | ||
|
|
85d2cc78d6 | ||
|
|
18071562ba | ||
|
|
5aeff6d47d | ||
|
|
a298b03735 | ||
|
|
3d0a2b55ce | ||
|
|
19871efd5a | ||
|
|
1410c339de | ||
|
|
96d32b29c9 | ||
|
|
88816e150a | ||
|
|
409fc4dc19 | ||
|
|
c54b36c902 | ||
|
|
19cbab78b2 | ||
|
|
1736cd9bc8 | ||
|
|
a5264e9995 | ||
|
|
6868127ba3 | ||
|
|
dbbadbc309 | ||
|
|
fb08164cbc | ||
|
|
7e999c5496 | ||
|
|
4fac825457 | ||
|
|
35c66744db | ||
|
|
930e04f6c7 | ||
|
|
37756b8d06 | ||
|
|
596c93ce7e | ||
|
|
edfae1abfb | ||
|
|
624943b3ca | ||
|
|
ef89a760d6 | ||
|
|
050aa277ae | ||
|
|
f03dfb50ad | ||
|
|
6e8474f584 | ||
|
|
4e73b1b133 | ||
|
|
e08e29c8b4 | ||
|
|
b82ca28190 | ||
|
|
e02d186946 | ||
|
|
d9b02657a7 | ||
|
|
d761a2273c | ||
|
|
e3d9cc30a8 | ||
|
|
1ef7994ae2 | ||
|
|
081f397460 | ||
|
|
f800298d01 | ||
|
|
301a25303f | ||
|
|
b24eb6ce88 | ||
|
|
fd60bfd3d2 | ||
|
|
da2c4b0fa1 | ||
|
|
4251979e8b | ||
|
|
12783674cb | ||
|
|
c17ffcae2c | ||
|
|
897f14e60a | ||
|
|
4163eb28d0 | ||
|
|
500442e5c5 | ||
|
|
8c54803094 | ||
|
|
2baf31dff8 | ||
|
|
d997397c38 | ||
|
|
7773000c36 | ||
|
|
042f7ccbcd | ||
|
|
44aa8a6b91 | ||
|
|
43c671cb5c | ||
|
|
a3df37b851 | ||
|
|
c01c2bd742 | ||
|
|
533ee87bb1 | ||
|
|
c810406195 | ||
|
|
3ec8a867db | ||
|
|
899a70908e | ||
|
|
bf95d77562 | ||
|
|
db992e808f | ||
|
|
f2aca68b82 | ||
|
|
12b448ef01 | ||
|
|
e77bb0157e | ||
|
|
75631bd8f1 | ||
|
|
63b1887ff2 | ||
|
|
ba36e47575 | ||
|
|
3866c4526e | ||
|
|
cb08f02de1 | ||
|
|
4188fbecee | ||
|
|
f261bf7e97 | ||
|
|
88dc9b6b63 | ||
|
|
632a265e14 | ||
|
|
449cd0a76e | ||
|
|
181a53d3ed | ||
|
|
44958409f5 | ||
|
|
f81129aa68 | ||
|
|
e5ef0d97bd | ||
|
|
469036990a | ||
|
|
d06f5c7c54 | ||
|
|
9911939576 | ||
|
|
c9ace14c40 | ||
|
|
d5cdb91d55 | ||
|
|
360be597a8 | ||
|
|
75f7c9ae0c | ||
|
|
c926454a41 | ||
|
|
5cfe7ea0aa | ||
|
|
c70fb4ba08 | ||
|
|
7cba9f3cb2 | ||
|
|
d6acb8d059 | ||
|
|
ec23b70bb7 | ||
|
|
58f2f5007d | ||
|
|
0caf4fd9d0 | ||
|
|
037ce08f72 | ||
|
|
27cdd27889 | ||
|
|
f60a6561bb | ||
|
|
204862ac3c | ||
|
|
0f50849fbb | ||
|
|
404c22ac86 | ||
|
|
fe555e4539 | ||
|
|
c87e629150 | ||
|
|
b9d6c816f1 | ||
|
|
0153a25061 | ||
|
|
476a4c7bc4 | ||
|
|
08d80b35cb | ||
|
|
6622b5fe3a | ||
|
|
d7bb5658f2 | ||
|
|
2f3627cd6d | ||
|
|
ce9fd0147f | ||
|
|
be12f56856 | ||
|
|
e0f41198d6 | ||
|
|
fb31a88c51 | ||
|
|
254ccb9ccb | ||
|
|
d2bebee9d9 | ||
|
|
b2c9352bb5 | ||
|
|
15481a9520 | ||
|
|
37723698dc | ||
|
|
af8c08e6a7 | ||
|
|
01249000c3 | ||
|
|
f6edd098a9 | ||
|
|
6321fb6a92 | ||
|
|
69ba009439 | ||
|
|
86e5762b1c | ||
|
|
49363c660c | ||
|
|
1debbc3100 | ||
|
|
ae0b09dd3a | ||
|
|
8d0afa632d | ||
|
|
561953e494 | ||
|
|
83a7796b74 | ||
|
|
ce72eb4eb4 | ||
|
|
7cde5f247e | ||
|
|
849e7cb4d5 | ||
|
|
92c823680a | ||
|
|
05f1541903 | ||
|
|
30d42e2806 | ||
|
|
ebdf4e478a | ||
|
|
f6bc1afcbb | ||
|
|
9013dcb527 | ||
|
|
dbe13aecea | ||
|
|
6521ceaf92 | ||
|
|
f497dbf01e | ||
|
|
8a9486eb49 | ||
|
|
2fb57805ea | ||
|
|
919c1d695c | ||
|
|
1530594b4b | ||
|
|
6f0d8e8dda | ||
|
|
62d7c081dc | ||
|
|
f78994b66c | ||
|
|
50a8c17cf8 | ||
|
|
6f9643df79 | ||
|
|
aeaf8e8433 | ||
|
|
7afb280990 | ||
|
|
99a46fd5af | ||
|
|
eed4ff7e2d | ||
|
|
659714f45d | ||
|
|
8f70c5ca35 | ||
|
|
0ea64ad8ab | ||
|
|
9fbb449e06 | ||
|
|
be3c4cf268 | ||
|
|
0a8fd50c4a | ||
|
|
70db096b6d | ||
|
|
005df31a0d | ||
|
|
d6193c1622 | ||
|
|
a74f2827b2 | ||
|
|
392b162024 | ||
|
|
4af4c8cca9 | ||
|
|
3c4346acb2 | ||
|
|
b8c1f9ab67 | ||
|
|
2e9970a98c | ||
|
|
4914b734dc | ||
|
|
0df3eabe26 | ||
|
|
8fe2211e2b | ||
|
|
645ee2003f | ||
|
|
d6f1162547 | ||
|
|
46991aa65c | ||
|
|
7eb41304e6 | ||
|
|
24da00bd5a | ||
|
|
34efc7db51 | ||
|
|
acf010326c | ||
|
|
d7814ed767 | ||
|
|
19e60b698f | ||
|
|
a7cfdc3a87 | ||
|
|
b010b8e3ca | ||
|
|
26a2c69c2e | ||
|
|
608bad26cf | ||
|
|
70768176f9 | ||
|
|
694a6ed4a1 | ||
|
|
dc15fa965b | ||
|
|
d78739d163 | ||
|
|
d90ce68f5d | ||
|
|
d2c52ff35b | ||
|
|
813b4cf74c | ||
|
|
a437b38270 | ||
|
|
f9d060146c | ||
|
|
7f0c6b9c21 | ||
|
|
5a7cfd8c02 | ||
|
|
babe694366 | ||
|
|
7560b29fb9 | ||
|
|
f6753a9013 | ||
|
|
647e53bcbb | ||
|
|
8439fc6c19 | ||
|
|
6f61cf2e4e | ||
|
|
191187ed1b | ||
|
|
1fb01d4d98 | ||
|
|
3106fe0ed6 | ||
|
|
e29954e03f | ||
|
|
3b5d56e087 | ||
|
|
aa91186119 | ||
|
|
d08f5af9c6 | ||
|
|
b96e471fa2 | ||
|
|
7120ab7b13 | ||
|
|
2f5dcda3b6 | ||
|
|
120b5dc80e | ||
|
|
d762253f74 | ||
|
|
a2dc1e0a29 | ||
|
|
6a1235ac28 | ||
|
|
7aebff2a86 | ||
|
|
1d28b935e8 | ||
|
|
4b4a1c6cac | ||
|
|
110a1b2ac7 | ||
|
|
79558910d1 | ||
|
|
fbf85398da | ||
|
|
1e4b96aa0a | ||
|
|
c064ae6bc3 | ||
|
|
39228f3495 | ||
|
|
12e2237131 | ||
|
|
066a9b7a61 | ||
|
|
cdb180e1d4 | ||
|
|
a8ecce7421 | ||
|
|
8c3461f0ff | ||
|
|
305f448d05 | ||
|
|
b31124983a | ||
|
|
f256dfe16e | ||
|
|
7c152685dc | ||
|
|
5d86dd0bbd | ||
|
|
4f97321c75 | ||
|
|
5f90a3e48c | ||
|
|
96cf190720 | ||
|
|
373832ba22 | ||
|
|
4f472e451e | ||
|
|
7e478cdeb8 | ||
|
|
2576543bb5 | ||
|
|
e453b347f4 | ||
|
|
f132e09475 | ||
|
|
2ee976d1c0 | ||
|
|
30570adf31 | ||
|
|
1c51ac4ac0 | ||
|
|
17a1358eb6 | ||
|
|
d36bbec5b5 | ||
|
|
04a7f7054a | ||
|
|
e97a1ad610 | ||
|
|
e258058cf1 | ||
|
|
c3ac1aac8c | ||
|
|
234f73e7bf | ||
|
|
f49dd97d24 | ||
|
|
7bd1565cfb | ||
|
|
e872310e4b | ||
|
|
6e448da90d | ||
|
|
9f035108e1 | ||
|
|
4bf2e1669d | ||
|
|
dd30c1b39d | ||
|
|
95850ac112 | ||
|
|
d0e154b830 | ||
|
|
4010f6e710 | ||
|
|
d74f2fe38d | ||
|
|
db642e3850 | ||
|
|
523dff7ae7 | ||
|
|
db09f2fa7e | ||
|
|
c2061e8199 | ||
|
|
ff9166d4a5 | ||
|
|
94006cb44c | ||
|
|
2e6ec91ce0 | ||
|
|
73e2b297df | ||
|
|
fe80da362c | ||
|
|
82aca1b02e | ||
|
|
4211e651d0 | ||
|
|
f9e1289463 | ||
|
|
a09b4e3b92 | ||
|
|
6e5373c87e | ||
|
|
ab6ae621cb | ||
|
|
17ae0a6a09 | ||
|
|
041925c123 | ||
|
|
9292a087e8 | ||
|
|
782bfab29e | ||
|
|
df15a0368c | ||
|
|
916f300448 | ||
|
|
fef0fd82ff | ||
|
|
7898f4e402 | ||
|
|
6f8bf90dc4 | ||
|
|
052870c0e5 | ||
|
|
5cbd587833 | ||
|
|
7c9d154461 | ||
|
|
8189c4ee43 | ||
|
|
1be1f65f33 | ||
|
|
fd6f017435 | ||
|
|
05de2f56b4 | ||
|
|
dfa6471227 | ||
|
|
a8f492776a | ||
|
|
6f0d98cf18 | ||
|
|
6f30813102 | ||
|
|
2fab3159dd | ||
|
|
e38494a10c | ||
|
|
f04fb0fc45 | ||
|
|
7a1180868a | ||
|
|
b2bdce98ab | ||
|
|
e178baefbd | ||
|
|
bfa2bfc8ae | ||
|
|
653e2661b2 | ||
|
|
9aa610f489 | ||
|
|
de7fff8ac6 | ||
|
|
2179797763 | ||
|
|
b5e9e44e07 | ||
|
|
5a0fe9ff83 | ||
|
|
f6fede5aae | ||
|
|
0fa3099ded | ||
|
|
6987d16bd3 | ||
|
|
5cc376ebd4 | ||
|
|
8190307dd3 | ||
|
|
3575f68c9f | ||
|
|
c1268d04fc | ||
|
|
ca756f3ec3 | ||
|
|
9af459f95b | ||
|
|
492b240304 | ||
|
|
d2106a3d3a | ||
|
|
cf2f4dd0af | ||
|
|
608c2574bd | ||
|
|
f17db21bf0 | ||
|
|
b26bdd3c19 | ||
|
|
6a9c5d8f7e | ||
|
|
e59f28d659 | ||
|
|
07ae300e0c | ||
|
|
4c5f24c7a7 | ||
|
|
be810c5ba6 | ||
|
|
5ec3b590bf | ||
|
|
88313670c0 | ||
|
|
f9f68236bc | ||
|
|
dadb3a68d3 | ||
|
|
6121c06f15 | ||
|
|
b289d740e2 | ||
|
|
ec266ff52e | ||
|
|
ec773fe8cf | ||
|
|
a412149e2c | ||
|
|
deb7b01717 | ||
|
|
6966c26f27 | ||
|
|
a5e3d06412 | ||
|
|
eb3dcc2786 | ||
|
|
c76e88cad5 | ||
|
|
f588656dd5 | ||
|
|
35e48fb7b7 | ||
|
|
a069b6dbe1 | ||
|
|
48f934abf7 | ||
|
|
2172c8a503 | ||
|
|
cbf96d73ee | ||
|
|
7166aea1d7 | ||
|
|
93b400c4d7 | ||
|
|
a506a18970 | ||
|
|
5b273178f5 | ||
|
|
cde87ed4a3 |
@@ -1,7 +1,7 @@
|
||||
#ifndef __HName_H
|
||||
#define __HName_H
|
||||
/*
|
||||
* Copyright (c) 2001-2007 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2001-2008 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
|
||||
@@ -18,11 +18,9 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: HName.h,v 1.7 2007/06/02 03:42:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <iostream>
|
||||
# include <list>
|
||||
# include "StringHeap.h"
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ > 2
|
||||
@@ -57,7 +55,7 @@ class hname_t {
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
// If the number is anything other then INT_MIN, then this is
|
||||
// If the number is anything other than INT_MIN, then this is
|
||||
// the numeric part of the name. Otherwise, it is not part of
|
||||
// the name at all.
|
||||
int number_;
|
||||
@@ -70,30 +68,16 @@ extern bool operator == (const hname_t&, const hname_t&);
|
||||
extern bool operator != (const hname_t&, const hname_t&);
|
||||
extern ostream& operator<< (ostream&, const hname_t&);
|
||||
|
||||
/*
|
||||
* $Log: HName.h,v $
|
||||
* Revision 1.7 2007/06/02 03:42:12 steve
|
||||
* Properly evaluate scope path expressions.
|
||||
*
|
||||
* Revision 1.6 2007/05/16 19:12:33 steve
|
||||
* Fix hname_t use of space for 1 perm_string.
|
||||
*
|
||||
* Revision 1.5 2007/04/26 03:06:21 steve
|
||||
* Rework hname_t to use perm_strings.
|
||||
*
|
||||
* Revision 1.4 2002/11/02 03:27:51 steve
|
||||
* Allow named events to be referenced by
|
||||
* hierarchical names.
|
||||
*
|
||||
* Revision 1.3 2002/08/12 01:34:58 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.2 2002/06/14 03:25:51 steve
|
||||
* Compiler portability.
|
||||
*
|
||||
* Revision 1.1 2001/12/03 04:47:14 steve
|
||||
* Parser and pform use hierarchical names as hname_t
|
||||
* objects instead of encoded strings.
|
||||
*
|
||||
*/
|
||||
inline ostream& operator<< (ostream&out, const list<hname_t>&ll)
|
||||
{
|
||||
list<hname_t>::const_iterator cur = ll.begin();
|
||||
out << *cur;
|
||||
cur ++;
|
||||
while (cur != ll.end()) {
|
||||
out << "." << *cur;
|
||||
cur ++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+33
-16
@@ -16,9 +16,6 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.181 2007/05/24 04:07:11 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
# This version string is only used in the version message printed
|
||||
@@ -51,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
LEX = @LEX@
|
||||
YACC = @YACC@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
GIT = @GIT@
|
||||
|
||||
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
|
||||
CXXFLAGS = -Wall @CXXFLAGS@
|
||||
@@ -65,7 +65,7 @@ all: dep version.h ivl@EXEEXT@
|
||||
|
||||
# In the windows world, the installer will need a dosify program to
|
||||
# dosify text files.
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
all: dep dosify.exe
|
||||
dosify.exe: dosify.c
|
||||
$(CC) -o dosify.exe dosify.c
|
||||
@@ -99,15 +99,15 @@ distclean: clean
|
||||
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o
|
||||
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
|
||||
|
||||
O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
||||
O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o elab_expr.o \
|
||||
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \
|
||||
elab_sig.o emit.o eval.o eval_attrib.o \
|
||||
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
load_module.o netlist.o netmisc.o net_assign.o \
|
||||
net_design.o net_event.o net_expr.o net_force.o net_func.o \
|
||||
net_link.o net_modulo.o net_nex_input.o net_nex_output.o \
|
||||
net_proc.o net_scope.o net_udp.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_dump.o pform_types.o \
|
||||
net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_disciplines.o pform_dump.o pform_types.o \
|
||||
set_width.o symbol_search.o sync.o sys_funcs.o \
|
||||
verinum.o verireal.o target.o targets.o \
|
||||
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \
|
||||
@@ -174,22 +174,28 @@ lexor.cc: $(srcdir)/lexor.lex
|
||||
lexor_keyword.o: lexor_keyword.cc parse.h
|
||||
|
||||
lexor_keyword.cc: lexor_keyword.gperf
|
||||
gperf -o -i 7 -C -k 1-3,$$ -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,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
|
||||
iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
|
||||
man -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
|
||||
$(MAN) -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
|
||||
|
||||
iverilog-vpi.pdf: iverilog-vpi.ps
|
||||
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
|
||||
$(PS2PDF) iverilog-vpi.ps iverilog-vpi.pdf
|
||||
|
||||
# For VERSION_TAG in driver/main.c, first try git-describe, then look for a
|
||||
# version.h file in the source tree (included in snapshots and releases), and
|
||||
# finally use nothing.
|
||||
.PHONY: version.h
|
||||
# "true" and "false" in the next few lines are Unix shell command names
|
||||
ifeq ($(GIT),none)
|
||||
GIT_PRESENT = false
|
||||
else
|
||||
GIT_PRESENT = true
|
||||
endif
|
||||
version.h:
|
||||
@if test -d $(srcdir)/.git; then \
|
||||
@if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \
|
||||
echo "Using git-describe for VERSION_TAG"; \
|
||||
tmp=`git --git-dir $(srcdir)/.git describe \
|
||||
tmp=`$(GIT) --git-dir $(srcdir)/.git describe \
|
||||
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
|
||||
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
|
||||
elif test -r $(srcdir)/$@; then \
|
||||
@@ -200,10 +206,18 @@ version.h:
|
||||
echo '#define VERSION_TAG ""' > $@; \
|
||||
fi
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: dep iverilog-vpi.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
@@ -217,7 +231,7 @@ endif
|
||||
|
||||
XNF_INSTALL = $(libdir)/ivl/xnf.conf $(libdir)/ivl/xnf-s.conf
|
||||
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(libdir)/ivl/include/disciplines.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
@@ -231,6 +245,9 @@ $(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
|
||||
$(libdir)/ivl/include/constants.vams: $(srcdir)/constants.vams
|
||||
$(INSTALL_DATA) $(srcdir)/constants.vams $@
|
||||
|
||||
$(libdir)/ivl/include/disciplines.vams: $(srcdir)/disciplines.vams
|
||||
$(INSTALL_DATA) $(srcdir)/disciplines.vams $@
|
||||
|
||||
$(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(DESTDIR)$(libdir)/ivl/xnf-s.conf
|
||||
|
||||
@@ -286,7 +303,7 @@ uninstall:
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams; \
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams include/disciplines.vams; \
|
||||
do rm -f $(DESTDIR)$(libdir)/ivl/$$f; done
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl/include
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
/* n is a permallocated string. */
|
||||
Module::Module(perm_string n)
|
||||
: PScope(n, 0)
|
||||
: PScope(n)
|
||||
{
|
||||
library_flag = false;
|
||||
default_nettype = NetNet::NONE;
|
||||
@@ -41,16 +41,6 @@ void Module::add_gate(PGate*gate)
|
||||
gates_.push_back(gate);
|
||||
}
|
||||
|
||||
void Module::add_task(perm_string name, PTask*task)
|
||||
{
|
||||
tasks_[name] = task;
|
||||
}
|
||||
|
||||
void Module::add_function(perm_string name, PFunction *func)
|
||||
{
|
||||
funcs_[name] = func;
|
||||
}
|
||||
|
||||
unsigned Module::port_count() const
|
||||
{
|
||||
return ports.count();
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include <utility>
|
||||
# include "svector.h"
|
||||
# include "StringHeap.h"
|
||||
# include "HName.h"
|
||||
@@ -75,16 +76,35 @@ class Module : public PScope, public LineInfo {
|
||||
|
||||
NetNet::Type default_nettype;
|
||||
|
||||
struct range_t {
|
||||
// True if this is an exclude
|
||||
bool exclude_flag;
|
||||
// lower bound
|
||||
// If low_open_flag is false and low_expr=0, then use -inf
|
||||
bool low_open_flag;
|
||||
PExpr*low_expr;
|
||||
// upper bound
|
||||
// If high_open_flag is false and high_expr=0, then use +inf
|
||||
bool high_open_flag;
|
||||
PExpr*high_expr;
|
||||
// Next range description in list
|
||||
struct range_t*next;
|
||||
};
|
||||
|
||||
/* The module has parameters that are evaluated when the
|
||||
module is elaborated. During parsing, I put the parameters
|
||||
into this map. */
|
||||
struct param_expr_t {
|
||||
PExpr*expr;
|
||||
struct param_expr_t : public LineInfo {
|
||||
param_expr_t() : type(IVL_VT_NO_TYPE), msb(0), lsb(0), signed_flag(false), expr(0), range(0) { }
|
||||
// Type information
|
||||
ivl_variable_type_t type;
|
||||
PExpr*msb;
|
||||
PExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
// Value expression
|
||||
PExpr*expr;
|
||||
// If there are range constraints, list them here
|
||||
range_t*range;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
@@ -99,7 +119,8 @@ class Module : public PScope, public LineInfo {
|
||||
new parameters within the module, but may be used to set
|
||||
values within this module (when instantiated) or in other
|
||||
instantiated modules. */
|
||||
map<pform_name_t,PExpr*>defparms;
|
||||
typedef pair<pform_name_t,PExpr*> named_expr_t;
|
||||
list<named_expr_t>defparms;
|
||||
|
||||
/* Parameters may be overridden at instantiation time;
|
||||
the overrides do not contain explicit parameter names,
|
||||
@@ -119,6 +140,10 @@ class Module : public PScope, public LineInfo {
|
||||
set by the `timescale directive. */
|
||||
int time_unit, time_precision;
|
||||
|
||||
/* Task definitions within this module */
|
||||
map<perm_string,PTask*> tasks;
|
||||
map<perm_string,PFunction*> funcs;
|
||||
|
||||
/* The module has a list of genvars that may be used in
|
||||
various generate schemes. */
|
||||
map<perm_string,LineInfo*> genvars;
|
||||
@@ -133,8 +158,6 @@ class Module : public PScope, public LineInfo {
|
||||
perm_string mod_name() const { return pscope_name(); }
|
||||
|
||||
void add_gate(PGate*gate);
|
||||
void add_task(perm_string name, PTask*def);
|
||||
void add_function(perm_string name, PFunction*def);
|
||||
|
||||
unsigned port_count() const;
|
||||
const svector<PEIdent*>& get_port(unsigned idx) const;
|
||||
@@ -148,18 +171,15 @@ class Module : public PScope, public LineInfo {
|
||||
bool elaborate(Design*, NetScope*scope) const;
|
||||
|
||||
typedef map<perm_string,NetExpr*> replace_t;
|
||||
bool elaborate_scope(Design*, NetScope*scope, const replace_t&rep) const;
|
||||
bool elaborate_scope(Design*, NetScope*scope, const replace_t&rep);
|
||||
|
||||
bool elaborate_sig(Design*, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
list<PGate*> gates_;
|
||||
map<perm_string,PTask*> tasks_;
|
||||
map<perm_string,PFunction*> funcs_;
|
||||
|
||||
static void elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno);
|
||||
Design*des, NetScope*scope);
|
||||
|
||||
private: // Not implemented
|
||||
Module(const Module&);
|
||||
|
||||
@@ -306,10 +306,16 @@ class PEIdent : public PExpr {
|
||||
private:
|
||||
// Common functions to calculate parts of part/bit selects.
|
||||
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
|
||||
NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
|
||||
bool calculate_param_range_(Design*, NetScope*,
|
||||
const NetExpr*msb_ex, long&msb,
|
||||
const NetExpr*lsb_ex, long&lsb) const;
|
||||
|
||||
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
|
||||
|
||||
private:
|
||||
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
|
||||
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
|
||||
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
||||
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
||||
index_component_t::ctype_t) const;
|
||||
@@ -321,6 +327,18 @@ class PEIdent : public PExpr {
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_net(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*net,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PGate_H
|
||||
#define __PGate_H
|
||||
/*
|
||||
* Copyright (c) 1998-2004 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2008 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
|
||||
@@ -18,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: PGate.h,v 1.32 2006/04/10 00:37:42 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
# include "StringHeap.h"
|
||||
@@ -232,9 +229,11 @@ class PGModule : public PGate {
|
||||
PExpr*msb_;
|
||||
PExpr*lsb_;
|
||||
|
||||
friend class delayed_elaborate_scope_mod_instances;
|
||||
void elaborate_mod_(Design*, Module*mod, NetScope*scope) const;
|
||||
void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const;
|
||||
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
|
||||
void elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const;
|
||||
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
|
||||
bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const;
|
||||
|
||||
|
||||
+1
-14
@@ -27,27 +27,14 @@ PGenerate::PGenerate(unsigned id)
|
||||
: id_number(id)
|
||||
{
|
||||
parent = 0;
|
||||
lexical_scope = 0;
|
||||
}
|
||||
|
||||
PGenerate::~PGenerate()
|
||||
{
|
||||
}
|
||||
|
||||
PWire* PGenerate::get_wire(perm_string name) const
|
||||
{
|
||||
map<perm_string,PWire*>::const_iterator obj = wires.find(name);
|
||||
if (obj == wires.end())
|
||||
return 0;
|
||||
else
|
||||
return (*obj).second;
|
||||
}
|
||||
|
||||
void PGenerate::add_gate(PGate*gate)
|
||||
{
|
||||
gates.push_back(gate);
|
||||
}
|
||||
|
||||
void PGenerate::add_behavior(PProcess*proc)
|
||||
{
|
||||
behaviors.push_back(proc);
|
||||
}
|
||||
|
||||
+16
-11
@@ -1,7 +1,7 @@
|
||||
#ifndef __PGenerate_H
|
||||
#define __PGenerate_H
|
||||
/*
|
||||
* Copyright (c) 2006 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2006-2008 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
|
||||
@@ -18,13 +18,11 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: PGenerate.h,v 1.4 2007/06/02 03:42:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "LineInfo.h"
|
||||
# include "StringHeap.h"
|
||||
# include "HName.h"
|
||||
# include "PScope.h"
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include "pform_types.h"
|
||||
@@ -32,7 +30,9 @@
|
||||
class Design;
|
||||
class NetScope;
|
||||
class PExpr;
|
||||
class PFunction;
|
||||
class PProcess;
|
||||
class PTask;
|
||||
class PGate;
|
||||
class PWire;
|
||||
|
||||
@@ -49,10 +49,10 @@ class PWire;
|
||||
* The parent points to the GS_CASE that contains this item.
|
||||
* the loop_test is compared with the parent->loop_test expression.
|
||||
*/
|
||||
class PGenerate : public LineInfo {
|
||||
class PGenerate : public LineInfo, public LexicalScope {
|
||||
|
||||
public:
|
||||
PGenerate(unsigned id_number);
|
||||
explicit PGenerate(unsigned id_number);
|
||||
~PGenerate();
|
||||
|
||||
// Generate schemes have an ID number, for when the scope is
|
||||
@@ -60,6 +60,10 @@ class PGenerate : public LineInfo {
|
||||
const unsigned id_number;
|
||||
perm_string scope_name;
|
||||
|
||||
// This is used during parsing to stack lexical scopes within
|
||||
// this generate scheme.
|
||||
PScope*lexical_scope;
|
||||
|
||||
enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE,
|
||||
GS_CASE, GS_CASE_ITEM};
|
||||
scheme_t scheme_type;
|
||||
@@ -71,16 +75,17 @@ class PGenerate : public LineInfo {
|
||||
PExpr*loop_test;
|
||||
PExpr*loop_step;
|
||||
|
||||
map<perm_string,PWire*>wires;
|
||||
PWire* get_wire(perm_string name) const;
|
||||
|
||||
list<PGate*> gates;
|
||||
void add_gate(PGate*);
|
||||
|
||||
list<PProcess*> behaviors;
|
||||
void add_behavior(PProcess*behave);
|
||||
|
||||
list<PGenerate*> generates;
|
||||
// Tasks instantiated within this scheme.
|
||||
map<perm_string,PTask*> tasks;
|
||||
map<perm_string,PFunction*>funcs;
|
||||
|
||||
// Generate schemes can contain further generate schemes.
|
||||
list<PGenerate*> generate_schemes;
|
||||
PGenerate*parent;
|
||||
|
||||
// This method is called by the elaboration of a module to
|
||||
|
||||
@@ -19,8 +19,13 @@
|
||||
|
||||
# include "PScope.h"
|
||||
|
||||
PScope::PScope(perm_string n, PScope*p)
|
||||
: name_(n), parent_(p)
|
||||
PScope::PScope(perm_string n, PScope*parent)
|
||||
: name_(n), parent_(parent)
|
||||
{
|
||||
}
|
||||
|
||||
PScope::PScope(perm_string n)
|
||||
: name_(n), parent_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,7 +33,7 @@ PScope::~PScope()
|
||||
{
|
||||
}
|
||||
|
||||
PWire* PScope::wires_find(perm_string name)
|
||||
PWire* LexicalScope::wires_find(perm_string name)
|
||||
{
|
||||
map<perm_string,PWire*>::const_iterator cur = wires.find(name);
|
||||
if (cur == wires.end())
|
||||
|
||||
@@ -38,7 +38,22 @@ class NetScope;
|
||||
* NOTE: This is note the same concept as the "scope" of an elaborated
|
||||
* hierarchy. That is represented by NetScope objects after elaboration.
|
||||
*/
|
||||
class PScope {
|
||||
|
||||
class LexicalScope {
|
||||
|
||||
public:
|
||||
explicit LexicalScope() { }
|
||||
// A virtual destructor is so that dynamic_cast can work.
|
||||
virtual ~LexicalScope() { }
|
||||
|
||||
// Nets an variables (wires) in the scope
|
||||
map<perm_string,PWire*>wires;
|
||||
PWire* wires_find(perm_string name);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class PScope : public LexicalScope {
|
||||
|
||||
public:
|
||||
// When created, a scope has a name and a parent. The name is
|
||||
@@ -50,15 +65,12 @@ class PScope {
|
||||
// modules. Scopes for tasks and functions point to their
|
||||
// containing module.
|
||||
PScope(perm_string name, PScope*parent);
|
||||
PScope(perm_string name);
|
||||
virtual ~PScope();
|
||||
|
||||
perm_string pscope_name() const { return name_; }
|
||||
PScope* pscope_parent() { return parent_; }
|
||||
|
||||
// Nets an variables (wires) in the scope
|
||||
map<perm_string,PWire*>wires;
|
||||
PWire* wires_find(perm_string name);
|
||||
|
||||
// Named events in the scope.
|
||||
map<perm_string,PEvent*>events;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ PWire::PWire(perm_string n,
|
||||
signed_(false), isint_(false),
|
||||
port_msb_(0), port_lsb_(0), port_set_(false),
|
||||
net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0),
|
||||
lidx_(0), ridx_(0)
|
||||
lidx_(0), ridx_(0), discipline_(0)
|
||||
{
|
||||
if (t == NetNet::INTEGER) {
|
||||
type_ = NetNet::REG;
|
||||
@@ -135,19 +135,6 @@ bool PWire::get_isint() const
|
||||
return isint_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since implicitly defined list of port declarations are no longer
|
||||
* considered fully defined we no longer need this routine to force
|
||||
* them to be fully defined.
|
||||
*
|
||||
void PWire::set_net_range()
|
||||
{
|
||||
net_msb_ = port_msb_;
|
||||
net_lsb_ = port_lsb_;
|
||||
net_set_ = true;
|
||||
}
|
||||
*/
|
||||
|
||||
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -211,3 +198,13 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||
}
|
||||
}
|
||||
|
||||
void PWire::set_discipline(discipline_t*d)
|
||||
{
|
||||
assert(discipline_ == 0);
|
||||
discipline_ = d;
|
||||
}
|
||||
|
||||
discipline_t* PWire::get_discipline(void) const
|
||||
{
|
||||
return discipline_;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class ostream;
|
||||
|
||||
class PExpr;
|
||||
class Design;
|
||||
class discipline_t;
|
||||
|
||||
/*
|
||||
* The different type of PWire::set_range() calls.
|
||||
@@ -78,10 +79,12 @@ class PWire : public LineInfo {
|
||||
ivl_variable_type_t get_data_type() const;
|
||||
|
||||
void set_range(PExpr*msb, PExpr*lsb, PWSRType type);
|
||||
void set_net_range();
|
||||
|
||||
void set_memory_idx(PExpr*ldx, PExpr*rdx);
|
||||
|
||||
void set_discipline(discipline_t*);
|
||||
discipline_t* get_discipline(void) const;
|
||||
|
||||
map<perm_string,PExpr*> attributes;
|
||||
|
||||
// Write myself to the specified stream.
|
||||
@@ -112,6 +115,8 @@ class PWire : public LineInfo {
|
||||
PExpr*lidx_;
|
||||
PExpr*ridx_;
|
||||
|
||||
discipline_t*discipline_;
|
||||
|
||||
private: // not implemented
|
||||
PWire(const PWire&);
|
||||
PWire& operator= (const PWire&);
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t)
|
||||
}
|
||||
|
||||
PBlock::PBlock(BL_TYPE t)
|
||||
: PScope(perm_string(),0), bl_type_(t)
|
||||
: PScope(perm_string()), bl_type_(t)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -9,11 +9,11 @@
|
||||
echo "Autoconf in root..."
|
||||
autoconf -f
|
||||
|
||||
for dir in vpip vpi vvp tgt-vvp tgt-fpga tgt-stub libveriuser cadpli
|
||||
for dir in vpip vpi vvp tgt-vvp tgt-fpga tgt-stub tgt-vhdl libveriuser cadpli
|
||||
do
|
||||
echo "Autoconf in $dir..."
|
||||
( cd ./$dir ; autoconf -f --include=.. )
|
||||
done
|
||||
|
||||
echo "Precompiling lexor_keyword.gperf"
|
||||
gperf -o -i 7 -C -k 1-3,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
gperf -o -i 7 -C -k 1-4,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
|
||||
+2
-5
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.13 2007/02/06 05:07:31 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -63,7 +60,7 @@ dep:
|
||||
O = cadpli.o
|
||||
|
||||
SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||
endif
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ extern bool debug_scopes;
|
||||
extern bool debug_eval_tree;
|
||||
extern bool debug_elaborate;
|
||||
extern bool debug_synth2;
|
||||
extern bool debug_optimizer;
|
||||
|
||||
/* Path to a directory useful for finding subcomponents. */
|
||||
extern const char*basedir;
|
||||
|
||||
+5
-2
@@ -9,6 +9,9 @@ AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_CHECK_TOOL(STRIP, strip, true)
|
||||
AC_CHECK_PROGS(XGPERF,gperf,none)
|
||||
AC_CHECK_PROGS(MAN,man,none)
|
||||
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
||||
AC_CHECK_PROGS(GIT,git,none)
|
||||
if test "$XGPERF" = "none"
|
||||
then
|
||||
echo ""
|
||||
@@ -119,6 +122,6 @@ AX_C_UNDERSCORES_TRAILING
|
||||
AX_CPP_IDENT
|
||||
|
||||
# XXX disable tgt-fpga for the moment
|
||||
AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp libveriuser cadpli)
|
||||
AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp tgt-vhdl libveriuser cadpli)
|
||||
|
||||
AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile)
|
||||
AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vhdl/Makefile)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "functor.h"
|
||||
# include "compiler.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
@@ -828,6 +829,32 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the select input is constant, then replace with a BUFZ */
|
||||
flag = obj->pin_Sel().nexus()->drivers_constant();
|
||||
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
|
||||
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
|
||||
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
|
||||
tmp->set_line(*obj);
|
||||
|
||||
if (debug_optimizer)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Replace binary MUX with constant select=" << sel_val
|
||||
<< " with a BUFZ to the selected input." << endl;
|
||||
|
||||
tmp->rise_time(obj->rise_time());
|
||||
tmp->fall_time(obj->fall_time());
|
||||
tmp->decay_time(obj->decay_time());
|
||||
|
||||
connect(tmp->pin(0), obj->pin_Result());
|
||||
if (sel_val == verinum::V1)
|
||||
connect(tmp->pin(1), obj->pin_Data(1));
|
||||
else
|
||||
connect(tmp->pin(1), obj->pin_Data(0));
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+101
-10
@@ -88,6 +88,34 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&o, ivl_switch_type_t val)
|
||||
{
|
||||
switch (val) {
|
||||
case IVL_SW_TRAN:
|
||||
o << "tran";
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
o << "tranif0";
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
o << "tranif1";
|
||||
break;
|
||||
case IVL_SW_RTRAN:
|
||||
o << "rtran";
|
||||
break;
|
||||
case IVL_SW_RTRANIF0:
|
||||
o << "rtranif0";
|
||||
break;
|
||||
case IVL_SW_RTRANIF1:
|
||||
o << "rtranif1";
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
o << "tran(VP)";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static inline void dump_scope_path(ostream&o, const NetScope*scope)
|
||||
{
|
||||
if (const NetScope*parent = scope->parent()) {
|
||||
@@ -274,6 +302,22 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCastInt::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Cast to int. (NetCastInt): " <<
|
||||
name() << " width=" << width() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCastReal::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Cast to real (NetCastReal): " <<
|
||||
name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCLShift::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
|
||||
@@ -493,9 +537,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
|
||||
case PV:
|
||||
pt = "PV";
|
||||
break;
|
||||
case BI:
|
||||
pt = "BI";
|
||||
break;
|
||||
}
|
||||
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
|
||||
<< name();
|
||||
@@ -611,6 +652,20 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "" << "endtask" << endl;
|
||||
}
|
||||
|
||||
void NetTran::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << type_ << " " << name()
|
||||
<< " island " << island;
|
||||
if (type_ == IVL_SW_TRAN_VP) {
|
||||
o << " width=" << vector_width()
|
||||
<< " part=" << part_width()
|
||||
<< " offset=" << part_offset();
|
||||
}
|
||||
o << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetUDP::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "UDP (" << udp_name() << "): ";
|
||||
@@ -966,8 +1021,37 @@ void NetScope::dump(ostream&o) const
|
||||
o << "[" << *(*pp).second.msb
|
||||
<< ":" << *(*pp).second.lsb << "] ";
|
||||
|
||||
o << (*pp).first << " = " <<
|
||||
*(*pp).second.expr << ";" << endl;
|
||||
o << (*pp).first << " = " << *(*pp).second.expr;
|
||||
|
||||
for (range_t*ran = (*pp).second.range ; ran ; ran = ran->next) {
|
||||
if (ran->exclude_flag)
|
||||
o << " exclude ";
|
||||
else
|
||||
o << " from ";
|
||||
|
||||
if (ran->low_open_flag)
|
||||
o << "(";
|
||||
else
|
||||
o << "[";
|
||||
if (ran->low_expr)
|
||||
o << *ran->low_expr;
|
||||
else if (ran->low_open_flag==false)
|
||||
o << "-inf";
|
||||
else
|
||||
o << "<?>";
|
||||
if (ran->high_expr)
|
||||
o << ":" << *ran->high_expr;
|
||||
else if (ran->high_open_flag==false)
|
||||
o << ":inf";
|
||||
else
|
||||
o << ":<?>";
|
||||
if (ran->high_open_flag)
|
||||
o << ")";
|
||||
else
|
||||
o << "]";
|
||||
}
|
||||
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
for (pp = localparams.begin()
|
||||
@@ -979,7 +1063,7 @@ void NetScope::dump(ostream&o) const
|
||||
|
||||
/* Dump the saved defparam assignments here. */
|
||||
{
|
||||
map<pform_name_t,NetExpr*>::const_iterator pp;
|
||||
list<pair<pform_name_t,NetExpr*> >::const_iterator pp;
|
||||
for (pp = defparams.begin()
|
||||
; pp != defparams.end() ; pp ++ ) {
|
||||
o << " defparam " << (*pp).first << " = " <<
|
||||
@@ -987,6 +1071,15 @@ void NetScope::dump(ostream&o) const
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
list<pair<list<hname_t>,NetExpr*> >::const_iterator pp;
|
||||
for (pp = defparams_later.begin()
|
||||
; pp != defparams_later.end() ; pp ++ ) {
|
||||
o << " defparam(later) " << pp->first << " = " <<
|
||||
*(pp->second) << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the events in this scope. */
|
||||
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
|
||||
o << " event " << cur->name() << "; nprobe="
|
||||
@@ -1261,11 +1354,9 @@ void NetESignal::dump(ostream&o) const
|
||||
void NetEParam::dump(ostream&o) const
|
||||
{
|
||||
if (scope_ != 0)
|
||||
o << "<" << scope_path(scope_) << "." << name_ << ">";
|
||||
else if (name_)
|
||||
o << "<" << name_ << ">";
|
||||
o << "<" << scope_path(scope_) << "." << (*reference_).first << ">";
|
||||
else
|
||||
o << "<" "???" ">";
|
||||
o << "<" << (*reference_).first << ">";
|
||||
}
|
||||
|
||||
void NetETernary::dump(ostream&o) const
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2008 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
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "discipline.h"
|
||||
|
||||
nature_t::nature_t(perm_string name, perm_string access)
|
||||
: name_(name), access_(access)
|
||||
{
|
||||
}
|
||||
|
||||
nature_t::~nature_t()
|
||||
{
|
||||
}
|
||||
|
||||
discipline_t::discipline_t(perm_string name, ddomain_t domain,
|
||||
nature_t*pot, nature_t*flow)
|
||||
: name_(name), domain_(domain), potential_(pot), flow_(flow)
|
||||
{
|
||||
}
|
||||
|
||||
discipline_t::~discipline_t()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef __discipline_H
|
||||
#define __discipline_H
|
||||
/*
|
||||
* Copyright (c) 2008 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
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* The discipline types include the discipline, nature and other
|
||||
* related types for managing declared and used disciplines in a
|
||||
* Verilog-AMS program.
|
||||
*/
|
||||
|
||||
# include "StringHeap.h"
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
# include "LineInfo.h"
|
||||
|
||||
typedef enum { DD_NONE, DD_DISCRETE, DD_CONTINUOUS } ddomain_t;
|
||||
extern std::ostream& operator << (std::ostream&, ddomain_t);
|
||||
|
||||
class nature_t : public LineInfo {
|
||||
public:
|
||||
explicit nature_t(perm_string name, perm_string access);
|
||||
~nature_t();
|
||||
|
||||
perm_string name() const { return name_; }
|
||||
// Identifier for the access function for this nature
|
||||
perm_string access() const { return access_; }
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
perm_string access_;
|
||||
};
|
||||
|
||||
class discipline_t : public LineInfo {
|
||||
public:
|
||||
explicit discipline_t (perm_string name, ddomain_t dom,
|
||||
nature_t*pot, nature_t*flow);
|
||||
~discipline_t();
|
||||
|
||||
perm_string name() const { return name_; }
|
||||
ddomain_t domain() const { return domain_; }
|
||||
const nature_t*potential() const { return potential_; }
|
||||
const nature_t*flow() const { return flow_; }
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
ddomain_t domain_;
|
||||
nature_t*potential_;
|
||||
nature_t*flow_;
|
||||
|
||||
private: // not implemented
|
||||
discipline_t(const discipline_t&);
|
||||
discipline_t& operator = (const discipline_t&);
|
||||
};
|
||||
|
||||
extern map<perm_string,nature_t*> natures;
|
||||
extern map<perm_string,discipline_t*> disciplines;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
// Standard definitions for Verilog-AMS
|
||||
`ifdef DISCIPLINES_VAMS
|
||||
`else
|
||||
`define DISCIPLINES_VAMS 1
|
||||
|
||||
discipline \logic ;
|
||||
domain discrete;
|
||||
enddiscipline
|
||||
|
||||
discipline ddiscrete;
|
||||
domain discrete;
|
||||
enddiscipline
|
||||
|
||||
nature Current;
|
||||
units = "A";
|
||||
access = I;
|
||||
idt_nature = Charge;
|
||||
`ifdef CURRENT_ABSTOL
|
||||
abstol = `CURRENT_ABSTOL
|
||||
`else
|
||||
abstol = 1e-12;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Charge;
|
||||
units = "coul";
|
||||
access = Q;
|
||||
ddt_nature = Current;
|
||||
`ifdef CHARGE_ABSTOL
|
||||
abstol = `CHARGE_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-14;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Voltage;
|
||||
units = "V";
|
||||
access = V;
|
||||
idt_nature = Flux;
|
||||
`ifdef VOLTAGE_ABSTOL
|
||||
abstol = `VOLTAGE_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-6;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Flux;
|
||||
units = "Wb";
|
||||
access = Phi;
|
||||
ddt_nature = Voltage;
|
||||
`ifdef FLUX_ABSTOL
|
||||
abstol = `flux_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-9;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
discipline electrical;
|
||||
potential Voltage;
|
||||
flow Current;
|
||||
enddiscipline
|
||||
|
||||
discipline voltage;
|
||||
potential Voltage;
|
||||
enddiscipline
|
||||
|
||||
discipline current;
|
||||
flow Current;
|
||||
enddiscipline
|
||||
|
||||
`endif // !`ifdef DISCIPLINES_VAMS
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.7.2.1 2006/10/04 17:08:59 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.8.3
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: iverilog-vpi@EXEEXT@
|
||||
|
||||
check: all
|
||||
|
||||
clean:
|
||||
rm -f *.o config.h
|
||||
rm -f iverilog-vpi@EXEEXT@
|
||||
|
||||
+8
-8
@@ -336,6 +336,14 @@ static int parse(int argc, char *argv[])
|
||||
assignn(&gstr.pOUT, argv[idx],
|
||||
strlen(argv[idx])-strlen(dot_o_ext));
|
||||
}
|
||||
/* Check for the -mingw option */
|
||||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --name option */
|
||||
else if (startsWith(name_option, argv[idx])) {
|
||||
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
|
||||
@@ -356,14 +364,6 @@ static int parse(int argc, char *argv[])
|
||||
append(&gstr.pDEFS, " ");
|
||||
append(&gstr.pDEFS, argv[idx]);
|
||||
}
|
||||
/* Check for the -mingw option */
|
||||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --cflags option */
|
||||
else if (stricmp("--cflags", argv[idx]) == 0) {
|
||||
setup_ivl_environment();
|
||||
|
||||
+14
-7
@@ -16,9 +16,6 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:31 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.9.devel
|
||||
@@ -41,6 +38,8 @@ CC = @CC@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
|
||||
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
|
||||
CFLAGS = -Wall @CFLAGS@
|
||||
@@ -76,15 +75,23 @@ cflexor.o: cflexor.c cfparse.h cfparse_misc.h globals.h
|
||||
cfparse.o: cfparse.c globals.h cfparse_misc.h
|
||||
|
||||
iverilog.ps: $(srcdir)/iverilog.man
|
||||
man -t $(srcdir)/iverilog.man > iverilog.ps
|
||||
$(MAN) -t $(srcdir)/iverilog.man > iverilog.ps
|
||||
|
||||
iverilog.pdf: iverilog.ps
|
||||
ps2pdf iverilog.ps iverilog.pdf
|
||||
$(PS2PDF) iverilog.ps iverilog.pdf
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/iverilog.pdf $(mandir)/man1/iverilog.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: iverilog.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
|
||||
@@ -223,6 +223,12 @@ mostly by EDIF format output. The Icarus Verilog fpga code generator
|
||||
can generate complete designs or EDIF macros that can in turn be
|
||||
imported into larger designs by other tools. The \fBfpga\fP target
|
||||
implies the synthesis \fB-S\fP flag.
|
||||
.TP 8
|
||||
.B vhdl
|
||||
This target produces a VHDL translation of the Verilog netlist. The
|
||||
output is a single file containing VHDL entities corresponding to
|
||||
the modules in the Verilog source code. Note that only a subset of
|
||||
the Verilog language is supported. See the wiki for more information.
|
||||
|
||||
.SH "WARNING TYPES"
|
||||
These are the types of warnings that can be selected by the \fB-W\fP
|
||||
|
||||
+17
-13
@@ -327,21 +327,26 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||
remove(defines_path);
|
||||
remove(compiled_defines_path);
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW just returns the exit status, so return it! */
|
||||
free(cmd);
|
||||
return rc;
|
||||
#else
|
||||
int rtn = 0;
|
||||
if (rc != 0) {
|
||||
if (rc == 127) {
|
||||
fprintf(stderr, "Failed to execute: %s\n", cmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (WIFEXITED(rc))
|
||||
return WEXITSTATUS(rc);
|
||||
|
||||
fprintf(stderr, "Command signaled: %s\n", cmd);
|
||||
return -1;
|
||||
rtn = 1;
|
||||
} else if (WIFEXITED(rc)) {
|
||||
rtn = WEXITSTATUS(rc);
|
||||
} else {
|
||||
fprintf(stderr, "Command signaled: %s\n", cmd);
|
||||
rtn = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
free(cmd);
|
||||
return rtn;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -501,7 +506,7 @@ int process_generation(const char*name)
|
||||
" 2005 -- IEEE1364-2005\n"
|
||||
"Other generation flags:\n"
|
||||
" specify | no-specify\n"
|
||||
" verilog-ams | no-verinlog-ams\n"
|
||||
" verilog-ams | no-verilog-ams\n"
|
||||
" std-include | no-std-include\n"
|
||||
" xtypes | no-xtypes\n"
|
||||
" icarus-misc | no-icarus-misc\n"
|
||||
@@ -867,6 +872,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
fprintf(stderr, "Command signaled: %s\n", cmd);
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -885,6 +891,4 @@ int main(int argc, char **argv)
|
||||
fclose(iconfig_file);
|
||||
|
||||
return t_default(cmd, ncmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+214
-105
@@ -716,6 +716,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if (!rep->value().is_defined()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be undefined (" << rep->value()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << rep->value().as_long()
|
||||
@@ -873,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we know that this is an indexed part select (up or down) this
|
||||
* method calculates the up/down base, as far at it can be calculated.
|
||||
*/
|
||||
NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.lsb != 0);
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
|
||||
NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
|
||||
const NetExpr*par_msb, long&par_msv,
|
||||
const NetExpr*par_lsb, long&par_lsv) const
|
||||
{
|
||||
if (par_msb == 0) {
|
||||
// If the parameter doesn't have an explicit range, then
|
||||
// just return range values of 0:0. The par_msv==0 is
|
||||
// correct. The par_msv is not necessarily correct, but
|
||||
// clients of this function don't need a correct value.
|
||||
ivl_assert(*this, par_lsb == 0);
|
||||
par_msv = 0;
|
||||
par_lsv = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetEConst*tmp = dynamic_cast<const NetEConst*> (par_msb);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
par_msv = tmp->value().as_long();
|
||||
|
||||
tmp = dynamic_cast<const NetEConst*> (par_lsb);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
par_lsv = tmp->value().as_long();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const
|
||||
@@ -1085,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static verinum param_part_select_bits(const verinum&par_val, long wid,
|
||||
long lsv, long par_lsv)
|
||||
{
|
||||
verinum result (verinum::Vx, wid, true);
|
||||
|
||||
for (long idx = 0 ; idx < wid ; idx += 1) {
|
||||
long off = idx + lsv - par_lsv;
|
||||
if (off < 0)
|
||||
result.set(idx, verinum::Vx);
|
||||
else if (off < (long)par_val.len())
|
||||
result.set(idx, par_val.get(off));
|
||||
else if (par_val.is_string()) // Pad strings with nulls.
|
||||
result.set(idx, verinum::V0);
|
||||
else if (par_val.has_len()) // Pad sized parameters with X
|
||||
result.set(idx, verinum::Vx);
|
||||
else // Unsized parameters are "infinite" width.
|
||||
result.set(idx, sign_bit(par_val));
|
||||
}
|
||||
|
||||
// If the input is a string, and the part select is working on
|
||||
// byte boundaries, then make the result into a string.
|
||||
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
|
||||
return result.as_string();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
long msv, lsv;
|
||||
bool flag = calculate_parts_(des, scope, msv, lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
long par_msv, par_lsv;
|
||||
flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
// Notice that the par_msv is not used in this function other
|
||||
// than for this test. It is used to tell the direction that
|
||||
// the bits are numbers, so that we can make sure the
|
||||
// direction matches the part select direction. After that,
|
||||
// we only need the par_lsv.
|
||||
if ((msv>lsv && par_msv<par_lsv) || (msv<lsv && par_msv>=par_lsv)) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< "[" << msv << ":" << lsv << "] is out of order." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long wid = 1 + labs(msv-lsv);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Calculate part select "
|
||||
<< "[" << msv << ":" << lsv << "] from range "
|
||||
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||
|
||||
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||
ivl_assert(*this, par_ex);
|
||||
|
||||
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
|
||||
NetEConst*result_ex = new NetEConst(result);
|
||||
result_ex->set_line(*this);
|
||||
|
||||
return result_ex;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
|
||||
long par_msv, par_lsv;
|
||||
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
if (base == 0)
|
||||
return 0;
|
||||
|
||||
unsigned long wid = 0;
|
||||
calculate_up_do_width_(des, scope, wid);
|
||||
|
||||
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||
ivl_assert(*this, par_ex);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Calculate part select "
|
||||
<< "[" << *base << "+:" << wid << "] from range "
|
||||
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||
|
||||
// Handle the special case that the base is constant. In this
|
||||
// case, just precalculate the entire constant result.
|
||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||
long lsv = base_c->value().as_long();
|
||||
|
||||
// Watch out for reversed bit numbering. We're making
|
||||
// the part select from LSB to MSB.
|
||||
if (par_msv < par_lsv)
|
||||
lsv = lsv - wid + 1;
|
||||
|
||||
verinum result = param_part_select_bits(par_ex->value(), wid,
|
||||
lsv, par_lsv);
|
||||
NetEConst*result_ex = new NetEConst(result);
|
||||
result_ex->set_line(*this);
|
||||
return result_ex;
|
||||
}
|
||||
|
||||
if ((par_msb < par_lsb) && (wid>1))
|
||||
base = make_add_expr(base, 1-(long)wid);
|
||||
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
tmp = new NetESelect(tmp, base, wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the case that the identifier is a parameter reference. The
|
||||
* parameter expression has already been located for us (as the par
|
||||
@@ -1097,84 +1276,29 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
|
||||
const name_component_t&name_tail = path_.back();
|
||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty())
|
||||
use_sel = name_tail.index.back().sel;
|
||||
|
||||
if (use_sel == index_component_t::SEL_PART) {
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.msb);
|
||||
ivl_assert(*this, index_tail.lsb);
|
||||
// NOTE TO SELF: This is the way I want to see this code
|
||||
// structured. This closely follows the structure of the
|
||||
// elaborate_expr_net_ code, which splits all the various
|
||||
// selects to different methods.
|
||||
if (use_sel == index_component_t::SEL_PART)
|
||||
return elaborate_expr_param_part_(des, scope, par, found_in,
|
||||
par_msb, par_lsb);
|
||||
|
||||
/* If the identifier has a part select, we support
|
||||
it by pulling the right bits out and making a
|
||||
sized unsigned constant. This code assumes the
|
||||
lsb of a parameter is 0 and the msb is the
|
||||
width of the parameter. */
|
||||
if (use_sel == index_component_t::SEL_IDX_UP)
|
||||
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
|
||||
par_msb, par_lsb);
|
||||
|
||||
verinum*lsn = index_tail.lsb->eval_const(des, scope);
|
||||
verinum*msn = index_tail.msb->eval_const(des, scope);
|
||||
if ((lsn == 0) || (msn == 0)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
"Part select expressions must be "
|
||||
"constant expressions." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
// NOTE TO SELF (continued): The code below should be
|
||||
// rewritten in the above format, as I get to it.
|
||||
|
||||
long lsb = lsn->as_long();
|
||||
long msb = msn->as_long();
|
||||
if ((lsb < 0) || (msb < lsb)) {
|
||||
cerr << get_fileline() << ": error: invalid part "
|
||||
<< "select: " << path_
|
||||
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned long ulsb=lsb;
|
||||
unsigned long umsb=msb;
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
assert(le);
|
||||
|
||||
verinum result (verinum::V0, msb-lsb+1, true);
|
||||
verinum exl = le->value();
|
||||
|
||||
/* Pull the bits from the parameter, one at a
|
||||
time. If the bit is within the range, simply
|
||||
copy it to the result. If the bit is outside
|
||||
the range, we sign extend signed unsized
|
||||
numbers, zero extend unsigned unsigned numbers,
|
||||
and X extend sized numbers. */
|
||||
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
|
||||
if (idx < exl.len())
|
||||
result.set(idx-lsb, exl.get(idx));
|
||||
else if (exl.is_string())
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
else if (exl.has_len())
|
||||
result.set(idx-lsb, verinum::Vx);
|
||||
else if (exl.has_sign())
|
||||
result.set(idx-lsb, exl.get(exl.len()-1));
|
||||
else
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
}
|
||||
|
||||
/* If the input is a string, and the part select
|
||||
is working on byte boundaries, then the result
|
||||
can be made into a string. */
|
||||
if (exl.is_string()
|
||||
&& (lsb%8 == 0)
|
||||
&& (result.len()%8 == 0))
|
||||
result = verinum(result.as_string());
|
||||
|
||||
delete tmp;
|
||||
tmp = new NetEConst(result);
|
||||
|
||||
} else if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) {
|
||||
if (use_sel == index_component_t::SEL_IDX_DO) {
|
||||
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
@@ -1249,7 +1373,7 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
par_mv = par_me->value().as_long();
|
||||
par_lv = par_le->value().as_long();
|
||||
}
|
||||
/* Convert the index to cannonical bit address. */
|
||||
/* Convert the index to canonical bit address. */
|
||||
long ridx = rv.as_long();
|
||||
if (par_mv >= par_lv) {
|
||||
ridx -= par_lv;
|
||||
@@ -1361,8 +1485,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||
// Special case: The index is out of range, so the value
|
||||
// of this expression is a 'bx vector the width of a word.
|
||||
if (!net->array_index_is_valid(addr)) {
|
||||
verinum xxx (verinum::Vx, net->vector_width());
|
||||
NetEConst*resx = new NetEConst(xxx);
|
||||
NetEConst*resx = make_const_x(net->vector_width());
|
||||
resx->set_line(*this);
|
||||
delete word_index;
|
||||
return resx;
|
||||
@@ -1428,16 +1551,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
negative values. However, the width that they represent is
|
||||
unsigned. Remember that any order is possible,
|
||||
i.e., [1:0], [-4:6], etc. */
|
||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
||||
if (wid > net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
//delete lsn;
|
||||
//delete msn;
|
||||
return net;
|
||||
}
|
||||
ivl_assert(*this, wid <= net->vector_width());
|
||||
unsigned long wid = 1 + labs(msv-lsv);
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
@@ -1448,26 +1562,29 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
//delete lsn;
|
||||
//delete msn;
|
||||
return net;
|
||||
}
|
||||
long sb_lsb = net->sig()->sb_to_idx(lsv);
|
||||
long sb_msb = net->sig()->sb_to_idx(msv);
|
||||
|
||||
// If the part select covers exactly the entire
|
||||
// vector, then do not bother with it. Return the
|
||||
// signal itself.
|
||||
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
|
||||
// signal itself, casting to unsigned if necessary.
|
||||
if (sb_lsb == 0 && wid == net->vector_width()) {
|
||||
net->cast_signed(false);
|
||||
return net;
|
||||
}
|
||||
|
||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
||||
// If the part select covers NONE of the vector, then return a
|
||||
// constant X.
|
||||
|
||||
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
|
||||
NetEConst*tmp = make_const_x(wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||
ss->set_line(*this);
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
@@ -1477,14 +1594,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||
NetESignal*net, NetScope*found_in) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.lsb != 0);
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
|
||||
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
|
||||
unsigned long wid = 0;
|
||||
calculate_up_do_width_(des, scope, wid);
|
||||
@@ -1609,8 +1719,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||
/* The bit select is out of range of the
|
||||
vector. This is legal, but returns a
|
||||
constant 1'bx value. */
|
||||
verinum x (verinum::Vx);
|
||||
NetEConst*tmp = new NetEConst(x);
|
||||
NetEConst*tmp = make_const_x(1);
|
||||
tmp->set_line(*this);
|
||||
|
||||
cerr << get_fileline() << ": warning: Bit select ["
|
||||
|
||||
+71
-102
@@ -208,101 +208,18 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
return 0;
|
||||
}
|
||||
|
||||
long msb, lsb;
|
||||
NetExpr*mux;
|
||||
|
||||
if (use_sel == index_component_t::SEL_BIT) {
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
ivl_assert(*this, index_tail.lsb == 0);
|
||||
|
||||
/* If there is only a single select expression, it is a
|
||||
bit select. Evaluate the constant value and treat it
|
||||
as a part select with a bit width of 1. If the
|
||||
expression it not constant, then return the
|
||||
expression as a mux. */
|
||||
|
||||
NetExpr*index_expr = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
|
||||
if (NetEConst*index_con = dynamic_cast<NetEConst*> (index_expr)) {
|
||||
msb = index_con->value().as_long();
|
||||
lsb = index_con->value().as_long();
|
||||
mux = 0;
|
||||
|
||||
} else {
|
||||
msb = 0;
|
||||
lsb = 0;
|
||||
mux = index_expr;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* No select expressions, so presume a part select the
|
||||
width of the register. */
|
||||
|
||||
msb = reg->msb();
|
||||
lsb = reg->lsb();
|
||||
mux = 0;
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
elaborate_lval_net_bit_(des, scope, lv);
|
||||
return lv;
|
||||
}
|
||||
|
||||
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
|
||||
|
||||
NetAssign_*lv;
|
||||
if (mux) {
|
||||
|
||||
/* If there is a non-constant bit select, make a
|
||||
NetAssign_ to the target reg and attach a
|
||||
bmux to select the target bit. */
|
||||
lv = new NetAssign_(reg);
|
||||
|
||||
/* Correct the mux for the range of the vector. */
|
||||
if (reg->msb() < reg->lsb())
|
||||
mux = make_sub_expr(reg->lsb(), mux);
|
||||
else if (reg->lsb() != 0)
|
||||
mux = make_add_expr(mux, - reg->lsb());
|
||||
|
||||
lv->set_part(mux, 1);
|
||||
|
||||
} else if (msb == reg->msb() && lsb == reg->lsb()) {
|
||||
|
||||
/* No bit select, and part select covers the entire
|
||||
vector. Simplest case. */
|
||||
lv = new NetAssign_(reg);
|
||||
|
||||
} else {
|
||||
|
||||
/* If the bit/part select is constant, then make the
|
||||
NetAssign_ only as wide as it needs to be and connect
|
||||
only to the selected bits of the reg. */
|
||||
unsigned loff = reg->sb_to_idx(lsb);
|
||||
unsigned moff = reg->sb_to_idx(msb);
|
||||
unsigned wid = moff - loff + 1;
|
||||
|
||||
if (moff < loff) {
|
||||
cerr << get_fileline() << ": error: part select "
|
||||
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
||||
<< " is reversed." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the part select extends beyond the extreme of the
|
||||
variable, then report an error. Note that loff is
|
||||
converted to normalized form so is relative the
|
||||
variable pins. */
|
||||
|
||||
if ((wid + loff) > reg->vector_width()) {
|
||||
cerr << get_fileline() << ": error: bit/part select "
|
||||
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
||||
<< " is out of range." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv = new NetAssign_(reg);
|
||||
lv->set_part(new NetEConst(verinum(loff)), wid);
|
||||
}
|
||||
/* No select expressions. */
|
||||
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
|
||||
return lv;
|
||||
}
|
||||
@@ -374,10 +291,67 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
return lv;
|
||||
}
|
||||
|
||||
bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||
NetScope*scope,
|
||||
NetAssign_*lv) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
ivl_assert(*this, index_tail.lsb == 0);
|
||||
|
||||
NetNet*reg = lv->sig();
|
||||
|
||||
// Bit selects have a single select expression. Evaluate the
|
||||
// constant value and treat it as a part select with a bit
|
||||
// width of 1.
|
||||
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
long lsb = 0;
|
||||
|
||||
if (NetEConst*index_con = dynamic_cast<NetEConst*> (mux)) {
|
||||
lsb = index_con->value().as_long();
|
||||
mux = 0;
|
||||
}
|
||||
|
||||
if (mux) {
|
||||
// Non-constant bit mux. Correct the mux for the range
|
||||
// of the vector, then set the l-value part select expression.
|
||||
if (reg->msb() < reg->lsb())
|
||||
mux = make_sub_expr(reg->lsb(), mux);
|
||||
else if (reg->lsb() != 0)
|
||||
mux = make_add_expr(mux, - reg->lsb());
|
||||
|
||||
lv->set_part(mux, 1);
|
||||
|
||||
} else if (lsb == reg->msb() && lsb == reg->lsb()) {
|
||||
// Constant bit mux that happens to select the only bit
|
||||
// of the l-value. Don't bother with any select at all.
|
||||
|
||||
} else {
|
||||
// Constant bit select that does something useful.
|
||||
long loff = reg->sb_to_idx(lsb);
|
||||
|
||||
if (loff < 0 || loff >= (long)reg->vector_width()) {
|
||||
cerr << get_fileline() << ": error: bit select "
|
||||
<< reg->name() << "[" <<lsb<<"]"
|
||||
<< " is out of range." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->set_part(new NetEConst(verinum(loff)), 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||
NetScope*scope,
|
||||
NetAssign_*lv) const
|
||||
{
|
||||
// The range expressions of a part select must be
|
||||
// constant. The calculate_parts_ function calculates the
|
||||
// values into msb and lsb.
|
||||
long msb, lsb;
|
||||
bool flag = calculate_parts_(des, scope, msb, lsb);
|
||||
if (!flag)
|
||||
@@ -388,17 +362,14 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||
|
||||
if (msb == reg->msb() && lsb == reg->lsb()) {
|
||||
|
||||
/* No bit select, and part select covers the entire
|
||||
vector. Simplest case. */
|
||||
/* Part select covers the entire vector. Simplest case. */
|
||||
|
||||
} else {
|
||||
|
||||
/* If the bit/part select is constant, then make the
|
||||
NetAssign_ only as wide as it needs to be and connect
|
||||
only to the selected bits of the reg. */
|
||||
unsigned loff = reg->sb_to_idx(lsb);
|
||||
unsigned moff = reg->sb_to_idx(msb);
|
||||
unsigned wid = moff - loff + 1;
|
||||
/* Get the canonical offsets into the vector. */
|
||||
long loff = reg->sb_to_idx(lsb);
|
||||
long moff = reg->sb_to_idx(msb);
|
||||
long wid = moff - loff + 1;
|
||||
|
||||
if (moff < loff) {
|
||||
cerr << get_fileline() << ": error: part select "
|
||||
@@ -408,17 +379,15 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the part select extends beyond the extreme of the
|
||||
/* If the part select extends beyond the extremes of the
|
||||
variable, then report an error. Note that loff is
|
||||
converted to normalized form so is relative the
|
||||
variable pins. */
|
||||
|
||||
if ((wid + loff) > reg->vector_width()) {
|
||||
cerr << get_fileline() << ": error: bit/part select "
|
||||
if (loff < 0 || moff >= (signed)reg->vector_width()) {
|
||||
cerr << get_fileline() << ": warning: Part select "
|
||||
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
||||
<< " is out of range." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
lv->set_part(new NetEConst(verinum(loff)), wid);
|
||||
|
||||
+116
-47
@@ -137,7 +137,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope,
|
||||
const NetExpr* decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
|
||||
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
|
||||
|
||||
if (lsig == 0 || rsig == 0) return 0;
|
||||
|
||||
@@ -449,26 +449,21 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
|
||||
const NetExpr* fall,
|
||||
const NetExpr* decay) const
|
||||
{
|
||||
|
||||
/* Elaborate the operands of the compare first as expressions
|
||||
(so that the eval_tree method can reduce constant
|
||||
expressions, including parameters) then turn those results
|
||||
into synthesized nets. */
|
||||
NetExpr*lexp = elab_and_eval(des, scope, left_, lwidth),
|
||||
*rexp = elab_and_eval(des, scope, right_, lwidth);
|
||||
NetExpr*lexp = elab_and_eval(des, scope, left_, -1),
|
||||
*rexp = elab_and_eval(des, scope, right_, -1);
|
||||
|
||||
if (lexp == 0 || rexp == 0) return 0;
|
||||
|
||||
unsigned operand_width;
|
||||
bool real_arg = false;
|
||||
if (lexp->expr_type() == IVL_VT_REAL ||
|
||||
rexp->expr_type() == IVL_VT_REAL) {
|
||||
operand_width = 1;
|
||||
real_arg = true;
|
||||
} else {
|
||||
bool real_arg = true;
|
||||
if (lexp->expr_type() != IVL_VT_REAL &&
|
||||
rexp->expr_type() != IVL_VT_REAL) {
|
||||
/* Choose the operand width to be the width of the widest
|
||||
self-determined operand. */
|
||||
operand_width = lexp->expr_width();
|
||||
unsigned operand_width = lexp->expr_width();
|
||||
if (rexp->expr_width() > operand_width)
|
||||
operand_width = rexp->expr_width();
|
||||
|
||||
@@ -476,6 +471,8 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
|
||||
lexp = pad_to_width(lexp, operand_width);
|
||||
rexp->set_width(operand_width);
|
||||
rexp = pad_to_width(rexp, operand_width);
|
||||
|
||||
real_arg = false;
|
||||
}
|
||||
|
||||
NetNet*lsig = 0;
|
||||
@@ -719,6 +716,16 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope,
|
||||
|
||||
unsigned rwidth = lwidth;
|
||||
|
||||
// If either operand is IVL_VT_REAL, then cast the other to
|
||||
// IVL_VT_REAL so that the division can become IVL_VT_REAL.
|
||||
|
||||
if (lsig->data_type()==IVL_VT_REAL || rsig->data_type()==IVL_VT_REAL) {
|
||||
if (lsig->data_type() != IVL_VT_REAL)
|
||||
lsig = cast_to_real(des, scope, lsig);
|
||||
if (rsig->data_type() != IVL_VT_REAL)
|
||||
rsig = cast_to_real(des, scope, rsig);
|
||||
}
|
||||
|
||||
if (rwidth == 0) {
|
||||
rwidth = lsig->vector_width();
|
||||
if (rsig->vector_width() > rwidth)
|
||||
@@ -790,8 +797,8 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
|
||||
const NetExpr* fall,
|
||||
const NetExpr* decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
|
||||
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
|
||||
|
||||
if (lsig == 0 || rsig == 0) return 0;
|
||||
|
||||
@@ -1578,6 +1585,14 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!erep->value().is_defined()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be undefined (" << erep->value()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (erep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << erep->value().as_long()
|
||||
@@ -1779,8 +1794,32 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
|
||||
that connects to a signal with the correct name. */
|
||||
if (par != 0) {
|
||||
|
||||
// Detect and handle the special case that we have a
|
||||
// real valued parameter. Return a NetLiteral and a
|
||||
// properly typed net.
|
||||
if (const NetECReal*pc = dynamic_cast<const NetECReal*>(par)) {
|
||||
NetLiteral*tmp = new NetLiteral(scope, scope->local_symbol(),
|
||||
pc->value());
|
||||
des->add_node(tmp);
|
||||
tmp->set_line(*par);
|
||||
sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::IMPLICIT);
|
||||
sig->set_line(*tmp);
|
||||
sig->data_type(tmp->data_type());
|
||||
sig->local_flag(true);
|
||||
|
||||
connect(tmp->pin(0), sig->pin(0));
|
||||
return sig;
|
||||
}
|
||||
|
||||
const NetEConst*pc = dynamic_cast<const NetEConst*>(par);
|
||||
assert(pc);
|
||||
if (pc == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Non-consant parameter value?: " << *par << endl;
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "Expression type is " << par->expr_type() << endl;
|
||||
}
|
||||
ivl_assert(*this, pc);
|
||||
verinum pvalue = pc->value();
|
||||
|
||||
/* If the parameter has declared dimensions, then apply
|
||||
@@ -2288,7 +2327,7 @@ NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
|
||||
} while (0);
|
||||
#else
|
||||
if (name_tail.index.size() > sig->array_dimensions())
|
||||
tmp = process_select_(des, scope, sig);
|
||||
tmp = process_select_(des, scope, tmp);
|
||||
|
||||
#endif
|
||||
return tmp;
|
||||
@@ -2367,30 +2406,53 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
osig->local_flag(true);
|
||||
osig->set_line(*this);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating part selects "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
if (bidirectional_flag) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating tran(VP) "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetTran*ps = new NetTran(scope, scope->local_symbol(),
|
||||
osig->vector_width(), wid, off);
|
||||
des->add_node(ps);
|
||||
ps->set_line(*this);
|
||||
|
||||
connect(ps->pin(0), osig->pin(0));
|
||||
connect(ps->pin(1), nets[idx]->pin(0));
|
||||
|
||||
ivl_assert(*this, wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating part selects "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
NetPartSelect::dir_t part_dir = NetPartSelect::VP;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
||||
des->add_node(ps);
|
||||
ps->set_line(*this);
|
||||
|
||||
connect(ps->pin(1), osig->pin(0));
|
||||
connect(ps->pin(0), nets[idx]->pin(0));
|
||||
|
||||
assert(wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
assert(width == 0);
|
||||
}
|
||||
|
||||
NetPartSelect::dir_t part_dir = bidirectional_flag
|
||||
? NetPartSelect::BI
|
||||
: NetPartSelect::VP;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
||||
des->add_node(ps);
|
||||
|
||||
connect(ps->pin(1), osig->pin(0));
|
||||
connect(ps->pin(0), nets[idx]->pin(0));
|
||||
|
||||
assert(wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
assert(width == 0);
|
||||
|
||||
osig->data_type(nets[0]->data_type());
|
||||
osig->local_flag(true);
|
||||
return osig;
|
||||
@@ -2743,11 +2805,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
/* If we are processing a tran or inout, then the
|
||||
partselect is bi-directional. Otherwise, it is a
|
||||
Part-to-Vector select. */
|
||||
NetPartSelect::dir_t part_dir;
|
||||
if (bidirectional_flag)
|
||||
part_dir = NetPartSelect::BI;
|
||||
else
|
||||
part_dir = NetPartSelect::PV;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
@@ -2764,11 +2821,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
subsig->local_flag(true);
|
||||
subsig->set_line(*this);
|
||||
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
part_dir);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
if (bidirectional_flag) {
|
||||
// Make a tran(VP)
|
||||
NetTran*sub = new NetTran(scope, scope->local_symbol(),
|
||||
sig->vector_width(),
|
||||
subnet_wid, lidx);
|
||||
sub->set_line(*this);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), sig->pin(0));
|
||||
connect(sub->pin(1), subsig->pin(0));
|
||||
|
||||
} else {
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
NetPartSelect::PV);
|
||||
des->add_node(sub);
|
||||
sub->set_line(*this);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
}
|
||||
sig = subsig;
|
||||
}
|
||||
|
||||
|
||||
+269
-80
@@ -22,6 +22,7 @@
|
||||
# include "netmisc.h"
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
@@ -43,16 +44,16 @@
|
||||
# include "util.h"
|
||||
# include <typeinfo>
|
||||
# include <assert.h>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno)
|
||||
Design*des, NetScope*scope)
|
||||
{
|
||||
PExpr*ex = cur.expr;
|
||||
assert(ex);
|
||||
|
||||
NetExpr*val = ex->elaborate_pexpr(des, scope);
|
||||
if (val == 0) return;
|
||||
|
||||
NetExpr*msb = 0;
|
||||
NetExpr*lsb = 0;
|
||||
bool signed_flag = cur.signed_flag;
|
||||
@@ -63,9 +64,53 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
parameter value is coerced to have the correct
|
||||
and defined width. */
|
||||
if (cur.msb) {
|
||||
assert(cur.lsb);
|
||||
msb = cur.msb ->elaborate_pexpr(des, scope);
|
||||
assert(msb);
|
||||
lsb = cur.lsb ->elaborate_pexpr(des, scope);
|
||||
assert(lsb);
|
||||
}
|
||||
|
||||
NetScope::range_t*range_list = 0;
|
||||
for (Module::range_t*range = cur.range ; range ; range = range->next) {
|
||||
NetScope::range_t*tmp = new NetScope::range_t;
|
||||
tmp->exclude_flag = range->exclude_flag;
|
||||
tmp->low_open_flag = range->low_open_flag;
|
||||
tmp->high_open_flag = range->high_open_flag;
|
||||
|
||||
if (range->low_expr) {
|
||||
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
|
||||
ivl_assert(*range->low_expr, tmp->low_expr);
|
||||
} else {
|
||||
tmp->low_expr = 0;
|
||||
}
|
||||
|
||||
if (range->high_expr && range->high_expr==range->low_expr) {
|
||||
// Detect the special case of a "point"
|
||||
// range. These are called out by setting the high
|
||||
// and low expression ranges to the same
|
||||
// expression. The exclude_flags should be false
|
||||
// in this case
|
||||
ivl_assert(*range->high_expr, tmp->low_open_flag==false && tmp->high_open_flag==false);
|
||||
tmp->high_expr = tmp->low_expr;
|
||||
|
||||
} else if (range->high_expr) {
|
||||
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
|
||||
ivl_assert(*range->high_expr, tmp->high_expr);
|
||||
} else {
|
||||
tmp->high_expr = 0;
|
||||
}
|
||||
|
||||
tmp->next = range_list;
|
||||
range_list = tmp;
|
||||
}
|
||||
|
||||
/* Set the parameter expression to 0 if the evaluation failed. */
|
||||
if (val == 0) {
|
||||
val = scope->set_parameter(name, val, cur.type, msb, lsb,
|
||||
signed_flag, range_list, cur);
|
||||
delete val;
|
||||
return;
|
||||
}
|
||||
|
||||
if (signed_flag) {
|
||||
@@ -81,14 +126,103 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
signed_flag = val->has_sign();
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val,
|
||||
msb, lsb, signed_flag, file, lineno);
|
||||
assert(val);
|
||||
val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag,
|
||||
range_list, cur);
|
||||
delete val;
|
||||
}
|
||||
|
||||
static void elaborate_scope_tasks(Design*des, NetScope*scope,
|
||||
const LineInfo&loc,
|
||||
const map<perm_string,PTask*>&tasks)
|
||||
{
|
||||
typedef map<perm_string,PTask*>::const_iterator tasks_it_t;
|
||||
|
||||
for (tasks_it_t cur = tasks.begin()
|
||||
; cur != tasks.end() ; cur ++ ) {
|
||||
|
||||
hname_t use_name( (*cur).first );
|
||||
if (scope->child(use_name)) {
|
||||
cerr << loc.get_fileline() << ": error: task/scope name "
|
||||
<< use_name << " already used in this context."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
NetScope*task_scope = new NetScope(scope, use_name,
|
||||
NetScope::TASK);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void elaborate_scope_funcs(Design*des, NetScope*scope,
|
||||
const LineInfo&loc,
|
||||
const map<perm_string,PFunction*>&funcs)
|
||||
{
|
||||
typedef map<perm_string,PFunction*>::const_iterator funcs_it_t;
|
||||
|
||||
for (funcs_it_t cur = funcs.begin()
|
||||
; cur != funcs.end() ; cur ++ ) {
|
||||
|
||||
hname_t use_name( (*cur).first );
|
||||
if (scope->child(use_name)) {
|
||||
cerr << loc.get_fileline() << ": error: function/scope name "
|
||||
<< use_name << " already used in this context."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
NetScope*func_scope = new NetScope(scope, use_name,
|
||||
NetScope::FUNC);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class generate_schemes_work_item_t : public elaborator_work_item_t {
|
||||
public:
|
||||
generate_schemes_work_item_t(Design*des, NetScope*scope, Module*mod)
|
||||
: elaborator_work_item_t(des), scope_(scope), mod_(mod)
|
||||
{ }
|
||||
|
||||
void elaborate_runrun()
|
||||
{
|
||||
if (debug_scopes)
|
||||
cerr << mod_->get_fileline() << ": debug: "
|
||||
<< "Processing generate schemes for "
|
||||
<< scope_path(scope_) << endl;
|
||||
|
||||
// Generate schemes can create new scopes in the form of
|
||||
// generated code. Scan the generate schemes, and *generate*
|
||||
// new scopes, which is slightly different from simple
|
||||
// elaboration.
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = mod_->generate_schemes.begin()
|
||||
; cur != mod_->generate_schemes.end() ; cur ++ ) {
|
||||
(*cur) -> generate_scope(des, scope_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// The scope_ is the scope that contains the generate scheme
|
||||
// we are to work on. the mod_ is the Module definition for
|
||||
// that scope, and contains the parsed generate schemes.
|
||||
NetScope*scope_;
|
||||
Module*mod_;
|
||||
};
|
||||
|
||||
bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
const replace_t&replacements) const
|
||||
const replace_t&replacements)
|
||||
{
|
||||
if (debug_scopes) {
|
||||
cerr << get_fileline() << ": debug: Elaborate scope "
|
||||
@@ -107,8 +241,6 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
// place of the elaborated expression.
|
||||
|
||||
typedef map<perm_string,param_expr_t>::const_iterator mparm_it_t;
|
||||
typedef map<pform_name_t,PExpr*>::const_iterator pform_parm_it_t;
|
||||
|
||||
|
||||
// This loop scans the parameters in the module, and creates
|
||||
// stub parameter entries in the scope for the parameter name.
|
||||
@@ -120,8 +252,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
tmp->set_line(*((*cur).second.expr));
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
scope->set_parameter((*cur).first, tmp, (*cur).second.type,
|
||||
0, 0, false, 0, (*cur).second);
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
@@ -132,8 +264,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
if ((*cur).second.msb)
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
scope->set_parameter((*cur).first, tmp, (*cur).second.type,
|
||||
0, 0, false, 0, (*cur).second);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,8 +277,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
}
|
||||
|
||||
/* run parameter replacements that were collected from the
|
||||
@@ -166,6 +297,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
<< "Replace " << (*cur).first
|
||||
<< " with expression " << *val
|
||||
<< " from " << val->get_fileline() << "." << endl;
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "Type=" << val->expr_type() << endl;
|
||||
}
|
||||
bool flag = scope->replace_parameter((*cur).first, val);
|
||||
if (! flag) {
|
||||
@@ -178,8 +311,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
}
|
||||
|
||||
// Run through the defparams for this module, elaborate the
|
||||
@@ -192,15 +324,17 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
// here because the parameter receiving the assignment may be
|
||||
// in a scope not discovered by this pass.
|
||||
|
||||
for (pform_parm_it_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; cur ++ ) {
|
||||
typedef list<Module::named_expr_t>::const_iterator defparms_iter_t;
|
||||
for (defparms_iter_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; cur ++) {
|
||||
|
||||
PExpr*ex = (*cur).second;
|
||||
PExpr*ex = cur->second;
|
||||
assert(ex);
|
||||
|
||||
NetExpr*val = ex->elaborate_pexpr(des, scope);
|
||||
if (val == 0) continue;
|
||||
scope->defparams[(*cur).first] = val;
|
||||
|
||||
scope->defparams.push_back(make_pair(cur->first, val));
|
||||
}
|
||||
|
||||
// Evaluate the attributes. Evaluate them in the scope of the
|
||||
@@ -213,66 +347,29 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
|
||||
delete[]attr;
|
||||
|
||||
// Generate schemes can create new scopes in the form of
|
||||
// generated code. Scan the generate schemes, and *generate*
|
||||
// new scopes, which is slightly different from simple
|
||||
// elaboration.
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generate_schemes.begin()
|
||||
; cur != generate_schemes.end() ; cur ++ ) {
|
||||
(*cur) -> generate_scope(des, scope);
|
||||
}
|
||||
// Generate schemes need to have their scopes elaborated, but
|
||||
// we cannot do that until defparams are run, so push it off
|
||||
// into an elaborate work item.
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Schedule generates within " << scope_path(scope)
|
||||
<< " for elaboration after defparams." << endl;
|
||||
|
||||
des->elaboration_work_list.push_back(new generate_schemes_work_item_t(des, scope, this));
|
||||
|
||||
// Tasks introduce new scopes, so scan the tasks in this
|
||||
// module. Create a scope for the task and pass that to the
|
||||
// elaborate_scope method of the PTask for detailed
|
||||
// processing.
|
||||
|
||||
typedef map<perm_string,PTask*>::const_iterator tasks_it_t;
|
||||
|
||||
for (tasks_it_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++ ) {
|
||||
|
||||
hname_t use_name( (*cur).first );
|
||||
if (scope->child(use_name)) {
|
||||
cerr << get_fileline() << ": error: task/scope name "
|
||||
<< use_name << " already used in this context."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
NetScope*task_scope = new NetScope(scope, use_name,
|
||||
NetScope::TASK);
|
||||
task_scope->set_line((*cur).second);
|
||||
(*cur).second->elaborate_scope(des, task_scope);
|
||||
}
|
||||
elaborate_scope_tasks(des, scope, *this, tasks);
|
||||
|
||||
|
||||
// Functions are very similar to tasks, at least from the
|
||||
// perspective of scopes. So handle them exactly the same
|
||||
// way.
|
||||
|
||||
typedef map<perm_string,PFunction*>::const_iterator funcs_it_t;
|
||||
|
||||
for (funcs_it_t cur = funcs_.begin()
|
||||
; cur != funcs_.end() ; cur ++ ) {
|
||||
|
||||
hname_t use_name( (*cur).first );
|
||||
if (scope->child(use_name)) {
|
||||
cerr << get_fileline() << ": error: function/scope name "
|
||||
<< use_name << " already used in this context."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
NetScope*func_scope = new NetScope(scope, use_name,
|
||||
NetScope::FUNC);
|
||||
func_scope->set_line((*cur).second);
|
||||
(*cur).second->elaborate_scope(des, func_scope);
|
||||
}
|
||||
|
||||
elaborate_scope_funcs(des, scope, *this, funcs);
|
||||
|
||||
// Gates include modules, which might introduce new scopes, so
|
||||
// scan all of them to create those scopes.
|
||||
@@ -386,7 +483,12 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
container->genvar_tmp_val = genvar;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
NetEConst*test = dynamic_cast<NetEConst*>(test_ex);
|
||||
assert(test);
|
||||
if (test == 0) {
|
||||
cerr << get_fileline() << ": error: Cannot evaluate genvar"
|
||||
<< " conditional expression: " << *loop_test << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
while (test->value().as_long()) {
|
||||
|
||||
// The actual name of the scope includes the genvar so
|
||||
@@ -421,9 +523,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
genvar_verinum);
|
||||
// The file and line information should really come
|
||||
// from the genvar statement, not the for loop.
|
||||
scope->set_localparam(loop_index, gp, get_file(),
|
||||
get_lineno());
|
||||
|
||||
scope->set_localparam(loop_index, gp, *this);
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Create implicit localparam "
|
||||
@@ -435,7 +535,12 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
// Calculate the step for the loop variable.
|
||||
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
|
||||
NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
|
||||
assert(step);
|
||||
if (step == 0) {
|
||||
cerr << get_fileline() << ": error: Cannot evaluate genvar"
|
||||
<< " step expression: " << *loop_step << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: genvar step from "
|
||||
<< genvar << " to " << step->value().as_long() << endl;
|
||||
@@ -460,7 +565,12 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
||||
{
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
NetEConst*test = dynamic_cast<NetEConst*> (test_ex);
|
||||
assert(test);
|
||||
if (test == 0) {
|
||||
cerr << get_fileline() << ": error: Cannot evaluate genvar"
|
||||
<< " conditional expression: " << *loop_test << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the condition evaluates as false, then do not create the
|
||||
// scope.
|
||||
@@ -502,7 +612,12 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
{
|
||||
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex);
|
||||
assert(case_value_co);
|
||||
if (case_value_co == 0) {
|
||||
cerr << get_fileline() << ": error: Cannot evaluate genvar case"
|
||||
<< " expression: " << *loop_test << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The name of the scope to generate, whatever that item is.
|
||||
hname_t use_name (scope_name);
|
||||
@@ -514,8 +629,8 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
PGenerate*default_item = 0;
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generator_it_t;
|
||||
generator_it_t cur = generates.begin();
|
||||
while (cur != generates.end()) {
|
||||
generator_it_t cur = generate_schemes.begin();
|
||||
while (cur != generate_schemes.end()) {
|
||||
PGenerate*item = *cur;
|
||||
assert( item->scheme_type == PGenerate::GS_CASE_ITEM );
|
||||
|
||||
@@ -544,7 +659,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
delete case_value_co;
|
||||
case_value_co = 0;
|
||||
|
||||
PGenerate*item = (cur == generates.end())? default_item : *cur;
|
||||
PGenerate*item = (cur == generate_schemes.end())? default_item : *cur;
|
||||
if (item == 0) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "No generate items found" << endl;
|
||||
@@ -571,11 +686,14 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
|
||||
// from simple elaboration.
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generates.begin()
|
||||
; cur != generates.end() ; cur ++ ) {
|
||||
for (generate_it_t cur = generate_schemes.begin()
|
||||
; cur != generate_schemes.end() ; cur ++ ) {
|
||||
(*cur) -> generate_scope(des, scope);
|
||||
}
|
||||
|
||||
elaborate_scope_tasks(des, scope, *this, tasks);
|
||||
elaborate_scope_funcs(des, scope, *this, funcs);
|
||||
|
||||
// Scan the generated scope for gates that may create
|
||||
// their own scopes.
|
||||
typedef list<PGate*>::const_iterator pgate_list_it_t;
|
||||
@@ -584,10 +702,51 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
|
||||
(*cur) ->elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
typedef list<PProcess*>::const_iterator proc_it_t;
|
||||
for (proc_it_t cur = behaviors.begin()
|
||||
; cur != behaviors.end() ; cur ++ ) {
|
||||
(*cur) -> statement() -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
// Save the scope that we created, for future use.
|
||||
scope_list_.push_back(scope);
|
||||
}
|
||||
|
||||
class delayed_elaborate_scope_mod_instances : public elaborator_work_item_t {
|
||||
|
||||
public:
|
||||
delayed_elaborate_scope_mod_instances(Design*des,
|
||||
const PGModule*obj,
|
||||
Module*mod,
|
||||
NetScope*sc)
|
||||
: elaborator_work_item_t(des), obj_(obj), mod_(mod), sc_(sc)
|
||||
{ }
|
||||
~delayed_elaborate_scope_mod_instances() { }
|
||||
|
||||
virtual void elaborate_runrun();
|
||||
|
||||
private:
|
||||
const PGModule*obj_;
|
||||
Module*mod_;
|
||||
NetScope*sc_;
|
||||
};
|
||||
|
||||
void delayed_elaborate_scope_mod_instances::elaborate_runrun()
|
||||
{
|
||||
if (debug_scopes)
|
||||
cerr << obj_->get_fileline() << ": debug: "
|
||||
<< "Resume scope elaboration of instances of "
|
||||
<< mod_->mod_name() << "." << endl;
|
||||
|
||||
obj_->elaborate_scope_mod_instances_(des, mod_, sc_);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we handle the elaborate scope of a module instance. The caller
|
||||
* has already figured out that this "gate" is a module, and has found
|
||||
* the module definition. The "sc" argument is the scope that will
|
||||
* contain this instance.
|
||||
*/
|
||||
void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||
{
|
||||
if (get_name() == "") {
|
||||
@@ -634,6 +793,36 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||
return;
|
||||
}
|
||||
|
||||
if (msb_ || lsb_) {
|
||||
// If there are expressions to evaluate in order to know
|
||||
// the actual number of instances that will be
|
||||
// instantiated, then we have to delay further scope
|
||||
// elaboration until after defparams (above me) are
|
||||
// run. Do that by appending a work item to the
|
||||
// elaboration work list.
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: delay elaborate_scope"
|
||||
<< " of array of " << get_name()
|
||||
<< " in scope " << scope_path(sc) << "." << endl;
|
||||
|
||||
elaborator_work_item_t*tmp
|
||||
= new delayed_elaborate_scope_mod_instances(des, this, mod, sc);
|
||||
des->elaboration_work_list.push_back(tmp);
|
||||
|
||||
} else {
|
||||
// If there are no expressions that need to be evaluated
|
||||
// to elaborate the scope of this next instances, then
|
||||
// get right to it.
|
||||
elaborate_scope_mod_instances_(des, mod, sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is called to process a module instantiation after basic
|
||||
* sanity testing is already complete.
|
||||
*/
|
||||
void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const
|
||||
{
|
||||
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0;
|
||||
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;
|
||||
NetEConst*msb = dynamic_cast<NetEConst*> (mse);
|
||||
|
||||
+61
-37
@@ -108,6 +108,42 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
|
||||
return flag;
|
||||
}
|
||||
|
||||
static void elaborate_sig_funcs(Design*des, NetScope*scope,
|
||||
const map<perm_string,PFunction*>&funcs)
|
||||
{
|
||||
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
|
||||
|
||||
for (mfunc_it_t cur = funcs.begin()
|
||||
; cur != funcs.end() ; cur ++) {
|
||||
|
||||
hname_t use_name ( (*cur).first );
|
||||
NetScope*fscope = scope->child(use_name);
|
||||
if (scope == 0) {
|
||||
cerr << (*cur).second->get_fileline() << ": internal error: "
|
||||
<< "Child scope for function " << (*cur).first
|
||||
<< " missing in " << scope_path(scope) << "." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
(*cur).second->elaborate_sig(des, fscope);
|
||||
}
|
||||
}
|
||||
|
||||
static void elaborate_sig_tasks(Design*des, NetScope*scope,
|
||||
const map<perm_string,PTask*>&tasks)
|
||||
{
|
||||
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
|
||||
|
||||
for (mtask_it_t cur = tasks.begin()
|
||||
; cur != tasks.end() ; cur ++) {
|
||||
NetScope*tscope = scope->child( hname_t((*cur).first) );
|
||||
assert(tscope);
|
||||
(*cur).second->elaborate_sig(des, tscope);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Module::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
@@ -182,38 +218,12 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
|
||||
flag &= (*gt)->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
|
||||
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
|
||||
|
||||
for (mfunc_it_t cur = funcs_.begin()
|
||||
; cur != funcs_.end() ; cur ++) {
|
||||
|
||||
hname_t use_name ( (*cur).first );
|
||||
NetScope*fscope = scope->child(use_name);
|
||||
if (scope == 0) {
|
||||
cerr << (*cur).second->get_fileline() << ": internal error: "
|
||||
<< "Child scope for function " << (*cur).first
|
||||
<< " missing in " << scope_path(scope) << "." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
(*cur).second->elaborate_sig(des, fscope);
|
||||
}
|
||||
|
||||
|
||||
// After all the wires are elaborated, we are free to
|
||||
// elaborate the ports of the tasks defined within this
|
||||
// module. Run through them now.
|
||||
|
||||
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
|
||||
|
||||
for (mtask_it_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++) {
|
||||
NetScope*tscope = scope->child( hname_t((*cur).first) );
|
||||
assert(tscope);
|
||||
(*cur).second->elaborate_sig(des, tscope);
|
||||
}
|
||||
elaborate_sig_funcs(des, scope, funcs);
|
||||
elaborate_sig_tasks(des, scope, tasks);
|
||||
|
||||
// initial and always blocks may contain begin-end and
|
||||
// fork-join blocks that can introduce scopes. Therefore, I
|
||||
@@ -415,8 +425,8 @@ bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
|
||||
<< scope_path(container) << "." << endl;
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generates.begin()
|
||||
; cur != generates.end() ; cur ++) {
|
||||
for (generate_it_t cur = generate_schemes.begin()
|
||||
; cur != generate_schemes.end() ; cur ++) {
|
||||
PGenerate*item = *cur;
|
||||
if (! item->scope_list_.empty()) {
|
||||
flag &= item->elaborate_sig(des, container);
|
||||
@@ -461,9 +471,12 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
|
||||
cur->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
elaborate_sig_funcs(des, scope, funcs);
|
||||
elaborate_sig_tasks(des, scope, tasks);
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generates.begin()
|
||||
; cur != generates.end() ; cur ++ ) {
|
||||
for (generate_it_t cur = generate_schemes.begin()
|
||||
; cur != generate_schemes.end() ; cur ++ ) {
|
||||
(*cur) -> elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
@@ -576,9 +589,17 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: I don't know how "
|
||||
<< "to deal with return type of function "
|
||||
<< scope->basename() << "." << endl;
|
||||
if (ports_) {
|
||||
cerr << get_fileline() << ": internal error: I don't know "
|
||||
<< "how to deal with return type of function "
|
||||
<< scope->basename() << "." << endl;
|
||||
} else {
|
||||
/* If we do not have any ports or a return type this
|
||||
* is probably a bad function definition. */
|
||||
cerr << get_fileline() << ": error: Bad definition for "
|
||||
<< "function " << scope->basename() << "?" << endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
svector<NetNet*>ports (ports_? ports_->count() : 0);
|
||||
@@ -990,8 +1011,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal "
|
||||
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name_
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name_;
|
||||
if (array_dimensions > 0) {
|
||||
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
|
||||
}
|
||||
cerr << " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+315
-87
@@ -94,7 +94,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
||||
assert(lval->pin_count() == 1);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: PGassign: elaborated l-value"
|
||||
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
|
||||
<< " width=" << lval->vector_width()
|
||||
<< ", type=" << lval->data_type() << endl;
|
||||
}
|
||||
@@ -113,14 +113,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
||||
return;
|
||||
}
|
||||
|
||||
/* If either lval or rid are real then both must be real. */
|
||||
if ((lval->data_type() == IVL_VT_REAL ||
|
||||
rid->data_type() == IVL_VT_REAL) &&
|
||||
lval->data_type() != rid->data_type()) {
|
||||
cerr << get_fileline() << ": sorry: Both the r-value and "
|
||||
"the l-value must be real in this context." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
/* Cast the right side when needed. */
|
||||
if ((lval->data_type() == IVL_VT_REAL &&
|
||||
rid->data_type() != IVL_VT_REAL)) {
|
||||
rid = cast_to_real(des, scope, rid);
|
||||
} else if ((lval->data_type() != IVL_VT_REAL &&
|
||||
rid->data_type() == IVL_VT_REAL)) {
|
||||
rid = cast_to_int(des, scope, rid, lval->vector_width());
|
||||
}
|
||||
|
||||
ivl_assert(*this, rid);
|
||||
@@ -287,14 +286,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
||||
assert(lval && rval);
|
||||
assert(rval->pin_count() == 1);
|
||||
|
||||
/* If either lval or rval are real then both must be real. */
|
||||
if ((lval->data_type() == IVL_VT_REAL ||
|
||||
rval->data_type() == IVL_VT_REAL) &&
|
||||
lval->data_type() != rval->data_type()) {
|
||||
cerr << get_fileline() << ": sorry: Both the r-value and "
|
||||
"the l-value must be real in this context." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
/* Cast the right side when needed. */
|
||||
if ((lval->data_type() == IVL_VT_REAL &&
|
||||
rval->data_type() != IVL_VT_REAL)) {
|
||||
rval = cast_to_real(des, scope, rval);
|
||||
} else if ((lval->data_type() != IVL_VT_REAL &&
|
||||
rval->data_type() == IVL_VT_REAL)) {
|
||||
rval = cast_to_int(des, scope, rval, lval->vector_width());
|
||||
}
|
||||
|
||||
/* If the r-value insists on being smaller then the l-value
|
||||
@@ -386,7 +384,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
high = msb.as_long();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: PGBuiltin: Make arrray "
|
||||
cerr << get_fileline() << ": debug: PGBuiltin: Make array "
|
||||
<< "[" << high << ":" << low << "]"
|
||||
<< " of " << count << " gates for " << name << endl;
|
||||
}
|
||||
@@ -419,7 +417,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
/* Allocate all the netlist nodes for the gates. */
|
||||
NetLogic**cur = new NetLogic*[count];
|
||||
NetNode**cur = new NetNode*[count];
|
||||
assert(cur);
|
||||
|
||||
/* Calculate the gate delays from the delay expressions
|
||||
@@ -659,6 +657,67 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
||||
NetLogic::XOR, instance_width);
|
||||
break;
|
||||
case TRAN:
|
||||
if (pin_count() != 2) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tran device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN);
|
||||
}
|
||||
break;
|
||||
case RTRAN:
|
||||
if (pin_count() != 2) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtran device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TRANIF0:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tranif0 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0);
|
||||
}
|
||||
break;
|
||||
case RTRANIF0:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtranif0 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0);
|
||||
}
|
||||
break;
|
||||
case TRANIF1:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tranif1 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1);
|
||||
}
|
||||
break;
|
||||
case RTRANIF1:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtranif1 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: unhandled "
|
||||
"gate type." << endl;
|
||||
@@ -670,13 +729,18 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
cur[idx]->attribute(attrib_list[adx].key,
|
||||
attrib_list[adx].val);
|
||||
|
||||
cur[idx]->rise_time(rise_time);
|
||||
cur[idx]->fall_time(fall_time);
|
||||
cur[idx]->decay_time(decay_time);
|
||||
/* The logic devices have some uniform processing. Then
|
||||
all may have output delays and output drive strength. */
|
||||
if (NetLogic*log = dynamic_cast<NetLogic*> (cur[idx])) {
|
||||
log->rise_time(rise_time);
|
||||
log->fall_time(fall_time);
|
||||
log->decay_time(decay_time);
|
||||
|
||||
cur[idx]->pin(0).drive0(drive_type(strength0()));
|
||||
cur[idx]->pin(0).drive1(drive_type(strength1()));
|
||||
log->pin(0).drive0(drive_type(strength0()));
|
||||
log->pin(0).drive1(drive_type(strength1()));
|
||||
}
|
||||
|
||||
cur[idx]->set_line(*this);
|
||||
des->add_node(cur[idx]);
|
||||
}
|
||||
|
||||
@@ -798,6 +862,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// "cur" is an array of pointers, and we don't need it any more.
|
||||
delete[]cur;
|
||||
}
|
||||
|
||||
NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
@@ -812,6 +879,31 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
tmp->local_flag(true);
|
||||
tmp->set_line(*sig);
|
||||
|
||||
// Handle the special case of a bi-directional part
|
||||
// select. Create a NetTran(VP) instead of a uni-directional
|
||||
// NetPartSelect node.
|
||||
if (dir == NetNet::PINOUT) {
|
||||
unsigned wida = sig->vector_width();
|
||||
unsigned widb = tmp->vector_width();
|
||||
bool part_b = widb < wida;
|
||||
NetTran*node = new NetTran(scope, scope->local_symbol(),
|
||||
part_b? wida : widb,
|
||||
part_b? widb : wida,
|
||||
0);
|
||||
if (part_b) {
|
||||
connect(node->pin(0), sig->pin(0));
|
||||
connect(node->pin(1), tmp->pin(0));
|
||||
} else {
|
||||
connect(node->pin(0), tmp->pin(0));
|
||||
connect(node->pin(1), sig->pin(0));
|
||||
}
|
||||
|
||||
node->set_line(*this);
|
||||
des->add_node(node);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetPartSelect*node = 0;
|
||||
|
||||
switch (dir) {
|
||||
@@ -840,15 +932,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
break;
|
||||
|
||||
case NetNet::PINOUT:
|
||||
if (sig->vector_width() > tmp->vector_width()) {
|
||||
node = new NetPartSelect(sig, 0, tmp->vector_width(),
|
||||
NetPartSelect::BI);
|
||||
connect(node->pin(0), tmp->pin(0));
|
||||
} else {
|
||||
node = new NetPartSelect(tmp, 0, sig->vector_width(),
|
||||
NetPartSelect::BI);
|
||||
connect(node->pin(0), sig->pin(0));
|
||||
}
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -860,6 +944,17 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static bool need_bufz_for_input_port(const svector<NetNet*>&prts)
|
||||
{
|
||||
if (prts[0]->port_type() != NetNet::PINPUT)
|
||||
return false;
|
||||
|
||||
if (prts[0]->pin(0).nexus()->drivers_present())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a module by recursively elaborating it. Set the path of
|
||||
* the recursive elaboration so that signal names get properly
|
||||
@@ -1074,11 +1169,11 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||
|
||||
/* Input to module. elaborate the expression to
|
||||
the desired width. If this in an instance
|
||||
array, then let the net determine it's own
|
||||
array, then let the net determine its own
|
||||
width. We use that, then, to decide how to hook
|
||||
it up.
|
||||
|
||||
NOTE that this also handles the case that the
|
||||
v NOTE that this also handles the case that the
|
||||
port is actually empty on the inside. We assume
|
||||
in that case that the port is input. */
|
||||
|
||||
@@ -1092,6 +1187,21 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||
continue;
|
||||
}
|
||||
|
||||
if (need_bufz_for_input_port(prts)) {
|
||||
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
|
||||
sig->vector_width());
|
||||
des->add_node(tmp);
|
||||
connect(tmp->pin(1), sig->pin(0));
|
||||
|
||||
NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, sig->vector_width());
|
||||
tmp2->local_flag(true);
|
||||
tmp2->set_line(*this);
|
||||
tmp2->data_type(sig->data_type());
|
||||
connect(tmp->pin(0), tmp2->pin(0));
|
||||
sig = tmp2;
|
||||
}
|
||||
|
||||
} else if (prts[0]->port_type() == NetNet::PINOUT) {
|
||||
|
||||
/* Inout to/from module. This is a more
|
||||
@@ -1103,8 +1213,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||
identifier elaborates to the same NetNet in
|
||||
both cases so the extra elaboration has no
|
||||
effect. But if the expression passed to the
|
||||
inout port is a part select, aspecial part
|
||||
select must be created that can paqss data in
|
||||
inout port is a part select, a special part
|
||||
select must be created that can pass data in
|
||||
both directions.
|
||||
|
||||
Use the elaborate_bi_net method to handle all
|
||||
@@ -1866,7 +1976,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
||||
if (nscope == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
"unable to find block scope " << scope_path(scope)
|
||||
<< "<" << pscope_name() << ">" << endl;
|
||||
<< "." << pscope_name() << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -2539,8 +2649,8 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
|
||||
}
|
||||
NexusSet*nset = enet->nex_input(rem_out);
|
||||
if (nset == 0) {
|
||||
cerr << get_fileline() << ": internal error: No NexusSet"
|
||||
<< " from statement." << endl;
|
||||
cerr << get_fileline() << ": error: Unable to elaborate:"
|
||||
<< endl;
|
||||
enet->dump(cerr, 6);
|
||||
des->errors += 1;
|
||||
return enet;
|
||||
@@ -2870,7 +2980,7 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
||||
dev = new NetForce(lval, rexp);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: ELaborate force,"
|
||||
cerr << get_fileline() << ": debug: Elaborate force,"
|
||||
<< " lval width=" << lval->lwidth()
|
||||
<< " rval width=" << rexp->expr_width()
|
||||
<< " rval=" << *rexp
|
||||
@@ -2969,7 +3079,7 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
||||
sig = des->find_signal(scope, id2->path());
|
||||
if (sig == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to find variable "
|
||||
<< id2->path() << " in for-loop increment expressin." << endl;
|
||||
<< id2->path() << " in for-loop increment expression." << endl;
|
||||
des->errors += 1;
|
||||
return body;
|
||||
}
|
||||
@@ -3470,6 +3580,34 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
|
||||
}
|
||||
|
||||
static void elaborate_functions(Design*des, NetScope*scope,
|
||||
const map<perm_string,PFunction*>&funcs)
|
||||
{
|
||||
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
|
||||
for (mfunc_it_t cur = funcs.begin()
|
||||
; cur != funcs.end() ; cur ++) {
|
||||
|
||||
hname_t use_name ( (*cur).first );
|
||||
NetScope*fscope = scope->child(use_name);
|
||||
assert(fscope);
|
||||
(*cur).second->elaborate(des, fscope);
|
||||
}
|
||||
}
|
||||
|
||||
static void elaborate_tasks(Design*des, NetScope*scope,
|
||||
const map<perm_string,PTask*>&tasks)
|
||||
{
|
||||
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
|
||||
for (mtask_it_t cur = tasks.begin()
|
||||
; cur != tasks.end() ; cur ++) {
|
||||
|
||||
hname_t use_name ( (*cur).first );
|
||||
NetScope*tscope = scope->child(use_name);
|
||||
assert(tscope);
|
||||
(*cur).second->elaborate(des, tscope);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When a module is instantiated, it creates the scope then uses this
|
||||
* method to elaborate the contents of the module.
|
||||
@@ -3529,28 +3667,12 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
// Elaborate functions.
|
||||
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
|
||||
for (mfunc_it_t cur = funcs_.begin()
|
||||
; cur != funcs_.end() ; cur ++) {
|
||||
|
||||
hname_t use_name ( (*cur).first );
|
||||
NetScope*fscope = scope->child(use_name);
|
||||
assert(fscope);
|
||||
(*cur).second->elaborate(des, fscope);
|
||||
}
|
||||
elaborate_functions(des, scope, funcs);
|
||||
|
||||
// Elaborate the task definitions. This is done before the
|
||||
// behaviors so that task calls may reference these, and after
|
||||
// the signals so that the tasks can reference them.
|
||||
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
|
||||
for (mtask_it_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++) {
|
||||
|
||||
hname_t use_name ( (*cur).first );
|
||||
NetScope*tscope = scope->child(use_name);
|
||||
assert(tscope);
|
||||
(*cur).second->elaborate(des, tscope);
|
||||
}
|
||||
elaborate_tasks(des, scope, tasks);
|
||||
|
||||
// Get all the gates of the module and elaborate them by
|
||||
// connecting them to the signals. The gate may be simple or
|
||||
@@ -3595,8 +3717,8 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
|
||||
<< scope_path(container) << "." << endl;
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generates.begin()
|
||||
; cur != generates.end() ; cur ++) {
|
||||
for (generate_it_t cur = generate_schemes.begin()
|
||||
; cur != generate_schemes.end() ; cur ++) {
|
||||
PGenerate*item = *cur;
|
||||
if (! item->scope_list_.empty()) {
|
||||
flag &= item->elaborate(des, container);
|
||||
@@ -3638,6 +3760,9 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
|
||||
|
||||
bool PGenerate::elaborate_(Design*des, NetScope*scope) const
|
||||
{
|
||||
elaborate_functions(des, scope, funcs);
|
||||
elaborate_tasks(des, scope, tasks);
|
||||
|
||||
typedef list<PGate*>::const_iterator gates_it_t;
|
||||
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; cur ++ )
|
||||
(*cur)->elaborate(des, scope);
|
||||
@@ -3647,8 +3772,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
|
||||
(*cur)->elaborate(des, scope);
|
||||
|
||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
||||
for (generate_it_t cur = generates.begin()
|
||||
; cur != generates.end() ; cur ++ ) {
|
||||
for (generate_it_t cur = generate_schemes.begin()
|
||||
; cur != generate_schemes.end() ; cur ++ ) {
|
||||
(*cur)->elaborate(des, scope);
|
||||
}
|
||||
|
||||
@@ -3676,6 +3801,82 @@ struct root_elem {
|
||||
NetScope *scope;
|
||||
};
|
||||
|
||||
class elaborate_root_scope_t : public elaborator_work_item_t {
|
||||
public:
|
||||
elaborate_root_scope_t(Design*des, NetScope*scope, Module*rmod)
|
||||
: elaborator_work_item_t(des), scope_(scope), rmod_(rmod)
|
||||
{ }
|
||||
|
||||
~elaborate_root_scope_t() { }
|
||||
|
||||
virtual void elaborate_runrun()
|
||||
{
|
||||
Module::replace_t stub;
|
||||
if (! rmod_->elaborate_scope(des, scope_, stub))
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
private:
|
||||
NetScope*scope_;
|
||||
Module*rmod_;
|
||||
};
|
||||
|
||||
class top_defparams : public elaborator_work_item_t {
|
||||
public:
|
||||
top_defparams(Design*des)
|
||||
: elaborator_work_item_t(des)
|
||||
{ }
|
||||
|
||||
~top_defparams() { }
|
||||
|
||||
virtual void elaborate_runrun()
|
||||
{
|
||||
// This method recurses through the scopes, looking for
|
||||
// defparam assignments to apply to the parameters in the
|
||||
// various scopes. This needs to be done after all the scopes
|
||||
// and basic parameters are taken care of because the defparam
|
||||
// can assign to a parameter declared *after* it.
|
||||
des->run_defparams();
|
||||
|
||||
// At this point, all parameter overrides are done. Scan the
|
||||
// scopes and evaluate the parameters all the way down to
|
||||
// constants.
|
||||
des->evaluate_parameters();
|
||||
}
|
||||
};
|
||||
|
||||
class later_defparams : public elaborator_work_item_t {
|
||||
public:
|
||||
later_defparams(Design*des)
|
||||
: elaborator_work_item_t(des)
|
||||
{ }
|
||||
|
||||
~later_defparams() { }
|
||||
|
||||
virtual void elaborate_runrun()
|
||||
{
|
||||
list<NetScope*>tmp_list;
|
||||
for (set<NetScope*>::iterator cur = des->defparams_later.begin()
|
||||
; cur != des->defparams_later.end() ; cur ++ )
|
||||
tmp_list.push_back(*cur);
|
||||
|
||||
des->defparams_later.clear();
|
||||
|
||||
while (! tmp_list.empty()) {
|
||||
NetScope*cur = tmp_list.front();
|
||||
tmp_list.pop_front();
|
||||
cur->run_defparams_later(des);
|
||||
}
|
||||
des->evaluate_parameters();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* This function is the root of all elaboration. The input is the list
|
||||
* of root module names. The function locates the Module definitions
|
||||
* for each root, does the whole elaboration sequence, and fills in
|
||||
* the resulting Design.
|
||||
*/
|
||||
Design* elaborate(list<perm_string>roots)
|
||||
{
|
||||
svector<root_elem*> root_elems(roots.size());
|
||||
@@ -3686,7 +3887,7 @@ Design* elaborate(list<perm_string>roots)
|
||||
// module and elaborate what I find.
|
||||
Design*des = new Design;
|
||||
|
||||
// Scan the root modules, and elaborate their scopes.
|
||||
// Scan the root modules by name, and elaborate their scopes.
|
||||
for (list<perm_string>::const_iterator root = roots.begin()
|
||||
; root != roots.end()
|
||||
; root++) {
|
||||
@@ -3705,47 +3906,74 @@ Design* elaborate(list<perm_string>roots)
|
||||
// Get the module definition for this root instance.
|
||||
Module *rmod = (*mod).second;
|
||||
|
||||
// Make the root scope.
|
||||
// Make the root scope. This makes a NetScoep object and
|
||||
// pushes it into the list of root scopes in the Design.
|
||||
NetScope*scope = des->make_root_scope(*root);
|
||||
|
||||
// Collect some basic properties of this scope from the
|
||||
// Module definition.
|
||||
scope->set_line(rmod);
|
||||
scope->time_unit(rmod->time_unit);
|
||||
scope->time_precision(rmod->time_precision);
|
||||
scope->default_nettype(rmod->default_nettype);
|
||||
des->set_precision(rmod->time_precision);
|
||||
|
||||
Module::replace_t stub;
|
||||
|
||||
// Recursively elaborate from this root scope down. This
|
||||
// does a lot of the grunt work of creating sub-scopes, etc.
|
||||
if (! rmod->elaborate_scope(des, scope, stub)) {
|
||||
delete des;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Save this scope, along with its defintion, in the
|
||||
// "root_elems" list for later passes.
|
||||
struct root_elem *r = new struct root_elem;
|
||||
r->mod = rmod;
|
||||
r->scope = scope;
|
||||
root_elems[i++] = r;
|
||||
|
||||
// Arrange for these scopes to be elaborated as root
|
||||
// scopes. Create an "elaborate_root_scope" object to
|
||||
// contain the work item, and append it to the scope
|
||||
// elaborations work list.
|
||||
elaborator_work_item_t*es = new elaborate_root_scope_t(des, scope, rmod);
|
||||
des->elaboration_work_list.push_back(es);
|
||||
}
|
||||
|
||||
// After the work items for the root scope elaboration, push a
|
||||
// work item to process the defparams.
|
||||
des->elaboration_work_list.push_back(new top_defparams(des));
|
||||
|
||||
// Run the work list of scope elaborations until the list is
|
||||
// empty. This list is initially populated above where the
|
||||
// initial root scopes are primed.
|
||||
while (! des->elaboration_work_list.empty()) {
|
||||
// Transfer the queue to a temporary queue.
|
||||
list<elaborator_work_item_t*> cur_queue;
|
||||
while (! des->elaboration_work_list.empty()) {
|
||||
cur_queue.push_back(des->elaboration_work_list.front());
|
||||
des->elaboration_work_list.pop_front();
|
||||
}
|
||||
|
||||
// Run from the temporary queue. If the temporary queue
|
||||
// items create new work queue items, they will show up
|
||||
// in the elaboration_work_list and then we get to run
|
||||
// through them in the next pass.
|
||||
while (! cur_queue.empty()) {
|
||||
elaborator_work_item_t*tmp = cur_queue.front();
|
||||
cur_queue.pop_front();
|
||||
tmp->elaborate_runrun();
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
if (! des->elaboration_work_list.empty()) {
|
||||
des->elaboration_work_list.push_back(new later_defparams(des));
|
||||
}
|
||||
}
|
||||
|
||||
// Look for residual defparams (that point to a non-existent
|
||||
// scope) and clean them out.
|
||||
des->residual_defparams();
|
||||
|
||||
// Errors already? Probably missing root modules. Just give up
|
||||
// now and return nothing.
|
||||
if (des->errors > 0)
|
||||
return des;
|
||||
|
||||
// This method recurses through the scopes, looking for
|
||||
// defparam assignments to apply to the parameters in the
|
||||
// various scopes. This needs to be done after all the scopes
|
||||
// and basic parameters are taken care of because the defparam
|
||||
// can assign to a parameter declared *after* it.
|
||||
des->run_defparams();
|
||||
|
||||
|
||||
// At this point, all parameter overrides are done. Scan the
|
||||
// scopes and evaluate the parameters all the way down to
|
||||
// constants.
|
||||
des->evaluate_parameters();
|
||||
|
||||
// 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
|
||||
|
||||
@@ -72,6 +72,16 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetCastInt::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->lpm_cast_int(this);
|
||||
}
|
||||
|
||||
bool NetCastReal::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->lpm_cast_real(this);
|
||||
}
|
||||
|
||||
bool NetCLShift::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_clshift(this);
|
||||
@@ -165,6 +175,11 @@ bool NetUserFunc::emit_node(struct target_t*tgt) const
|
||||
return tgt->net_function(this);
|
||||
}
|
||||
|
||||
bool NetTran::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->tran(this);
|
||||
}
|
||||
|
||||
bool NetBUFZ::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->bufz(this);
|
||||
@@ -357,7 +372,7 @@ void NetScope::emit_scope(struct target_t*tgt) const
|
||||
/* Run the signals again, but this time to connect the
|
||||
delay paths. This is done as a second pass because
|
||||
the paths reference other signals that may be later
|
||||
in the list. We can do it here becase delay paths are
|
||||
in the list. We can do it here because delay paths are
|
||||
always connected within the scope. */
|
||||
cur = signals_->sig_next_;
|
||||
do {
|
||||
|
||||
+12
-20
@@ -1171,17 +1171,9 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
}
|
||||
|
||||
assert(scope_);
|
||||
const NetExpr*expr_msb;
|
||||
const NetExpr*expr_lsb;
|
||||
const NetExpr*expr = scope_->get_parameter(name_, expr_msb, expr_lsb);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": internal error: Unable to match "
|
||||
<< "parameter " << name_ << " in scope "
|
||||
<< scope_path(scope_) << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(expr);
|
||||
perm_string name = (*reference_).first;
|
||||
const NetExpr*expr = (*reference_).second.expr;
|
||||
ivl_assert(*this, expr);
|
||||
|
||||
NetExpr*nexpr = expr->dup_expr();
|
||||
assert(nexpr);
|
||||
@@ -1190,7 +1182,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
// return the constant value.
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
|
||||
verinum val = tmp->value();
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||
ptmp->set_line(*this);
|
||||
delete nexpr;
|
||||
return ptmp;
|
||||
@@ -1198,7 +1190,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
|
||||
verireal val = tmp->value();
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||
ptmp->set_line(*this);
|
||||
delete nexpr;
|
||||
return ptmp;
|
||||
@@ -1209,7 +1201,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
NetExpr*res = nexpr->eval_tree();
|
||||
if (res == 0) {
|
||||
cerr << get_fileline() << ": internal error: Unable to evaluate "
|
||||
<< "parameter " << name_ << " expression: "
|
||||
<< "parameter " << name << " expression: "
|
||||
<< *nexpr << endl;
|
||||
delete nexpr;
|
||||
return 0;
|
||||
@@ -1217,10 +1209,10 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
// The result can be saved as the value of the parameter for
|
||||
// future reference, and return a copy to the caller.
|
||||
bool flag = scope_->replace_parameter(name_, res);
|
||||
bool flag = scope_->replace_parameter(name, res);
|
||||
if (!flag) {
|
||||
cerr << get_fileline() << ": internal error: Could not "
|
||||
<< "replace parameter expression for " << name_ << endl;
|
||||
<< "replace parameter expression for " << name << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1234,7 +1226,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
{ NetEConst*tmp = dynamic_cast<NetEConst*>(res);
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: parameter "
|
||||
<< name_ << " evaluates to incomprehensible "
|
||||
<< name << " evaluates to incomprehensible "
|
||||
<< *res << "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1242,7 +1234,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
assert(tmp);
|
||||
|
||||
verinum val = tmp->value();
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||
|
||||
return ptmp;
|
||||
}
|
||||
@@ -1251,7 +1243,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
{ NetECReal*tmp = dynamic_cast<NetECReal*>(res);
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: parameter "
|
||||
<< name_ << " evaluates to incomprehensible "
|
||||
<< name << " evaluates to incomprehensible "
|
||||
<< *res << "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1259,7 +1251,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
assert(tmp);
|
||||
|
||||
verireal val = tmp->value();
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||
|
||||
return ptmp;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
*
|
||||
* The POST_MAP compiler directive causes the GSR manipulations
|
||||
* included in the test bench to be compiled in, to simulate the chip
|
||||
* startup. Other then that, the test bench runs the post-map design
|
||||
* startup. Other than that, the test bench runs the post-map design
|
||||
* the same way the pre-synthesis design works.
|
||||
*
|
||||
* Run this design with the command:
|
||||
|
||||
+1
-1
@@ -459,7 +459,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
|
||||
|
||||
default: {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "NetEBDiv has unexpeced op() code: "
|
||||
<< "NetEBDiv has unexpected op() code: "
|
||||
<< op() << endl;
|
||||
des->errors += 1;
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ ivl_file_table_index
|
||||
ivl_file_table_item
|
||||
ivl_file_table_size
|
||||
|
||||
ivl_island_flag_set
|
||||
ivl_island_flag_test
|
||||
|
||||
ivl_logic_attr
|
||||
ivl_logic_attr_cnt
|
||||
ivl_logic_attr_val
|
||||
@@ -115,6 +118,7 @@ ivl_nexus_ptr_pin
|
||||
ivl_nexus_ptr_lpm
|
||||
ivl_nexus_ptr_log
|
||||
ivl_nexus_ptr_sig
|
||||
ivl_nexus_ptr_switch
|
||||
|
||||
ivl_parameter_basename
|
||||
ivl_parameter_expr
|
||||
@@ -152,6 +156,8 @@ ivl_scope_port
|
||||
ivl_scope_ports
|
||||
ivl_scope_sigs
|
||||
ivl_scope_sig
|
||||
ivl_scope_switch
|
||||
ivl_scope_switches
|
||||
ivl_scope_time_precision
|
||||
ivl_scope_time_units
|
||||
ivl_scope_type
|
||||
@@ -185,6 +191,8 @@ ivl_path_source
|
||||
|
||||
ivl_process_attr_cnt
|
||||
ivl_process_attr_val
|
||||
ivl_process_file
|
||||
ivl_process_lineno
|
||||
ivl_process_scope
|
||||
ivl_process_stmt
|
||||
ivl_process_type
|
||||
@@ -216,6 +224,19 @@ ivl_stmt_parm_count
|
||||
ivl_stmt_rval
|
||||
ivl_stmt_sub_stmt
|
||||
|
||||
ivl_switch_a
|
||||
ivl_switch_b
|
||||
ivl_switch_basename
|
||||
ivl_switch_enable
|
||||
ivl_switch_file
|
||||
ivl_switch_island
|
||||
ivl_switch_lineno
|
||||
ivl_switch_offset
|
||||
ivl_switch_part
|
||||
ivl_switch_scope
|
||||
ivl_switch_type
|
||||
ivl_switch_width
|
||||
|
||||
ivl_udp_init
|
||||
ivl_udp_name
|
||||
ivl_udp_nin
|
||||
|
||||
+89
-1
@@ -80,6 +80,13 @@ _BEGIN_DECL
|
||||
* processes. Structural expressions are instead treated as logic
|
||||
* gates.
|
||||
*
|
||||
* ivl_island_t
|
||||
* Certain types of objects may belong to islands. The island that
|
||||
* they belong to is represented by the ivl_island_t cookie. To
|
||||
* know if object belong to the same island, it is sufficient to
|
||||
* compare island cookies. If a==b, then island a is the same as
|
||||
* island b.
|
||||
*
|
||||
* ivl_lpm_t
|
||||
* This object is the base class for all the various LPM type
|
||||
* device nodes. This object carries a few base properties
|
||||
@@ -123,6 +130,9 @@ _BEGIN_DECL
|
||||
* ivl_process_t object holds one of these, but a statement may in
|
||||
* turn contain other statements.
|
||||
*
|
||||
* ivl_switch_t
|
||||
* Switches are the tran/tranif devices in the design.
|
||||
*
|
||||
* -- A Note About Bit Sets --
|
||||
* Some objects hold a value as an array of bits. In these cases there
|
||||
* is some method that retrieves the width of the value and another
|
||||
@@ -143,6 +153,7 @@ typedef struct ivl_delaypath_s*ivl_delaypath_t;
|
||||
typedef struct ivl_design_s *ivl_design_t;
|
||||
typedef struct ivl_event_s *ivl_event_t;
|
||||
typedef struct ivl_expr_s *ivl_expr_t;
|
||||
typedef struct ivl_island_s *ivl_island_t;
|
||||
typedef struct ivl_lpm_s *ivl_lpm_t;
|
||||
typedef struct ivl_lval_s *ivl_lval_t;
|
||||
typedef struct ivl_net_const_s*ivl_net_const_t;
|
||||
@@ -155,6 +166,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
|
||||
typedef struct ivl_process_s *ivl_process_t;
|
||||
typedef struct ivl_scope_s *ivl_scope_t;
|
||||
typedef struct ivl_signal_s *ivl_signal_t;
|
||||
typedef struct ivl_switch_s *ivl_switch_t;
|
||||
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
|
||||
typedef struct ivl_statement_s*ivl_statement_t;
|
||||
|
||||
@@ -226,11 +238,24 @@ typedef enum ivl_logic_e {
|
||||
IVL_LO_UDP = 21
|
||||
} ivl_logic_t;
|
||||
|
||||
/* This is the type of a ivl_switch_t object */
|
||||
typedef enum ivl_switch_type_e {
|
||||
IVL_SW_TRAN = 0,
|
||||
IVL_SW_TRANIF0 = 1,
|
||||
IVL_SW_TRANIF1 = 2,
|
||||
IVL_SW_RTRAN = 3,
|
||||
IVL_SW_RTRANIF0 = 4,
|
||||
IVL_SW_RTRANIF1 = 5,
|
||||
IVL_SW_TRAN_VP = 6
|
||||
} ivl_switch_type_t;
|
||||
|
||||
/* This is the type of an LPM object. */
|
||||
typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_ABS = 32,
|
||||
IVL_LPM_ADD = 0,
|
||||
IVL_LPM_ARRAY = 30,
|
||||
IVL_LPM_CAST_INT = 34,
|
||||
IVL_LPM_CAST_REAL = 33,
|
||||
IVL_LPM_CONCAT = 16,
|
||||
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
|
||||
IVL_LPM_CMP_EQ = 10,
|
||||
@@ -243,7 +268,7 @@ typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_MOD = 13,
|
||||
IVL_LPM_MULT = 4,
|
||||
IVL_LPM_MUX = 5,
|
||||
IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
|
||||
/* IVL_LPM_PART_BI= 28, / obsolete */
|
||||
IVL_LPM_PART_VP= 15, /* part select: vector to part */
|
||||
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
|
||||
IVL_LPM_POW = 31,
|
||||
@@ -699,6 +724,16 @@ extern unsigned ivl_file_table_index(const char *);
|
||||
extern unsigned ivl_file_table_size(void);
|
||||
|
||||
|
||||
/* ISLAND
|
||||
*
|
||||
* ivl_island_flag_set
|
||||
* ivl_island_flag_test
|
||||
* Allow the user to test or set a boolean flag associated with the
|
||||
* island.
|
||||
*/
|
||||
extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value);
|
||||
extern int ivl_island_flag_test(ivl_island_t net, unsigned flag);
|
||||
|
||||
/* LOGIC
|
||||
* These types and functions support manipulation of logic gates. The
|
||||
* ivl_logic_t enumeration identifies the various kinds of gates that
|
||||
@@ -1313,6 +1348,7 @@ extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net);
|
||||
extern ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net);
|
||||
extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net);
|
||||
extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net);
|
||||
extern ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net);
|
||||
extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
|
||||
|
||||
/* PARAMETER
|
||||
@@ -1501,6 +1537,8 @@ extern unsigned ivl_scope_ports(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_sigs(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_switches(ivl_scope_t net);
|
||||
extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx);
|
||||
extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net);
|
||||
extern const char* ivl_scope_tname(ivl_scope_t net);
|
||||
extern int ivl_scope_time_precision(ivl_scope_t net);
|
||||
@@ -1657,6 +1695,9 @@ extern ivl_statement_t ivl_process_stmt(ivl_process_t net);
|
||||
extern unsigned ivl_process_attr_cnt(ivl_process_t net);
|
||||
extern ivl_attribute_t ivl_process_attr_val(ivl_process_t net, unsigned idx);
|
||||
|
||||
extern const char* ivl_process_file(ivl_process_t net);
|
||||
extern unsigned ivl_process_lineno(ivl_process_t net);
|
||||
|
||||
/*
|
||||
* These functions manage statements of various type. This includes
|
||||
* all the different kinds of statements (as enumerated in
|
||||
@@ -1826,6 +1867,53 @@ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
|
||||
IVL_ST_WAIT, IVL_ST_WHILE */
|
||||
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
|
||||
|
||||
/* SWITCHES
|
||||
*
|
||||
* The switches represent the tran devices in the design.
|
||||
*
|
||||
* FUNCTION SUMMARY
|
||||
*
|
||||
* ivl_switch_type
|
||||
* Return the enumerated value that is the type of the switch.
|
||||
*
|
||||
* ivl_switch_basename
|
||||
* This is the name given to the device in the source code.
|
||||
*
|
||||
* ivl_switch_a
|
||||
* ivl_switch_b
|
||||
* The a and b ports are the two ports of the switch.
|
||||
*
|
||||
* ivl_switch_enable
|
||||
* If the device has an enable (tranifX) then this is the enable
|
||||
* port.
|
||||
*
|
||||
* SEMANTIC NOTES
|
||||
* The a/b ports can be any type, but the types must exactly
|
||||
* match, including vector widths. The enable must be a scalar.
|
||||
*
|
||||
* The IVL_SW_TRAN_VP is an exception to the above. In this case,
|
||||
* the B side may be a different size, and the a side will have a
|
||||
* a fixed width. The unused bits are padded to Z on the A side.
|
||||
*/
|
||||
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
|
||||
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
|
||||
extern const char*ivl_switch_basename(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_a(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
|
||||
extern ivl_island_t ivl_switch_island(ivl_switch_t net);
|
||||
|
||||
/* These are only support for IVL_SW_TRAN_VP switches. */
|
||||
extern unsigned ivl_switch_width(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_part(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_offset(ivl_switch_t net);
|
||||
|
||||
/* Not implemented yet
|
||||
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
|
||||
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
|
||||
*** */
|
||||
extern const char* ivl_switch_file(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_lineno(ivl_switch_t net);
|
||||
|
||||
#if defined(__MINGW32__) || defined (__CYGWIN32__)
|
||||
# define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef __ivl_target_priv_H
|
||||
#define __ivl_target_H
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include <inttypes.h>
|
||||
|
||||
/*
|
||||
* This deader has declarations related to the ivl_target.h API that
|
||||
* are not to be exported outside of the core via the ivl_target.h
|
||||
* interface.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information about islands. Connected branches within a net are
|
||||
* collected into islands. Branches that are purely ddiscrete do not
|
||||
* have disciplines and do not belong to islands.
|
||||
*/
|
||||
|
||||
class discipline_t;
|
||||
|
||||
struct ivl_island_s {
|
||||
discipline_t*discipline;
|
||||
// user accessible flags. They are initially false, always.
|
||||
vector<bool> flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
+15
-6
@@ -115,7 +115,7 @@ static void ifdef_enter(void)
|
||||
struct ifdef_stack_t*cur;
|
||||
|
||||
cur = (struct ifdef_stack_t*) calloc(1, sizeof(struct ifdef_stack_t));
|
||||
cur->path = strdup(istack->path);
|
||||
if (istack->path) cur->path = strdup(istack->path);
|
||||
cur->lineno = istack->lineno;
|
||||
cur->next = ifdef_stack;
|
||||
|
||||
@@ -131,8 +131,10 @@ static void ifdef_leave(void)
|
||||
cur = ifdef_stack;
|
||||
ifdef_stack = cur->next;
|
||||
|
||||
if (strcmp(istack->path,cur->path) != 0)
|
||||
{
|
||||
/* If either path is from a non-file context e.g.(macro expansion)
|
||||
* we assume that the non-file part is from this file. */
|
||||
if (istack->path != NULL && cur->path != NULL &&
|
||||
strcmp(istack->path,cur->path) != 0) {
|
||||
fprintf
|
||||
(
|
||||
stderr,
|
||||
@@ -856,6 +858,7 @@ static int define_continue_flag = 0;
|
||||
static char *find_arg(char*ptr, char*head, char*arg)
|
||||
{
|
||||
char *cp = ptr;
|
||||
size_t len = strlen(arg);
|
||||
|
||||
while (1) {
|
||||
/* Look for a candidate match, just return if none is found. */
|
||||
@@ -866,7 +869,8 @@ static char *find_arg(char*ptr, char*head, char*arg)
|
||||
* match is not in the middle of another identifier.
|
||||
*/
|
||||
if (cp != head &&
|
||||
(isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$')) {
|
||||
(isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$' ||
|
||||
isalnum(*(cp+len)) || *(cp+len) == '_' || *(cp+len) == '$')) {
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
@@ -941,7 +945,7 @@ static void do_define()
|
||||
}
|
||||
|
||||
/* Detect the continuation sequence. If I find it, remove it
|
||||
* and the white space that preceeds it, then replace all that
|
||||
* and the white space that precedes it, then replace all that
|
||||
* with a single newline.
|
||||
*/
|
||||
if ((cp > yytext) && (cp[-1] == '\\'))
|
||||
@@ -1468,7 +1472,7 @@ static void do_include()
|
||||
fprintf(depend_file, "%s\n", standby->path);
|
||||
|
||||
if (line_direct_flag)
|
||||
fprintf(yyout, "\n`line %u \"%s\" 1\n", istack->lineno+1, standby->path);
|
||||
fprintf(yyout, "\n`line 1 \"%s\" 1\n", standby->path);
|
||||
|
||||
standby->next = istack;
|
||||
standby->stringify_flag = 0;
|
||||
@@ -1616,7 +1620,11 @@ static int load_next_input()
|
||||
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
|
||||
{
|
||||
if (!table->keyword)
|
||||
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||
fprintf(out, "%s:%d:%d:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#else
|
||||
fprintf(out, "%s:%d:%zd:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#endif
|
||||
|
||||
if (table->left)
|
||||
do_dump_precompiled_defines(out, table->left);
|
||||
@@ -1741,6 +1749,7 @@ void reset_lexor(FILE* out, char* paths[])
|
||||
isp->ebs = 0;
|
||||
isp->next = 0;
|
||||
isp->lineno = 0;
|
||||
isp->stringify_flag = 0;
|
||||
|
||||
if (tail)
|
||||
tail->next = isp;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
# include <ctype.h>
|
||||
# include <string.h>
|
||||
# include "lexor_keyword.h"
|
||||
# include "discipline.h"
|
||||
# include <list>
|
||||
|
||||
# define YY_USER_INIT reset_lexor();
|
||||
@@ -152,6 +153,7 @@ S [afpnumkKMGT]
|
||||
"->" { return K_TRIGGER; }
|
||||
"+:" { return K_PO_POS; }
|
||||
"-:" { return K_PO_NEG; }
|
||||
"<+" { return K_CONTRIBUTE; }
|
||||
|
||||
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
|
||||
and ")", but since I know that this is really ( * ), replace it
|
||||
@@ -230,6 +232,18 @@ S [afpnumkKMGT]
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this identifier names a discipline, then return this as
|
||||
a DISCIPLINE_IDENTIFIER and return the discipline as the
|
||||
value instead. */
|
||||
if (rc == IDENTIFIER && gn_verilog_ams_flag) {
|
||||
perm_string tmp = lex_strings.make(yylval.text);
|
||||
map<perm_string,discipline_t*>::iterator cur = disciplines.find(tmp);
|
||||
if (cur != disciplines.end()) {
|
||||
yylval.discipline = (*cur).second;
|
||||
rc = DISCIPLINE_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -829,7 +843,7 @@ static verinum*make_unsized_dec(const char*ptr)
|
||||
if (ptr[0] == '\'') {
|
||||
/* The number has decorations of the form 'sd<digits>,
|
||||
possibly with space between the d and the <digits>.
|
||||
Also, the 's' is optional, and markes the number as
|
||||
Also, the 's' is optional, and marks the number as
|
||||
signed. */
|
||||
ptr += 1;
|
||||
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
struct lexor_keyword { const char*name; int mask; int tokenType; };
|
||||
%%
|
||||
abs, GN_KEYWORDS_VAMS_2_3, K_abs
|
||||
abstol, GN_KEYWORDS_VAMS_2_3, K_abstol
|
||||
access, GN_KEYWORDS_VAMS_2_3, K_access
|
||||
acos, GN_KEYWORDS_VAMS_2_3, K_acos
|
||||
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
|
||||
always, GN_KEYWORDS_1364_1995, K_always
|
||||
analog, GN_KEYWORDS_VAMS_2_3, K_analog
|
||||
and, GN_KEYWORDS_1364_1995, K_and
|
||||
asin, GN_KEYWORDS_VAMS_2_3, K_asin
|
||||
asinh, GN_KEYWORDS_VAMS_2_3, K_asinh
|
||||
@@ -22,6 +25,7 @@ assign, GN_KEYWORDS_1364_1995, K_assign
|
||||
atan, GN_KEYWORDS_VAMS_2_3, K_atan
|
||||
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
|
||||
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
|
||||
automatic, GN_KEYWORDS_1364_2001, K_automatic
|
||||
begin, GN_KEYWORDS_1364_1995, K_begin
|
||||
bool, GN_KEYWORDS_ICARUS, K_bool
|
||||
buf, GN_KEYWORDS_1364_1995, K_buf
|
||||
@@ -32,38 +36,51 @@ casex, GN_KEYWORDS_1364_1995, K_casex
|
||||
casez, GN_KEYWORDS_1364_1995, K_casez
|
||||
ceil, GN_KEYWORDS_VAMS_2_3, K_ceil
|
||||
cmos, GN_KEYWORDS_1364_1995, K_cmos
|
||||
continuous, GN_KEYWORDS_VAMS_2_3, K_continuous
|
||||
cos, GN_KEYWORDS_VAMS_2_3, K_cos
|
||||
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
|
||||
ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature
|
||||
deassign, GN_KEYWORDS_1364_1995, K_deassign
|
||||
default, GN_KEYWORDS_1364_1995, K_default
|
||||
defparam, GN_KEYWORDS_1364_1995, K_defparam
|
||||
disable, GN_KEYWORDS_1364_1995, K_disable
|
||||
discipline, GN_KEYWORDS_VAMS_2_3, K_discipline
|
||||
discrete, GN_KEYWORDS_VAMS_2_3, K_discrete
|
||||
domain, GN_KEYWORDS_VAMS_2_3, K_domain
|
||||
edge, GN_KEYWORDS_1364_1995, K_edge
|
||||
else, GN_KEYWORDS_1364_1995, K_else
|
||||
end, GN_KEYWORDS_1364_1995, K_end
|
||||
endcase, GN_KEYWORDS_1364_1995, K_endcase
|
||||
enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline
|
||||
endfunction, GN_KEYWORDS_1364_1995, K_endfunction
|
||||
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate
|
||||
endmodule, GN_KEYWORDS_1364_1995, K_endmodule
|
||||
endnature, GN_KEYWORDS_VAMS_2_3, K_endnature
|
||||
endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive
|
||||
endspecify, GN_KEYWORDS_1364_1995, K_endspecify
|
||||
endtable, GN_KEYWORDS_1364_1995, K_endtable
|
||||
endtask, GN_KEYWORDS_1364_1995, K_endtask
|
||||
event, GN_KEYWORDS_1364_1995, K_event
|
||||
exclude, GN_KEYWORDS_VAMS_2_3, K_exclude
|
||||
exp, GN_KEYWORDS_VAMS_2_3, K_exp
|
||||
floor, GN_KEYWORDS_VAMS_2_3, K_floor
|
||||
flow, GN_KEYWORDS_VAMS_2_3, K_flow
|
||||
for, GN_KEYWORDS_1364_1995, K_for
|
||||
force, GN_KEYWORDS_1364_1995, K_force
|
||||
forever, GN_KEYWORDS_1364_1995, K_forever
|
||||
fork, GN_KEYWORDS_1364_1995, K_fork
|
||||
from, GN_KEYWORDS_VAMS_2_3, K_from
|
||||
function, GN_KEYWORDS_1364_1995, K_function
|
||||
generate, GN_KEYWORDS_1364_2001, K_generate
|
||||
genvar, GN_KEYWORDS_1364_2001, K_genvar
|
||||
ground, GN_KEYWORDS_VAMS_2_3, K_ground
|
||||
highz0, GN_KEYWORDS_1364_1995, K_highz0
|
||||
highz1, GN_KEYWORDS_1364_1995, K_highz1
|
||||
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
|
||||
idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature
|
||||
if, GN_KEYWORDS_1364_1995, K_if
|
||||
ifnone, GN_KEYWORDS_1364_1995, K_ifnone
|
||||
inf, GN_KEYWORDS_VAMS_2_3, K_inf
|
||||
initial, GN_KEYWORDS_1364_1995, K_initial
|
||||
inout, GN_KEYWORDS_1364_1995, K_inout
|
||||
input, GN_KEYWORDS_1364_1995, K_input
|
||||
@@ -80,6 +97,7 @@ medium, GN_KEYWORDS_1364_1995, K_medium
|
||||
min, GN_KEYWORDS_VAMS_2_3, K_min
|
||||
module, GN_KEYWORDS_1364_1995, K_module
|
||||
nand, GN_KEYWORDS_1364_1995, K_nand
|
||||
nature, GN_KEYWORDS_VAMS_2_3, K_nature
|
||||
negedge, GN_KEYWORDS_1364_1995, K_negedge
|
||||
nmos, GN_KEYWORDS_1364_1995, K_nmos
|
||||
nor, GN_KEYWORDS_1364_1995, K_nor
|
||||
@@ -91,6 +109,7 @@ output, GN_KEYWORDS_1364_1995, K_output
|
||||
parameter, GN_KEYWORDS_1364_1995, K_parameter
|
||||
pmos, GN_KEYWORDS_1364_1995, K_pmos
|
||||
posedge, GN_KEYWORDS_1364_1995, K_posedge
|
||||
potential, GN_KEYWORDS_VAMS_2_3, K_potential
|
||||
pow, GN_KEYWORDS_VAMS_2_3, K_pow
|
||||
primitive, GN_KEYWORDS_1364_1995, K_primitive
|
||||
pull0, GN_KEYWORDS_1364_1995, K_pull0
|
||||
@@ -116,6 +135,7 @@ small, GN_KEYWORDS_1364_1995, K_small
|
||||
specify, GN_KEYWORDS_1364_1995, K_specify
|
||||
specparam, GN_KEYWORDS_1364_1995, K_specparam
|
||||
sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt
|
||||
string, GN_KEYWORDS_VAMS_2_3, K_string
|
||||
strong0, GN_KEYWORDS_1364_1995, K_strong0
|
||||
strong1, GN_KEYWORDS_1364_1995, K_strong1
|
||||
supply0, GN_KEYWORDS_1364_1995, K_supply0
|
||||
@@ -134,6 +154,7 @@ tri1, GN_KEYWORDS_1364_1995, K_tri1
|
||||
triand, GN_KEYWORDS_1364_1995, K_triand
|
||||
trior, GN_KEYWORDS_1364_1995, K_trior
|
||||
trireg, GN_KEYWORDS_1364_1995, K_trireg
|
||||
units, GN_KEYWORDS_VAMS_2_3, K_units
|
||||
vectored, GN_KEYWORDS_1364_1995, K_vectored
|
||||
wait, GN_KEYWORDS_1364_1995, K_wait
|
||||
wand, GN_KEYWORDS_1364_1995, K_wand
|
||||
|
||||
@@ -54,9 +54,11 @@ const char NOTICE[] =
|
||||
#endif
|
||||
# include "pform.h"
|
||||
# include "parse_api.h"
|
||||
# include "PGenerate.h"
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
# include "compiler.h"
|
||||
# include "discipline.h"
|
||||
|
||||
#if defined(__MINGW32__) && !defined(HAVE_GETOPT_H)
|
||||
extern "C" int getopt(int argc, char*argv[], const char*fmt);
|
||||
@@ -123,6 +125,8 @@ bool debug_scopes = false;
|
||||
bool debug_eval_tree = false;
|
||||
bool debug_elaborate = false;
|
||||
bool debug_synth2 = false;
|
||||
bool debug_optimizer = false;
|
||||
|
||||
/*
|
||||
* Verbose messages enabled.
|
||||
*/
|
||||
@@ -269,6 +273,9 @@ static void parm_to_flagmap(const string&flag)
|
||||
flags[key] = value;
|
||||
}
|
||||
|
||||
static void find_module_mention(map<perm_string,bool>&check_map, Module*m);
|
||||
static void find_module_mention(map<perm_string,bool>&check_map, PGenerate*s);
|
||||
|
||||
/*
|
||||
* Read the contents of a config file. This file is a temporary
|
||||
* configuration file made by the compiler driver to carry the bulky
|
||||
@@ -390,6 +397,9 @@ static void read_iconfig_file(const char*ipath)
|
||||
} else if (strcmp(cp,"synth2") == 0) {
|
||||
debug_synth2 = true;
|
||||
cerr << "debug: Enable synth2 debug" << endl;
|
||||
} else if (strcmp(cp,"optimizer") == 0) {
|
||||
debug_optimizer = true;
|
||||
cerr << "debug: Enable optimizer debug" << endl;
|
||||
} else {
|
||||
}
|
||||
|
||||
@@ -683,6 +693,16 @@ int main(int argc, char*argv[])
|
||||
|
||||
if (pf_path) {
|
||||
ofstream out (pf_path);
|
||||
out << "PFORM DUMP NATURES:" << endl;
|
||||
for (map<perm_string,nature_t*>::iterator cur = natures.begin()
|
||||
; cur != natures.end() ; cur ++ ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP DISCIPLINES:" << endl;
|
||||
for (map<perm_string,discipline_t*>::iterator cur = disciplines.begin()
|
||||
; cur != disciplines.end() ; cur ++ ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP MODULES:" << endl;
|
||||
for (map<perm_string,Module*>::iterator mod = pform_modules.begin()
|
||||
; mod != pform_modules.end()
|
||||
@@ -713,15 +733,7 @@ int main(int argc, char*argv[])
|
||||
for (mod = pform_modules.begin()
|
||||
; mod != pform_modules.end()
|
||||
; mod++) {
|
||||
list<PGate*> gates = (*mod).second->get_gates();
|
||||
list<PGate*>::const_iterator gate;
|
||||
for (gate = gates.begin(); gate != gates.end(); gate++) {
|
||||
PGModule *mod = dynamic_cast<PGModule*>(*gate);
|
||||
if (mod) {
|
||||
// Note that this module has been instantiated
|
||||
mentioned_p[mod->get_type()] = true;
|
||||
}
|
||||
}
|
||||
find_module_mention(mentioned_p, mod->second);
|
||||
}
|
||||
|
||||
for (mod = pform_modules.begin()
|
||||
@@ -809,6 +821,11 @@ int main(int argc, char*argv[])
|
||||
func(des);
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
cout << "CALCULATING ISLANDS" << endl;
|
||||
}
|
||||
des->join_islands();
|
||||
|
||||
if (net_path) {
|
||||
if (verbose_flag)
|
||||
cerr<<" dumping netlist to " <<net_path<< "..." <<endl;
|
||||
@@ -886,3 +903,40 @@ int main(int argc, char*argv[])
|
||||
|
||||
return des? des->errors : 1;
|
||||
}
|
||||
|
||||
static void find_module_mention(map<perm_string,bool>&check_map, Module*mod)
|
||||
{
|
||||
list<PGate*> gates = mod->get_gates();
|
||||
list<PGate*>::const_iterator gate;
|
||||
for (gate = gates.begin(); gate != gates.end(); gate++) {
|
||||
PGModule*tmp = dynamic_cast<PGModule*>(*gate);
|
||||
if (tmp) {
|
||||
// Note that this module has been instantiated
|
||||
check_map[tmp->get_type()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
list<PGenerate*>::const_iterator cur;
|
||||
for (cur = mod->generate_schemes.begin()
|
||||
; cur != mod->generate_schemes.end() ; cur ++) {
|
||||
find_module_mention(check_map, *cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void find_module_mention(map<perm_string,bool>&check_map, PGenerate*schm)
|
||||
{
|
||||
list<PGate*>::const_iterator gate;
|
||||
for (gate = schm->gates.begin(); gate != schm->gates.end(); gate++) {
|
||||
PGModule*tmp = dynamic_cast<PGModule*>(*gate);
|
||||
if (tmp) {
|
||||
// Note that this module has been instantiated
|
||||
check_map[tmp->get_type()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
list<PGenerate*>::const_iterator cur;
|
||||
for (cur = schm->generate_schemes.begin()
|
||||
; cur != schm->generate_schemes.end() ; cur ++) {
|
||||
find_module_mention(check_map, *cur);
|
||||
}
|
||||
}
|
||||
|
||||
+398
-154
@@ -20,6 +20,8 @@
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
# include <set>
|
||||
# include <cstdlib>
|
||||
|
||||
/*
|
||||
* This source file contains all the implementations of the Design
|
||||
@@ -31,6 +33,7 @@
|
||||
# include "compiler.h"
|
||||
# include "netmisc.h"
|
||||
# include <sstream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
Design:: Design()
|
||||
: errors(0), nodes_(0), procs_(0), lcounter_(0)
|
||||
@@ -206,10 +209,12 @@ void NetScope::run_defparams(Design*des)
|
||||
}
|
||||
}
|
||||
|
||||
map<pform_name_t,NetExpr*>::const_iterator pp;
|
||||
for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) {
|
||||
NetExpr*val = (*pp).second;
|
||||
pform_name_t path = (*pp).first;
|
||||
while (! defparams.empty()) {
|
||||
pair<pform_name_t,NetExpr*> pp = defparams.front();
|
||||
defparams.pop_front();
|
||||
|
||||
pform_name_t path = pp.first;
|
||||
NetExpr*val = pp.second;
|
||||
|
||||
perm_string perm_name = peek_tail_name(path);
|
||||
path.pop_back();
|
||||
@@ -220,11 +225,20 @@ void NetScope::run_defparams(Design*des)
|
||||
is the current scope. */
|
||||
NetScope*targ_scope = des->find_scope(this, eval_path);
|
||||
if (targ_scope == 0) {
|
||||
cerr << val->get_fileline() << ": warning: scope of " <<
|
||||
path << "." << perm_name << " not found." << endl;
|
||||
|
||||
// Push the defparam onto a list for retry
|
||||
// later. It is possible for the scope lookup to
|
||||
// fail if the scope being defparam'd into is
|
||||
// generated by an index array for generate.
|
||||
eval_path.push_back(hname_t(perm_name));
|
||||
defparams_later.push_back(make_pair(eval_path,val));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Once placed in the parameter map, the expression may
|
||||
// be deleted when evaluated, so give it a copy of this
|
||||
// expression, not the original.
|
||||
val = val->dup_expr();
|
||||
bool flag = targ_scope->replace_parameter(perm_name, val);
|
||||
if (! flag) {
|
||||
cerr << val->get_fileline() << ": warning: parameter "
|
||||
@@ -233,6 +247,66 @@ void NetScope::run_defparams(Design*des)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If some of the defparams didn't find a scope in the name,
|
||||
// then try again later. It may be that the target scope is
|
||||
// created later by generate scheme or instance array.
|
||||
if (! defparams_later.empty())
|
||||
des->defparams_later.insert(this);
|
||||
}
|
||||
|
||||
void NetScope::run_defparams_later(Design*des)
|
||||
{
|
||||
set<NetScope*> target_scopes;
|
||||
list<pair<list<hname_t>,NetExpr*> > defparams_even_later;
|
||||
|
||||
while (! defparams_later.empty()) {
|
||||
pair<list<hname_t>,NetExpr*> cur = defparams_later.front();
|
||||
defparams_later.pop_front();
|
||||
|
||||
list<hname_t>eval_path = cur.first;
|
||||
perm_string name = eval_path.back().peek_name();
|
||||
eval_path.pop_back();
|
||||
|
||||
NetExpr*val = cur.second;
|
||||
|
||||
NetScope*targ_scope = des->find_scope(this, eval_path);
|
||||
if (targ_scope == 0) {
|
||||
// If a scope in the target path is not found,
|
||||
// then push this defparam for handling even
|
||||
// later. Maybe a later generate scheme or
|
||||
// instance array will create the scope.
|
||||
defparams_even_later.push_back(cur);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Once placed in the parameter map, the expression may
|
||||
// be deleted when evaluated, so give it a copy of this
|
||||
// expression, not the original.
|
||||
val = val->dup_expr();
|
||||
bool flag = targ_scope->replace_parameter(name, val);
|
||||
if (! flag) {
|
||||
cerr << val->get_fileline() << ": warning: parameter "
|
||||
<< name << " not found in "
|
||||
<< scope_path(targ_scope) << "." << endl;
|
||||
}
|
||||
|
||||
// We'll need to re-evaluate parameters in this scope
|
||||
target_scopes.insert(targ_scope);
|
||||
}
|
||||
|
||||
// All the scopes that this defparam set touched should have
|
||||
// their parameters re-evaluated.
|
||||
for (set<NetScope*>::iterator cur = target_scopes.begin()
|
||||
; cur != target_scopes.end() ; cur ++ )
|
||||
(*cur)->evaluate_parameters(des);
|
||||
|
||||
// If there are some scopes that still have missing scopes,
|
||||
// then sav them back into the defparams_later list for a
|
||||
// later pass.
|
||||
defparams_later = defparams_even_later;
|
||||
if (! defparams_later.empty())
|
||||
des->defparams_later.insert(this);
|
||||
}
|
||||
|
||||
void Design::evaluate_parameters()
|
||||
@@ -242,6 +316,268 @@ void Design::evaluate_parameters()
|
||||
(*scope)->evaluate_parameters(this);
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
{
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
bool range_flag = false;
|
||||
|
||||
/* Evaluate the msb expression, if it is present. */
|
||||
if ((*cur).second.msb) {
|
||||
eval_expr((*cur).second.msb);
|
||||
if (! eval_as_long(msb, (*cur).second.msb)) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate msb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *(*cur).second.msb << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
/* Evaluate the lsb expression, if it is present. */
|
||||
if ((*cur).second.lsb) {
|
||||
eval_expr((*cur).second.lsb);
|
||||
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate lsb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *(*cur).second.lsb << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the parameter expression, if necessary. */
|
||||
NetExpr*expr = (*cur).second.expr;
|
||||
if (expr == NULL) return; // This is an invalid parameter so return.
|
||||
|
||||
eval_expr(expr);
|
||||
|
||||
/* The eval_expr may delete and replace the expr pointer, so the
|
||||
second.expr value cannot be relied on. Might as well replace
|
||||
it now with the expression that we evaluated. */
|
||||
(*cur).second.expr = expr;
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate real parameter value: "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate parameter "
|
||||
<< (*cur).first
|
||||
<< " value: " << *expr << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unhandled expression type?" << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
sure the value is set right. Note that if the
|
||||
parameter doesn't have an explicit range, then it
|
||||
will get the signedness from the expression itself. */
|
||||
if (range_flag) {
|
||||
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
/* If we have a real value convert it to an integer. */
|
||||
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
verinum nval(tmp->value().as_long64());
|
||||
expr = new NetEConst(nval);
|
||||
expr->set_line(*((*cur).second.expr));
|
||||
(*cur).second.expr = expr;
|
||||
}
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>(expr);
|
||||
assert(val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
if (! (value.has_len()
|
||||
&& (value.len() == wid)
|
||||
&& (value.has_sign() == (*cur).second.signed_flag))) {
|
||||
|
||||
verinum tmp (value, wid);
|
||||
tmp.has_sign ( (*cur).second.signed_flag );
|
||||
delete val;
|
||||
val = new NetEConst(tmp);
|
||||
(*cur).second.expr = expr = val;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no value ranges to test the value against,
|
||||
// then we are done.
|
||||
if ((*cur).second.range == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
|
||||
ivl_assert(*(*cur).second.expr, (*cur).second.expr);
|
||||
ivl_assert(*(*cur).second.expr, val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
bool from_flag = (*cur).second.range == 0? true : false;
|
||||
for (range_t*value_range = (*cur).second.range
|
||||
; value_range ; value_range = value_range->next) {
|
||||
|
||||
// If we already know that the value is
|
||||
// within a "from" range, then do not test
|
||||
// any more of the from ranges.
|
||||
if (from_flag && value_range->exclude_flag==false)
|
||||
continue;
|
||||
|
||||
if (value_range->low_expr) {
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
|
||||
ivl_assert(*value_range->low_expr, tmp);
|
||||
if (value_range->low_open_flag && value <= tmp->value())
|
||||
continue;
|
||||
else if (value < tmp->value())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->high_expr) {
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
|
||||
ivl_assert(*value_range->high_expr, tmp);
|
||||
if (value_range->high_open_flag && value >= tmp->value())
|
||||
continue;
|
||||
else if (value > tmp->value())
|
||||
continue;
|
||||
}
|
||||
|
||||
// Within the range. If this is a "from"
|
||||
// range, then set the from_flag and continue.
|
||||
if (value_range->exclude_flag == false) {
|
||||
from_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// OH NO! In an excluded range. signal an error.
|
||||
from_flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we found no from range that contains the
|
||||
// value, then report an error.
|
||||
if (! from_flag) {
|
||||
cerr << val->get_fileline() << ": error: "
|
||||
<< "Parameter value " << value
|
||||
<< " is out of range for parameter " << (*cur).first
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
||||
{
|
||||
NetExpr*expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
NetECReal*res = 0;
|
||||
eval_expr(expr);
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
res = tmp;
|
||||
} else {
|
||||
ivl_assert(*expr, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
verireal val (tmp->value().as_long());
|
||||
res = new NetECReal(val);
|
||||
res->set_line(*tmp);
|
||||
} else {
|
||||
ivl_assert(*expr, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ivl_assert(*expr, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
(*cur).second.expr = res;
|
||||
double value = res->value().as_double();
|
||||
|
||||
bool from_flag = (*cur).second.range == 0? true : false;
|
||||
for (range_t*value_range = (*cur).second.range
|
||||
; value_range ; value_range = value_range->next) {
|
||||
|
||||
if (from_flag && value_range->exclude_flag==false)
|
||||
continue;
|
||||
|
||||
if (value_range->low_expr) {
|
||||
double tmp;
|
||||
bool flag = eval_as_double(tmp, value_range->low_expr);
|
||||
ivl_assert(*value_range->low_expr, flag);
|
||||
if (value_range->low_open_flag && value <= tmp)
|
||||
continue;
|
||||
else if (value < tmp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->high_expr) {
|
||||
double tmp;
|
||||
bool flag = eval_as_double(tmp, value_range->high_expr);
|
||||
ivl_assert(*value_range->high_expr, flag);
|
||||
if (value_range->high_open_flag && value >= tmp)
|
||||
continue;
|
||||
else if (value > tmp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->exclude_flag == false) {
|
||||
from_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// All the above tests failed, so we must have tripped
|
||||
// an exclude rule.
|
||||
from_flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! from_flag) {
|
||||
cerr << res->get_fileline() << ": error: "
|
||||
<< "Parameter value " << value
|
||||
<< " is out of range for parameter " << (*cur).first
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameters(Design*des)
|
||||
{
|
||||
NetScope*cur = sub_;
|
||||
@@ -250,172 +586,69 @@ void NetScope::evaluate_parameters(Design*des)
|
||||
cur = cur->sib_;
|
||||
}
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << ":0" << ": debug: "
|
||||
<< "Evaluate parameters in " << scope_path(this) << endl;
|
||||
|
||||
// Evaluate the parameter values. The parameter expressions
|
||||
// have already been elaborated and replaced by the scope
|
||||
// scanning code. Now the parameter expression can be fully
|
||||
// evaluated, or it cannot be evaluated at all.
|
||||
|
||||
typedef map<perm_string,param_expr_t>::iterator mparm_it_t;
|
||||
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
for (param_ref_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
bool range_flag = false;
|
||||
NetExpr*expr;
|
||||
|
||||
/* Evaluate the msb expression, if it is present. */
|
||||
expr = (*cur).second.msb;
|
||||
|
||||
if (expr) {
|
||||
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
|
||||
|
||||
if (! tmp) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate msb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.msb = nexpr;
|
||||
|
||||
tmp = dynamic_cast<NetEConst*>(nexpr);
|
||||
}
|
||||
|
||||
assert(tmp);
|
||||
msb = tmp->value().as_long();
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
/* Evaluate the lsb expression, if it is present. */
|
||||
expr = (*cur).second.lsb;
|
||||
if (expr) {
|
||||
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
|
||||
|
||||
if (! tmp) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate lsb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.lsb = nexpr;
|
||||
|
||||
tmp = dynamic_cast<NetEConst*>(nexpr);
|
||||
}
|
||||
|
||||
assert(tmp);
|
||||
lsb = tmp->value().as_long();
|
||||
|
||||
assert(range_flag);
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the parameter expression, if necessary. */
|
||||
expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate real parameter value: "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
}
|
||||
switch ((*cur).second.type) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
evaluate_parameter_logic_(des, cur);
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
|
||||
// Try to evaluate the expression.
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate parameter "
|
||||
<< (*cur).first
|
||||
<< " value: " <<
|
||||
*expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The evaluate worked, replace the old
|
||||
// expression with this constant value.
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
}
|
||||
case IVL_VT_REAL:
|
||||
evaluate_parameter_real_(des, cur);
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unhandled expression type?" << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
sure the value is set right. Note that if the
|
||||
parameter doesn't have an explicit range, then it
|
||||
will get the signedness from the expression itself. */
|
||||
if (range_flag) {
|
||||
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
|
||||
assert(val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
if (! (value.has_len()
|
||||
&& (value.len() == wid)
|
||||
&& (value.has_sign() == (*cur).second.signed_flag))) {
|
||||
|
||||
verinum tmp (value, wid);
|
||||
tmp.has_sign ( (*cur).second.signed_flag );
|
||||
delete val;
|
||||
val = new NetEConst(tmp);
|
||||
(*cur).second.expr = val;
|
||||
}
|
||||
cerr << (*cur).second.get_fileline() << ": internal error: "
|
||||
<< "Unexpected expression type " << (*cur).second.type
|
||||
<< "." << endl;
|
||||
cerr << (*cur).second.get_fileline() << ": : "
|
||||
<< "Parameter name: " << (*cur).first << endl;
|
||||
cerr << (*cur).second.get_fileline() << ": : "
|
||||
<< "Expression is: " << *(*cur).second.expr << endl;
|
||||
ivl_assert((*cur).second, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Design::residual_defparams()
|
||||
{
|
||||
for (list<NetScope*>::const_iterator scope = root_scopes_.begin();
|
||||
scope != root_scopes_.end(); scope++)
|
||||
(*scope)->residual_defparams(this);
|
||||
}
|
||||
|
||||
void NetScope::residual_defparams(Design*des)
|
||||
{
|
||||
// Clean out the list of defparams that never managed to match
|
||||
// a scope. Print a warning for each.
|
||||
while (! defparams_later.empty()) {
|
||||
pair<list<hname_t>,NetExpr*> cur = defparams_later.front();
|
||||
defparams_later.pop_front();
|
||||
|
||||
cerr << cur.second->get_fileline() << ": warning: "
|
||||
<< "Scope of " << cur.first << " not found." << endl;
|
||||
}
|
||||
|
||||
NetScope*cur = sub_;
|
||||
while (cur) {
|
||||
cur->residual_defparams(des);
|
||||
cur = cur->sib_;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Design::get_flag(const string&key) const
|
||||
{
|
||||
map<string,const char*>::const_iterator tmp = flags_.find(key);
|
||||
@@ -553,3 +786,14 @@ void Design::delete_process(NetProcTop*top)
|
||||
delete top;
|
||||
}
|
||||
|
||||
void Design::join_islands(void)
|
||||
{
|
||||
if (nodes_ == 0)
|
||||
return;
|
||||
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
join_island(cur);
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
|
||||
+12
-2
@@ -476,7 +476,12 @@ NetEParam::NetEParam()
|
||||
}
|
||||
|
||||
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
|
||||
: des_(d), scope_(s), name_(n)
|
||||
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
|
||||
{
|
||||
}
|
||||
|
||||
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
|
||||
: des_(d), scope_(s), reference_(ref)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -489,9 +494,14 @@ bool NetEParam::has_width() const
|
||||
return false;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEParam::expr_type() const
|
||||
{
|
||||
return (*reference_).second.type;
|
||||
}
|
||||
|
||||
NetEParam* NetEParam::dup_expr() const
|
||||
{
|
||||
NetEParam*tmp = new NetEParam(des_, scope_, name_);
|
||||
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
+35
@@ -247,6 +247,41 @@ verinum::V Nexus::get_init() const
|
||||
return verinum::Vz;
|
||||
}
|
||||
|
||||
bool Nexus::drivers_present() const
|
||||
{
|
||||
assert(list_);
|
||||
for (Link*cur = list_ ; cur ; cur = cur->next_) {
|
||||
if (cur->get_dir() == Link::OUTPUT)
|
||||
return true;
|
||||
|
||||
if (cur->get_dir() == Link::INPUT)
|
||||
continue;
|
||||
|
||||
// Must be PASSIVE, so if it is some kind of net, see if
|
||||
// it is the sort that might drive the nexus.
|
||||
const NetObj*obj;
|
||||
unsigned pin;
|
||||
cur->cur_link(obj, pin);
|
||||
if (const NetNet*net = dynamic_cast<const NetNet*>(obj))
|
||||
switch (net->type()) {
|
||||
case NetNet::SUPPLY0:
|
||||
case NetNet::SUPPLY1:
|
||||
case NetNet::TRI0:
|
||||
case NetNet::TRI1:
|
||||
case NetNet::WAND:
|
||||
case NetNet::WOR:
|
||||
case NetNet::TRIAND:
|
||||
case NetNet::TRIOR:
|
||||
case NetNet::REG:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
|
||||
{
|
||||
for (Link*cur = list_ ; cur ; cur = cur->next_) {
|
||||
|
||||
+10
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -53,8 +53,13 @@ NexusSet* NetEBinary::nex_input(bool rem_out)
|
||||
|
||||
NexusSet* NetEConcat::nex_input(bool rem_out)
|
||||
{
|
||||
if (parms_[0] == NULL) return NULL;
|
||||
NexusSet*result = parms_[0]->nex_input(rem_out);
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
if (parms_[idx] == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
@@ -98,6 +103,10 @@ NexusSet* NetESelect::nex_input(bool rem_out)
|
||||
{
|
||||
NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet();
|
||||
NexusSet*tmp = expr_->nex_input(rem_out);
|
||||
if (tmp == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
return result;
|
||||
@@ -381,4 +390,3 @@ NexusSet* NetWhile::nex_input(bool rem_out)
|
||||
delete tmp;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+30
-8
@@ -22,7 +22,9 @@
|
||||
|
||||
# include "netlist.h"
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
/*
|
||||
* The NetScope class keeps a scope tree organized. Each node of the
|
||||
@@ -104,17 +106,24 @@ void NetScope::set_line(perm_string file, perm_string def_file,
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
|
||||
ivl_variable_type_t type,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno)
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line)
|
||||
{
|
||||
param_expr_t&ref = parameters[key];
|
||||
NetExpr* res = ref.expr;
|
||||
ref.expr = expr;
|
||||
ref.type = type;
|
||||
ref.msb = msb;
|
||||
ref.lsb = lsb;
|
||||
ref.signed_flag = signed_flag;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
ivl_assert(file_line, ref.range == 0);
|
||||
ref.range = range_list;
|
||||
ref.set_line(file_line);
|
||||
|
||||
ivl_assert(file_line, type != IVL_VT_NO_TYPE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -157,10 +166,10 @@ bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
|
||||
|
||||
/*
|
||||
* This is not really complete (msb, lsb, sign). It is currently only
|
||||
* used to add a genver to the local parameter list.
|
||||
* used to add a genvar to the local parameter list.
|
||||
*/
|
||||
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
|
||||
perm_string file, unsigned lineno)
|
||||
const LineInfo&file_line)
|
||||
{
|
||||
param_expr_t&ref = localparams[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -168,8 +177,7 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
ref.set_line(file_line);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -202,6 +210,20 @@ const NetExpr* NetScope::get_parameter(const char* key,
|
||||
|
||||
return 0;
|
||||
}
|
||||
map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_string key)
|
||||
{
|
||||
map<perm_string,param_expr_t>::iterator idx;
|
||||
|
||||
idx = parameters.find(key);
|
||||
if (idx != parameters.end())
|
||||
return idx;
|
||||
|
||||
idx = localparams.find(perm_string::literal(key));
|
||||
if (idx != localparams.end())
|
||||
return idx;
|
||||
|
||||
return (map<perm_string,param_expr_t>::iterator) 0;
|
||||
}
|
||||
|
||||
NetScope::TYPE NetScope::type() const
|
||||
{
|
||||
@@ -253,7 +275,7 @@ const NetFuncDef* NetScope::func_def() const
|
||||
void NetScope::set_module_name(perm_string n)
|
||||
{
|
||||
assert(type_ == MODULE);
|
||||
module_name_ = n; /* NOTE: n mus have been permallocated. */
|
||||
module_name_ = n; /* NOTE: n must have been permallocated. */
|
||||
}
|
||||
|
||||
perm_string NetScope::module_name() const
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
|
||||
# include <typeinfo>
|
||||
# include <cstdlib>
|
||||
# include "compiler.h"
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static bool has_enable(ivl_switch_type_t tt)
|
||||
{
|
||||
switch (tt) {
|
||||
case IVL_SW_TRANIF0:
|
||||
case IVL_SW_TRANIF1:
|
||||
case IVL_SW_RTRANIF0:
|
||||
case IVL_SW_RTRANIF1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
|
||||
: NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
|
||||
{
|
||||
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
|
||||
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
|
||||
if (pin_count() == 3) {
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
pin(2).set_name(perm_string::literal("E"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off)
|
||||
: NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off)
|
||||
{
|
||||
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
|
||||
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
|
||||
}
|
||||
|
||||
NetTran::~NetTran()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetTran::vector_width() const
|
||||
{
|
||||
return wid_;
|
||||
}
|
||||
|
||||
unsigned NetTran::part_width() const
|
||||
{
|
||||
return part_;
|
||||
}
|
||||
|
||||
unsigned NetTran::part_offset() const
|
||||
{
|
||||
return off_;
|
||||
}
|
||||
|
||||
void join_island(NetObj*obj)
|
||||
{
|
||||
IslandBranch*branch = dynamic_cast<IslandBranch*> (obj);
|
||||
|
||||
// If this is not even a branch, then stop now.
|
||||
if (branch == 0)
|
||||
return;
|
||||
|
||||
// If this is a branch, but already given to an island, then
|
||||
// stop.
|
||||
if (branch->island)
|
||||
return;
|
||||
|
||||
list<NetObj*> uncommitted_neighbors;
|
||||
|
||||
// Look for neighboring objects that might already be in
|
||||
// islands. If we find something, then join that island.
|
||||
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
|
||||
Nexus*nex = obj->pin(idx).nexus();
|
||||
for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
unsigned pin;
|
||||
NetObj*tmp;
|
||||
cur->cur_link(tmp, pin);
|
||||
|
||||
// Skip self.
|
||||
if (tmp == obj)
|
||||
continue;
|
||||
|
||||
// If tmb is not a branch, then skip it.
|
||||
IslandBranch*tmp_branch = dynamic_cast<IslandBranch*> (tmp);
|
||||
if (tmp_branch == 0)
|
||||
continue;
|
||||
|
||||
// If that is an uncommitted branch, then save
|
||||
// it. When I finally choose an island for self,
|
||||
// these branches will be scanned so that they join
|
||||
// this island as well.
|
||||
if (tmp_branch->island == 0) {
|
||||
uncommitted_neighbors.push_back(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
ivl_assert(*obj, branch->island==0 || branch->island==tmp_branch->island);
|
||||
|
||||
// We found an existing island to join. Join it
|
||||
// now. Keep scanning in order to find more neighbors.
|
||||
if (branch->island == 0) {
|
||||
if (debug_elaborate)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Join branch to existing island." << endl;
|
||||
branch->island = tmp_branch->island;
|
||||
|
||||
} else if (branch->island != tmp_branch->island) {
|
||||
cerr << obj->get_fileline() << ": internal error: "
|
||||
<< "Oops, Found 2 neighboring islands." << endl;
|
||||
ivl_assert(*obj, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If after all that we did not find an island to join, then
|
||||
// start the island not and join it.
|
||||
if (branch->island == 0) {
|
||||
branch->island = new ivl_island_s;
|
||||
branch->island->discipline = 0;
|
||||
if (debug_elaborate)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Create new island for this branch" << endl;
|
||||
}
|
||||
|
||||
// Now scan all the uncommitted neighbors I found. Calling
|
||||
// join_island() on them will cause them to notice me in the
|
||||
// process, and thus they will join my island. This process
|
||||
// will recurse until all the connected branches join this island.
|
||||
for (list<NetObj*>::iterator cur = uncommitted_neighbors.begin()
|
||||
; cur != uncommitted_neighbors.end() ; cur ++ ) {
|
||||
join_island(*cur);
|
||||
}
|
||||
}
|
||||
+23
-8
@@ -761,10 +761,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
|
||||
pin(0).set_dir(Link::INPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
}
|
||||
pin(0).set_name(perm_string::literal("Part"), 0);
|
||||
pin(1).set_name(perm_string::literal("Vect"), 0);
|
||||
@@ -787,10 +783,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
|
||||
pin(0).set_dir(Link::INPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::PASSIVE);
|
||||
pin(1).set_dir(Link::PASSIVE);
|
||||
break;
|
||||
}
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
|
||||
@@ -857,6 +849,24 @@ const NetScope* NetProcTop::scope() const
|
||||
return scope_;
|
||||
}
|
||||
|
||||
NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width)
|
||||
: NetNode(scope, n, 2), width_(width)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(0).set_name(perm_string::literal("O"), 0);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
pin(1).set_name(perm_string::literal("I"), 0);
|
||||
}
|
||||
|
||||
NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag)
|
||||
: NetNode(scope, n, 2), signed_flag_(signed_flag)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(0).set_name(perm_string::literal("O"), 0);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
pin(1).set_name(perm_string::literal("I"), 0);
|
||||
}
|
||||
|
||||
NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt)
|
||||
: NetNode(scope, n, cnt+1), width_(wid)
|
||||
{
|
||||
@@ -1504,6 +1514,11 @@ NetLiteral::~NetLiteral()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetLiteral::data_type() const
|
||||
{
|
||||
return IVL_VT_REAL;
|
||||
}
|
||||
|
||||
const verireal& NetLiteral::value_real() const
|
||||
{
|
||||
return real_;
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
# include <map>
|
||||
# include <list>
|
||||
# include <vector>
|
||||
# include <set>
|
||||
# include <utility>
|
||||
# include "ivl_target.h"
|
||||
# include "pform_types.h"
|
||||
# include "config.h"
|
||||
@@ -49,8 +51,10 @@ class ostream;
|
||||
class Design;
|
||||
class Link;
|
||||
class Nexus;
|
||||
class NetEvent;
|
||||
class NetNet;
|
||||
class NetNode;
|
||||
class NetObj;
|
||||
class NetProc;
|
||||
class NetProcTop;
|
||||
class NetRelease;
|
||||
@@ -60,6 +64,7 @@ class NetExpr;
|
||||
class NetESignal;
|
||||
class NetFuncDef;
|
||||
class NetRamDq;
|
||||
class NetTaskDef;
|
||||
class NetEvTrig;
|
||||
class NetEvWait;
|
||||
|
||||
@@ -69,6 +74,8 @@ struct functor_t;
|
||||
|
||||
ostream& operator << (ostream&o, ivl_variable_type_t val);
|
||||
|
||||
extern void join_island(NetObj*obj);
|
||||
|
||||
/* =========
|
||||
* A NetObj is anything that has any kind of behavior in the
|
||||
* netlist. Nodes can be gates, registers, etc. and are linked
|
||||
@@ -129,6 +136,20 @@ class NetObj : public Attrib, public virtual LineInfo {
|
||||
const NetExpr* delay3_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Objects that can be island branches are derived from this. (It is
|
||||
* possible for an object to be a NetObj and an IslandBranch.) This is
|
||||
* used to collect island information about the node.
|
||||
*/
|
||||
|
||||
class IslandBranch {
|
||||
public:
|
||||
IslandBranch() : island(0) { }
|
||||
|
||||
public:
|
||||
struct ivl_island_s* island;
|
||||
};
|
||||
|
||||
class Link {
|
||||
|
||||
friend void connect(Link&, Link&);
|
||||
@@ -269,6 +290,10 @@ class Nexus {
|
||||
|
||||
NetNet* pick_any_net();
|
||||
|
||||
/* This method returns true if there are any drivers
|
||||
(including variables) attached to this nexus. */
|
||||
bool drivers_present() const;
|
||||
|
||||
/* This method returns true if all the possible drivers of
|
||||
this nexus are constant. It will also return true if there
|
||||
are no drivers at all. */
|
||||
@@ -578,9 +603,243 @@ class NetNet : public NetObj {
|
||||
vector<class NetDelaySrc*> delay_paths_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
*/
|
||||
class NetScope : public Attrib {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
|
||||
|
||||
/* Create a new scope, and attach it to the given parent. The
|
||||
name is expected to have been permallocated. */
|
||||
NetScope(NetScope*up, const hname_t&name, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
/* Rename the scope using the name generated by inserting as
|
||||
many pad characters as required between prefix and suffix
|
||||
to make the name unique in the parent scope. Return false
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* 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
|
||||
the scope. The return value from set_parameter is the
|
||||
previous expression, if there was one. */
|
||||
|
||||
struct range_t;
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
ivl_variable_type_t type,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
const LineInfo&file_line);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
const NetExpr*&lsb) const;
|
||||
|
||||
/* These are used by defparam elaboration to replace the
|
||||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
bool replace_parameter(perm_string name, NetExpr*val);
|
||||
|
||||
/* These methods set or access events that live in this
|
||||
scope. */
|
||||
|
||||
void add_event(NetEvent*);
|
||||
void rem_event(NetEvent*);
|
||||
NetEvent*find_event(perm_string name);
|
||||
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
used to locate signals within a scope. */
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
objects to locate nearby scopes. */
|
||||
NetScope* parent();
|
||||
NetScope* child(const hname_t&name);
|
||||
const NetScope* parent() const;
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
TYPE type() const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_module_name(perm_string);
|
||||
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
void set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno);
|
||||
void set_line(perm_string file, unsigned lineno);
|
||||
void set_line(const LineInfo *info);
|
||||
perm_string get_file() const { return file_; };
|
||||
perm_string get_def_file() const { return def_file_; };
|
||||
unsigned get_lineno() const { return lineno_; };
|
||||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
||||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
units of milliseconds.
|
||||
|
||||
If a NetScope is created with a parent scope, the new scope
|
||||
will initially inherit the unit and precision of the
|
||||
parent scope. */
|
||||
|
||||
void time_unit(int);
|
||||
void time_precision(int);
|
||||
|
||||
int time_unit() const;
|
||||
int time_precision() const;
|
||||
|
||||
void default_nettype(NetNet::Type);
|
||||
NetNet::Type default_nettype() const;
|
||||
|
||||
/* The fullname of the scope is the hierarchical name
|
||||
component (which includes the name and array index) whereas
|
||||
the basename is just my name. */
|
||||
perm_string basename() const;
|
||||
const hname_t& fullname() const { return name_; }
|
||||
|
||||
void run_defparams(class Design*);
|
||||
void run_defparams_later(class Design*);
|
||||
|
||||
void evaluate_parameters(class Design*);
|
||||
|
||||
// Look for defparams that never matched, and print warnings.
|
||||
void residual_defparams(class Design*);
|
||||
|
||||
/* This method generates a non-hierarchical name that is
|
||||
guaranteed to be unique within this scope. */
|
||||
perm_string local_symbol();
|
||||
|
||||
void dump(ostream&) const;
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
/* This method runs the functor on me. Recurse through the
|
||||
children of this node as well. */
|
||||
void run_functor(Design*des, functor_t*fun);
|
||||
|
||||
|
||||
/* This member is used during elaboration to pass defparam
|
||||
assignments from the scope pass to the parameter evaluation
|
||||
step. After that, it is not used. */
|
||||
|
||||
list<pair<pform_name_t,NetExpr*> > defparams;
|
||||
list<pair<list<hname_t>,NetExpr*> > defparams_later;
|
||||
|
||||
public:
|
||||
struct range_t {
|
||||
bool exclude_flag;
|
||||
// Lower bound
|
||||
bool low_open_flag;
|
||||
NetExpr*low_expr;
|
||||
// Upper bound
|
||||
bool high_open_flag;
|
||||
NetExpr*high_expr;
|
||||
// Link to the next range specification
|
||||
struct range_t*next;
|
||||
};
|
||||
|
||||
/* After everything is all set up, the code generators like
|
||||
access to these things to make up the parameter lists. */
|
||||
struct param_expr_t : public LineInfo {
|
||||
param_expr_t() : type(IVL_VT_NO_TYPE), range(0) { }
|
||||
// Type information
|
||||
ivl_variable_type_t type;
|
||||
bool signed_flag;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
// range constraints
|
||||
struct range_t*range;
|
||||
// Expression value
|
||||
NetExpr*expr;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
|
||||
typedef map<perm_string,param_expr_t>::iterator param_ref_t;
|
||||
|
||||
param_ref_t find_parameter(perm_string name);
|
||||
|
||||
|
||||
struct spec_val_t {
|
||||
ivl_variable_type_t type;
|
||||
union {
|
||||
double real_val; // type == IVL_VT_REAL
|
||||
long integer; // type == IVL_VT_BOOL
|
||||
};
|
||||
};
|
||||
map<perm_string,spec_val_t>specparams;
|
||||
|
||||
/* Module instance arrays are collected here for access during
|
||||
the multiple elaboration passes. */
|
||||
typedef svector<NetScope*> scope_vec_t;
|
||||
map<perm_string, scope_vec_t>instance_arrays;
|
||||
|
||||
/* Loop generate uses this as scratch space during
|
||||
elaboration. Expression evaluation can use this to match
|
||||
names. */
|
||||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
private:
|
||||
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
|
||||
void evaluate_parameter_real_(Design*des, param_ref_t cur);
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
perm_string file_;
|
||||
perm_string def_file_;
|
||||
unsigned lineno_;
|
||||
unsigned def_lineno_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
NetEvent *events_;
|
||||
NetNet *signals_;
|
||||
perm_string module_name_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
};
|
||||
|
||||
NetScope*up_;
|
||||
NetScope*sib_;
|
||||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ABS component. The node has a single
|
||||
* input, a signe expression, that it converts to the absolute
|
||||
* input, a signed expression, that it converts to the absolute
|
||||
* value. The gate is simple: pin(0) is the output and pin(1) is the input.
|
||||
*/
|
||||
class NetAbs : public NetNode {
|
||||
@@ -669,6 +928,44 @@ class NetArrayDq : public NetNode {
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert an IVL_VT_REAL input to a logical value with the
|
||||
* given width. The input is pin(1) and the output is pin(0).
|
||||
*/
|
||||
class NetCastInt : public NetNode {
|
||||
|
||||
public:
|
||||
NetCastInt(NetScope*s, perm_string n, unsigned width);
|
||||
|
||||
unsigned width() const { return width_; }
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert an input to IVL_VT_REAL. The input is pin(1), which can be
|
||||
* any vector type (VT_BOOL or VT_LOGIC) and the output is pin(0),
|
||||
* which is IVL_VT_REAL. The conversion interprets the input as an
|
||||
* unsigned value unless the signed_flag is true.
|
||||
*/
|
||||
class NetCastReal : public NetNode {
|
||||
|
||||
public:
|
||||
NetCastReal(NetScope*s, perm_string n, bool signed_flag);
|
||||
|
||||
bool signed_flag() const { return signed_flag_; }
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
||||
private:
|
||||
bool signed_flag_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This type represents the LPM_CLSHIFT device.
|
||||
*/
|
||||
@@ -1129,6 +1426,33 @@ class NetSysFunc : public NetNode {
|
||||
const struct sfunc_return_type*def_;
|
||||
};
|
||||
|
||||
class NetTran : public NetNode, public IslandBranch {
|
||||
|
||||
public:
|
||||
// Tran devices other than TRAN_VP
|
||||
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
|
||||
// Create a TRAN_VP
|
||||
NetTran(NetScope*scope, perm_string n, unsigned wid,
|
||||
unsigned part, unsigned off);
|
||||
~NetTran();
|
||||
|
||||
ivl_switch_type_t type() const { return type_; }
|
||||
|
||||
// These are only used for IVL_SW_TRAN_PV
|
||||
unsigned vector_width() const;
|
||||
unsigned part_width() const;
|
||||
unsigned part_offset() const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
||||
private:
|
||||
ivl_switch_type_t type_;
|
||||
unsigned wid_;
|
||||
unsigned part_;
|
||||
unsigned off_;
|
||||
};
|
||||
|
||||
/* =========
|
||||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a hierarchy that serves that purpose.
|
||||
@@ -1343,8 +1667,8 @@ class NetECRealParam : public NetECReal {
|
||||
* selector as the input.
|
||||
*
|
||||
* The NetPartSelect can be output from the signal (i.e. reading a
|
||||
* part), input into the signal, or bi-directional. The DIR method
|
||||
* gives the type of the node.
|
||||
* part) or input into the signal. The DIR method gives the type of
|
||||
* the node.
|
||||
*
|
||||
* VP (Vector-to-Part)
|
||||
* Output pin 0 is the part select, and input pin 1 is connected to
|
||||
@@ -1354,10 +1678,6 @@ class NetECRealParam : public NetECReal {
|
||||
* Output pin 1 is connected to the NetNet, and input pin 0 is the
|
||||
* part select. In this case, the node is driving the NetNet.
|
||||
*
|
||||
* BI (BI-directional)
|
||||
* Pin 0 is the part select and pin 1 is connected to the NetNet, but
|
||||
* the ports are intended to be bi-directional.
|
||||
*
|
||||
* Note that whatever the direction that data is intended to flow,
|
||||
* pin-0 is the part select and pin-1 is connected to the NetNet.
|
||||
*/
|
||||
@@ -1365,7 +1685,7 @@ class NetPartSelect : public NetNode {
|
||||
|
||||
public:
|
||||
// enum for the device direction
|
||||
enum dir_t { VP, PV, BI };
|
||||
enum dir_t { VP, PV};
|
||||
|
||||
explicit NetPartSelect(NetNet*sig,
|
||||
unsigned off, unsigned wid, dir_t dir);
|
||||
@@ -3006,6 +3326,7 @@ class NetEParam : public NetExpr {
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual bool has_width() const;
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEParam* dup_expr() const;
|
||||
|
||||
@@ -3014,7 +3335,10 @@ class NetEParam : public NetExpr {
|
||||
private:
|
||||
Design*des_;
|
||||
NetScope*scope_;
|
||||
perm_string name_;
|
||||
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
|
||||
ref_t reference_;
|
||||
|
||||
NetEParam(class Design*des, NetScope*scope, ref_t ref);
|
||||
};
|
||||
|
||||
|
||||
@@ -3286,205 +3610,17 @@ class NetESignal : public NetExpr {
|
||||
NetExpr*word_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
* The Design object keeps a list of work items for processing
|
||||
* elaboration. This is the type of those work items.
|
||||
*/
|
||||
class NetScope : public Attrib {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
|
||||
|
||||
/* Create a new scope, and attach it to the given parent. The
|
||||
name is expected to have been permallocated. */
|
||||
NetScope(NetScope*up, const hname_t&name, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
/* Rename the scope using the name generated by inserting as
|
||||
many pad characters as required between prefix and suffix
|
||||
to make the name unique in the parent scope. Return false
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* 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
|
||||
the scope. The return value from set_parameter is the
|
||||
previous expression, if there was one. */
|
||||
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
perm_string file, unsigned lineno);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
const NetExpr*&lsb) const;
|
||||
|
||||
/* These are used by defparam elaboration to replace the
|
||||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
bool replace_parameter(perm_string name, NetExpr*val);
|
||||
|
||||
/* These methods set or access events that live in this
|
||||
scope. */
|
||||
|
||||
void add_event(NetEvent*);
|
||||
void rem_event(NetEvent*);
|
||||
NetEvent*find_event(perm_string name);
|
||||
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
used to locate signals within a scope. */
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
objects to locate nearby scopes. */
|
||||
NetScope* parent();
|
||||
NetScope* child(const hname_t&name);
|
||||
const NetScope* parent() const;
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
TYPE type() const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_module_name(perm_string);
|
||||
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
void set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno);
|
||||
void set_line(perm_string file, unsigned lineno);
|
||||
void set_line(const LineInfo *info);
|
||||
perm_string get_file() const { return file_; };
|
||||
perm_string get_def_file() const { return def_file_; };
|
||||
unsigned get_lineno() const { return lineno_; };
|
||||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
||||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
units of milliseconds.
|
||||
|
||||
If a NetScope is created with a parent scope, the new scope
|
||||
will initially inherit the unit and precision of the
|
||||
parent scope. */
|
||||
|
||||
void time_unit(int);
|
||||
void time_precision(int);
|
||||
|
||||
int time_unit() const;
|
||||
int time_precision() const;
|
||||
|
||||
void default_nettype(NetNet::Type);
|
||||
NetNet::Type default_nettype() const;
|
||||
|
||||
/* The fullname of the scope is the hierarchical name
|
||||
component (which includes the name and array index) whereas
|
||||
the basename is just my name. */
|
||||
perm_string basename() const;
|
||||
const hname_t& fullname() const { return name_; }
|
||||
|
||||
void run_defparams(class Design*);
|
||||
void evaluate_parameters(class Design*);
|
||||
|
||||
/* This method generates a non-hierarchical name that is
|
||||
guaranteed to be unique within this scope. */
|
||||
perm_string local_symbol();
|
||||
|
||||
void dump(ostream&) const;
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
/* This method runs the functor on me. Recurse through the
|
||||
children of this node as well. */
|
||||
void run_functor(Design*des, functor_t*fun);
|
||||
|
||||
|
||||
/* This member is used during elaboration to pass defparam
|
||||
assignments from the scope pass to the parameter evaluation
|
||||
step. After that, it is not used. */
|
||||
|
||||
map<pform_name_t,NetExpr*>defparams;
|
||||
|
||||
public:
|
||||
/* After everything is all set up, the code generators like
|
||||
access to these things to make up the parameter lists. */
|
||||
struct param_expr_t {
|
||||
NetExpr*expr;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
|
||||
struct spec_val_t {
|
||||
ivl_variable_type_t type;
|
||||
union {
|
||||
double real_val; // type == IVL_VT_REAL
|
||||
long integer; // type == IVL_VT_BOOL
|
||||
};
|
||||
};
|
||||
map<perm_string,spec_val_t>specparams;
|
||||
|
||||
/* Module instance arrays are collected here for access during
|
||||
the multiple elaboration passes. */
|
||||
typedef svector<NetScope*> scope_vec_t;
|
||||
map<perm_string, scope_vec_t>instance_arrays;
|
||||
|
||||
/* Loop generate uses this as scratch space during
|
||||
elaboration. Expression evaluation can use this to match
|
||||
names. */
|
||||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
perm_string file_;
|
||||
perm_string def_file_;
|
||||
unsigned lineno_;
|
||||
unsigned def_lineno_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
NetEvent *events_;
|
||||
NetNet *signals_;
|
||||
perm_string module_name_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
};
|
||||
|
||||
NetScope*up_;
|
||||
NetScope*sib_;
|
||||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
struct elaborator_work_item_t {
|
||||
explicit elaborator_work_item_t(Design*d)
|
||||
: des(d) { }
|
||||
virtual ~elaborator_work_item_t() { }
|
||||
virtual void elaborate_runrun() =0;
|
||||
protected:
|
||||
Design*des;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3535,10 +3671,23 @@ class Design {
|
||||
NetScope* find_scope(NetScope*, const std::list<hname_t>&path,
|
||||
NetScope::TYPE type = NetScope::MODULE) const;
|
||||
|
||||
/* These members help manage elaboration of scopes. When we
|
||||
get to a point in scope elaboration where we want to put
|
||||
off a scope elaboration, an object of scope_elaboration_t
|
||||
is pushed onto the scope_elaborations list. The scope
|
||||
elaborator will go through this list elaborating scopes
|
||||
until the list is empty. */
|
||||
list<elaborator_work_item_t*>elaboration_work_list;
|
||||
void run_elaboration_work(void);
|
||||
|
||||
set<NetScope*> defparams_later;
|
||||
|
||||
// PARAMETERS
|
||||
|
||||
void run_defparams();
|
||||
void evaluate_parameters();
|
||||
// Look for defparams that never matched, and print warnings.
|
||||
void residual_defparams();
|
||||
|
||||
/* This method locates a signal, starting at a given
|
||||
scope. The name parameter may be partially hierarchical, so
|
||||
@@ -3564,6 +3713,7 @@ class Design {
|
||||
// Iterate over the design...
|
||||
void dump(ostream&) const;
|
||||
void functor(struct functor_t*);
|
||||
void join_islands(void);
|
||||
int emit(struct target_t*) const;
|
||||
|
||||
// This is incremented by elaboration when an error is
|
||||
|
||||
+114
-24
@@ -76,6 +76,46 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
|
||||
#endif
|
||||
}
|
||||
|
||||
NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid)
|
||||
{
|
||||
if (src->data_type() != IVL_VT_REAL)
|
||||
return src;
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid);
|
||||
tmp->data_type(IVL_VT_LOGIC);
|
||||
tmp->set_line(*src);
|
||||
tmp->local_flag(true);
|
||||
|
||||
NetCastInt*cast = new NetCastInt(scope, scope->local_symbol(), wid);
|
||||
cast->set_line(*src);
|
||||
des->add_node(cast);
|
||||
|
||||
connect(cast->pin(0), tmp->pin(0));
|
||||
connect(cast->pin(1), src->pin(0));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
|
||||
{
|
||||
if (src->data_type() == IVL_VT_REAL)
|
||||
return src;
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
|
||||
tmp->data_type(IVL_VT_REAL);
|
||||
tmp->set_line(*src);
|
||||
tmp->local_flag(true);
|
||||
|
||||
NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed());
|
||||
cast->set_line(*src);
|
||||
des->add_node(cast);
|
||||
|
||||
connect(cast->pin(0), tmp->pin(0));
|
||||
connect(cast->pin(1), src->pin(0));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a signed constant to an existing expression. Generate a new
|
||||
* NetEBAdd node that has the input expression and an expression made
|
||||
@@ -123,6 +163,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* make_const_x(unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
NetEConst*resx = new NetEConst(xxx);
|
||||
return resx;
|
||||
}
|
||||
|
||||
NetExpr* condition_reduce(NetExpr*expr)
|
||||
{
|
||||
if (expr->expr_width() == 1)
|
||||
@@ -182,6 +229,72 @@ bool eval_as_long(long&value, NetExpr*expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eval_as_double(double&value, NetExpr*expr)
|
||||
{
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr) ) {
|
||||
value = tmp->value().as_long();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NetECReal*rtmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
value = rtmp->value().as_double();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* At the parser level, a name component it a name with a collection
|
||||
* of expressions. For example foo[N] is the name "foo" and the index
|
||||
* expression "N". This function takes as input the name component and
|
||||
* returns the path component name. It will evaulate the index
|
||||
* expression if it is present.
|
||||
*/
|
||||
hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp)
|
||||
{
|
||||
// No index exression, so the path component is an undecorated
|
||||
// name, for example "foo".
|
||||
if (comp.index.empty())
|
||||
return hname_t(comp.name);
|
||||
|
||||
// The parser will assure that path components will have only
|
||||
// one index. For example, foo[N] is one index, foo[n][m] is two.
|
||||
assert(comp.index.size() == 1);
|
||||
|
||||
const index_component_t&index = comp.index.front();
|
||||
|
||||
// The parser will assure that path components will have only
|
||||
// bit select index expressions. For example, "foo[n]" is OK,
|
||||
// but "foo[n:m]" is not.
|
||||
assert(index.sel == index_component_t::SEL_BIT);
|
||||
|
||||
// Evaluate the bit select to get a number.
|
||||
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
|
||||
ivl_assert(*index.msb, tmp);
|
||||
|
||||
// Now we should have a constant value for the bit select
|
||||
// expression, and we can use it to make the final hname_t
|
||||
// value, for example "foo[5]".
|
||||
if (NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp)) {
|
||||
hname_t res(comp.name, ctmp->value().as_long());
|
||||
delete ctmp;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Darn, the expression doesn't evaluate to a constant. That's
|
||||
// and error to be reported. And make up a fake index value to
|
||||
// return to the caller.
|
||||
cerr << index.msb->get_fileline() << ": error: "
|
||||
<< "Scope index expression is not constant: "
|
||||
<< *index.msb << endl;
|
||||
des->errors += 1;
|
||||
|
||||
delete tmp;
|
||||
return hname_t (comp.name, 0);
|
||||
}
|
||||
|
||||
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path)
|
||||
{
|
||||
@@ -191,30 +304,7 @@ std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
|
||||
for (pform_path_it cur = path.begin() ; cur != path.end(); cur++) {
|
||||
const name_component_t&comp = *cur;
|
||||
if (comp.index.empty()) {
|
||||
res.push_back(hname_t(comp.name));
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(comp.index.size() == 1);
|
||||
const index_component_t&index = comp.index.front();
|
||||
assert(index.sel == index_component_t::SEL_BIT);
|
||||
|
||||
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
|
||||
ivl_assert(*index.msb, tmp);
|
||||
|
||||
if (NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp)) {
|
||||
res.push_back(hname_t(comp.name, ctmp->value().as_long()));
|
||||
delete ctmp;
|
||||
continue;
|
||||
} else {
|
||||
cerr << index.msb->get_fileline() << ": error: "
|
||||
<< "Scope index expression is not constant: "
|
||||
<< *index.msb << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
res.push_back( eval_path_component(des,scope,comp) );
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -64,6 +64,13 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
|
||||
|
||||
extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w);
|
||||
|
||||
/*
|
||||
* Generate the nodes necessary to cast an expression (a net) to a
|
||||
* real value.
|
||||
*/
|
||||
extern NetNet*cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid);
|
||||
extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src);
|
||||
|
||||
/*
|
||||
* Take the input expression and return a variation that assures that
|
||||
* the expression is 1-bit wide and logical. This reflects the needs
|
||||
@@ -102,6 +109,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
|
||||
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
||||
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Make a NetEConst object that contains only X bits.
|
||||
*/
|
||||
extern NetEConst*make_const_x(unsigned long wid);
|
||||
|
||||
/*
|
||||
* In some cases the lval is accessible as a pointer to the head of
|
||||
* a list of NetAssign_ objects. This function returns the width of
|
||||
@@ -138,7 +150,18 @@ void eval_expr(NetExpr*&expr, int prune_width =-1);
|
||||
* down to a constant) then return false and leave value unchanged.
|
||||
*/
|
||||
bool eval_as_long(long&value, NetExpr*expr);
|
||||
bool eval_as_double(double&value, NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Evaluate the component of a scope path to get an hname_t value. Do
|
||||
* the evaluation in the context of the given scope.
|
||||
*/
|
||||
extern hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp);
|
||||
|
||||
/*
|
||||
* Evaluate an entire scope path in the context of the given scope.
|
||||
*/
|
||||
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path);
|
||||
|
||||
|
||||
+11
-8
@@ -30,6 +30,15 @@ unsigned error_count = 0;
|
||||
unsigned warn_count = 0;
|
||||
unsigned long based_size = 0;
|
||||
|
||||
std::ostream& operator << (std::ostream&o, const YYLTYPE&loc)
|
||||
{
|
||||
if (loc.text)
|
||||
o << loc.text << ":";
|
||||
o << loc.first_line;
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
void VLerror(const char*msg)
|
||||
{
|
||||
error_count += 1;
|
||||
@@ -39,20 +48,14 @@ void VLerror(const char*msg)
|
||||
void VLerror(const YYLTYPE&loc, const char*msg)
|
||||
{
|
||||
error_count += 1;
|
||||
if (loc.text)
|
||||
cerr << loc.text << ":";
|
||||
|
||||
cerr << loc.first_line << ": " << msg << endl;
|
||||
cerr << loc << ": " << msg << endl;
|
||||
based_size = 0; /* Clear the base information if we have an error. */
|
||||
}
|
||||
|
||||
void yywarn(const YYLTYPE&loc, const char*msg)
|
||||
{
|
||||
warn_count += 1;
|
||||
if (loc.text)
|
||||
cerr << loc.text << ":";
|
||||
|
||||
cerr << loc.first_line << ": warning: " << msg << endl;
|
||||
cerr << loc << ": warning: " << msg << endl;
|
||||
}
|
||||
|
||||
int VLwrap()
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
# include <ostream>
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
|
||||
/*
|
||||
@@ -39,6 +41,13 @@ struct vlltype {
|
||||
};
|
||||
# define YYLTYPE struct vlltype
|
||||
|
||||
class LineInfo;
|
||||
inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
/* This for compatibility with new and older bison versions. */
|
||||
#ifndef yylloc
|
||||
# define yylloc VLlloc
|
||||
@@ -54,6 +63,8 @@ extern void VLerror(const YYLTYPE&loc, const char*msg);
|
||||
#define yywarn VLwarn
|
||||
extern void VLwarn(const YYLTYPE&loc, const char*msg);
|
||||
|
||||
extern ostream& operator << (ostream&, const YYLTYPE&loc);
|
||||
|
||||
extern unsigned error_count, warn_count;
|
||||
extern unsigned long based_size;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
# include "PUdp.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PSpec.h"
|
||||
# include "discipline.h"
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include <assert.h>
|
||||
@@ -38,7 +39,6 @@
|
||||
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
map<perm_string,Module*> pform_modules;
|
||||
map<perm_string,PUdp*> pform_primitives;
|
||||
|
||||
@@ -82,12 +82,6 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
|
||||
obj->set_file(filename_strings.make(file));
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
/*
|
||||
* The lexical_scope keeps track of the current lexical scope that is
|
||||
* being parsed. The lexical scope may stack, so the current scope may
|
||||
@@ -99,54 +93,103 @@ static PScope* lexical_scope = 0;
|
||||
|
||||
void pform_pop_scope()
|
||||
{
|
||||
lexical_scope = lexical_scope->pscope_parent();
|
||||
if (pform_cur_generate) {
|
||||
assert(pform_cur_generate->lexical_scope);
|
||||
PScope*cur = pform_cur_generate->lexical_scope;
|
||||
pform_cur_generate->lexical_scope = cur->pscope_parent();
|
||||
} else {
|
||||
assert(lexical_scope);
|
||||
lexical_scope = lexical_scope->pscope_parent();
|
||||
}
|
||||
}
|
||||
|
||||
PTask* pform_push_task_scope(char*name)
|
||||
{
|
||||
perm_string task_name = lex_strings.make(name);
|
||||
PTask*task = new PTask(task_name, pform_cur_module);
|
||||
|
||||
// Add the task to the current module
|
||||
pform_cur_module->add_task(task->pscope_name(), task);
|
||||
// Make this the current lexical scope
|
||||
lexical_scope = task;
|
||||
PTask*task;
|
||||
if (pform_cur_generate) {
|
||||
task = new PTask(task_name, pform_cur_generate->lexical_scope);
|
||||
pform_cur_generate->tasks[task->pscope_name()] = task;
|
||||
pform_cur_generate->lexical_scope = task;
|
||||
} else {
|
||||
task = new PTask(task_name, lexical_scope);
|
||||
pform_cur_module->tasks[task->pscope_name()] = task;
|
||||
lexical_scope = task;
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
PFunction* pform_push_function_scope(char*name)
|
||||
{
|
||||
perm_string func_name = lex_strings.make(name);
|
||||
PFunction*func = new PFunction(func_name, lexical_scope);
|
||||
|
||||
// Add the task to the current module
|
||||
pform_cur_module->add_function(func->pscope_name(), func);
|
||||
// Make this the current lexical scope
|
||||
lexical_scope = func;
|
||||
PFunction*func;
|
||||
if (pform_cur_generate) {
|
||||
func = new PFunction(func_name, pform_cur_generate->lexical_scope);
|
||||
pform_cur_generate->funcs[func->pscope_name()] = func;
|
||||
pform_cur_generate->lexical_scope = func;
|
||||
} else {
|
||||
func = new PFunction(func_name, lexical_scope);
|
||||
pform_cur_module->funcs[func->pscope_name()] = func;
|
||||
lexical_scope = func;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
|
||||
{
|
||||
perm_string block_name = lex_strings.make(name);
|
||||
PBlock*block = new PBlock(block_name, lexical_scope, bt);
|
||||
|
||||
// Make this the current lexical scope
|
||||
lexical_scope = block;
|
||||
PBlock*block;
|
||||
if (pform_cur_generate) {
|
||||
block = new PBlock(block_name, pform_cur_generate->lexical_scope, bt);
|
||||
pform_cur_generate->lexical_scope = block;
|
||||
} else {
|
||||
block = new PBlock(block_name, lexical_scope, bt);
|
||||
lexical_scope = block;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static PWire*get_wire_in_scope(perm_string name)
|
||||
PWire*pform_get_wire_in_scope(perm_string name)
|
||||
{
|
||||
/* Note that if we are processing a generate, then the
|
||||
scope depth will be empty because generate schemes
|
||||
cannot be within sub-scopes. Only directly in
|
||||
modules. */
|
||||
if (pform_cur_generate)
|
||||
return pform_cur_generate->get_wire(name);
|
||||
if (pform_cur_generate->lexical_scope)
|
||||
return pform_cur_generate->lexical_scope->wires_find(name);
|
||||
else
|
||||
return pform_cur_generate->wires_find(name);
|
||||
else
|
||||
return lexical_scope->wires_find(name);
|
||||
}
|
||||
|
||||
return lexical_scope->wires_find(name);
|
||||
static void pform_put_wire_in_scope(perm_string name, PWire*net)
|
||||
{
|
||||
if (pform_cur_generate)
|
||||
if (pform_cur_generate->lexical_scope)
|
||||
pform_cur_generate->lexical_scope->wires[name] = net;
|
||||
else
|
||||
pform_cur_generate->wires[name] = net;
|
||||
else
|
||||
lexical_scope->wires[name] = net;
|
||||
}
|
||||
|
||||
static void pform_put_behavior_in_scope(PProcess*pp)
|
||||
{
|
||||
if (pform_cur_generate)
|
||||
if (pform_cur_generate->lexical_scope)
|
||||
pform_cur_generate->lexical_scope->behaviors.push_back(pp);
|
||||
else
|
||||
pform_cur_generate->behaviors.push_back(pp);
|
||||
else
|
||||
lexical_scope->behaviors.push_back(pp);
|
||||
}
|
||||
|
||||
void pform_set_default_nettype(NetNet::Type type,
|
||||
@@ -514,7 +557,7 @@ void pform_endgenerate()
|
||||
if (pform_cur_generate != 0) {
|
||||
assert(cur->scheme_type == PGenerate::GS_CASE_ITEM
|
||||
|| pform_cur_generate->scheme_type != PGenerate::GS_CASE);
|
||||
pform_cur_generate->generates.push_back(cur);
|
||||
pform_cur_generate->generate_schemes.push_back(cur);
|
||||
} else {
|
||||
assert(cur->scheme_type != PGenerate::GS_CASE_ITEM);
|
||||
pform_cur_module->generate_schemes.push_back(cur);
|
||||
@@ -925,7 +968,7 @@ static void pform_set_net_range(perm_string name,
|
||||
ivl_variable_type_t dt,
|
||||
PWSRType rt)
|
||||
{
|
||||
PWire*cur = get_wire_in_scope(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
VLerror("error: name is not a valid net.");
|
||||
return;
|
||||
@@ -1242,7 +1285,7 @@ void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
void pform_make_reginit(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr)
|
||||
{
|
||||
PWire*cur = lexical_scope->wires_find(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
VLerror(li, "internal error: reginit to non-register?");
|
||||
delete expr;
|
||||
@@ -1256,7 +1299,7 @@ void pform_make_reginit(const struct vlltype&li,
|
||||
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
|
||||
FILE_NAME(top, li);
|
||||
|
||||
lexical_scope->behaviors.push_back(top);
|
||||
pform_put_behavior_in_scope(top);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1277,7 +1320,7 @@ void pform_module_define_port(const struct vlltype&li,
|
||||
svector<PExpr*>*range,
|
||||
svector<named_pexpr_t*>*attr)
|
||||
{
|
||||
PWire*cur = lexical_scope->wires_find(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur) {
|
||||
ostringstream msg;
|
||||
msg << name << " definition conflicts with "
|
||||
@@ -1311,7 +1354,7 @@ void pform_module_define_port(const struct vlltype&li,
|
||||
cur->attributes[tmp->name] = tmp->parm;
|
||||
}
|
||||
}
|
||||
lexical_scope->wires[name] = cur;
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1344,7 +1387,7 @@ void pform_makewire(const vlltype&li, perm_string name,
|
||||
ivl_variable_type_t dt,
|
||||
svector<named_pexpr_t*>*attr)
|
||||
{
|
||||
PWire*cur = get_wire_in_scope(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
|
||||
// If this is not implicit ("implicit" meaning we don't know
|
||||
// what the type is yet) then set the type now.
|
||||
@@ -1394,12 +1437,8 @@ void pform_makewire(const vlltype&li, perm_string name,
|
||||
}
|
||||
}
|
||||
|
||||
if (new_wire_flag) {
|
||||
if (pform_cur_generate)
|
||||
pform_cur_generate->wires[name] = cur;
|
||||
else
|
||||
lexical_scope->wires[name] = cur;
|
||||
}
|
||||
if (new_wire_flag)
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1458,7 +1497,7 @@ void pform_makewire(const vlltype&li,
|
||||
SR_NET);
|
||||
}
|
||||
|
||||
PWire*cur = get_wire_in_scope(first->name);
|
||||
PWire*cur = pform_get_wire_in_scope(first->name);
|
||||
if (cur != 0) {
|
||||
PEIdent*lval = new PEIdent(first->name);
|
||||
FILE_NAME(lval, li.text, li.first_line);
|
||||
@@ -1475,11 +1514,11 @@ void pform_makewire(const vlltype&li,
|
||||
void pform_set_port_type(perm_string name, NetNet::PortType pt,
|
||||
const char*file, unsigned lineno)
|
||||
{
|
||||
PWire*cur = lexical_scope->wires_find(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
|
||||
FILE_NAME(cur, file, lineno);
|
||||
lexical_scope->wires[name] = cur;
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
}
|
||||
|
||||
switch (cur->get_port_type()) {
|
||||
@@ -1561,13 +1600,13 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
|
||||
/* Look for a preexisting wire. If it exists, set the
|
||||
port direction. If not, create it. */
|
||||
PWire*curw = lexical_scope->wires_find(name);
|
||||
PWire*curw = pform_get_wire_in_scope(name);
|
||||
if (curw) {
|
||||
curw->set_port_type(pt);
|
||||
} else {
|
||||
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
|
||||
FILE_NAME(curw, file, lineno);
|
||||
lexical_scope->wires[name] = curw;
|
||||
pform_put_wire_in_scope(name, curw);
|
||||
}
|
||||
|
||||
curw->set_signed(signed_flag);
|
||||
@@ -1628,7 +1667,7 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
||||
{
|
||||
PWire*cur = 0;
|
||||
if (pform_cur_generate) {
|
||||
cur = pform_cur_generate->get_wire(name);
|
||||
cur = pform_cur_generate->wires_find(name);
|
||||
} else {
|
||||
cur = lexical_scope->wires_find(name);
|
||||
}
|
||||
@@ -1640,50 +1679,76 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
||||
cur->set_memory_idx(l, r);
|
||||
}
|
||||
|
||||
void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
Module::range_t* pform_parameter_value_range(bool exclude_flag,
|
||||
bool low_open, PExpr*low_expr,
|
||||
bool hig_open, PExpr*hig_expr)
|
||||
{
|
||||
// Detect +-inf and make the the *_open flags false to force
|
||||
// the range interpretation as inf.
|
||||
if (low_expr == 0) low_open = false;
|
||||
if (hig_expr == 0) hig_open = false;
|
||||
|
||||
Module::range_t*tmp = new Module::range_t;
|
||||
tmp->exclude_flag = exclude_flag;
|
||||
tmp->low_open_flag = low_open;
|
||||
tmp->low_expr = low_expr;
|
||||
tmp->high_open_flag = hig_open;
|
||||
tmp->high_expr = hig_expr;
|
||||
tmp->next = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name, ivl_variable_type_t type,
|
||||
bool signed_flag, svector<PExpr*>*range, PExpr*expr,
|
||||
Module::range_t*value_range)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->parameters[name].expr = expr;
|
||||
Module::param_expr_t&parm = pform_cur_module->parameters[name];
|
||||
FILE_NAME(&parm, loc);
|
||||
|
||||
parm.expr = expr;
|
||||
|
||||
parm.type = type;
|
||||
if (range) {
|
||||
assert(range->count() == 2);
|
||||
assert((*range)[0]);
|
||||
assert((*range)[1]);
|
||||
pform_cur_module->parameters[name].msb = (*range)[0];
|
||||
pform_cur_module->parameters[name].lsb = (*range)[1];
|
||||
parm.msb = (*range)[0];
|
||||
parm.lsb = (*range)[1];
|
||||
} else {
|
||||
pform_cur_module->parameters[name].msb = 0;
|
||||
pform_cur_module->parameters[name].lsb = 0;
|
||||
parm.msb = 0;
|
||||
parm.lsb = 0;
|
||||
}
|
||||
pform_cur_module->parameters[name].signed_flag = signed_flag;
|
||||
pform_cur_module->parameters[name].file = filename_strings.make(file);
|
||||
pform_cur_module->parameters[name].lineno = lineno;
|
||||
parm.signed_flag = signed_flag;
|
||||
parm.range = value_range;
|
||||
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
void pform_set_localparam(const struct vlltype&loc,
|
||||
perm_string name, ivl_variable_type_t type,
|
||||
bool signed_flag, svector<PExpr*>*range, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->localparams[name].expr = expr;
|
||||
Module::param_expr_t&parm = pform_cur_module->localparams[name];
|
||||
FILE_NAME(&parm, loc);
|
||||
|
||||
parm.expr = expr;
|
||||
|
||||
parm.type = type;
|
||||
if (range) {
|
||||
assert(range->count() == 2);
|
||||
assert((*range)[0]);
|
||||
assert((*range)[1]);
|
||||
pform_cur_module->localparams[name].msb = (*range)[0];
|
||||
pform_cur_module->localparams[name].lsb = (*range)[1];
|
||||
parm.msb = (*range)[0];
|
||||
parm.lsb = (*range)[1];
|
||||
} else {
|
||||
pform_cur_module->localparams[name].msb = 0;
|
||||
pform_cur_module->localparams[name].lsb = 0;
|
||||
parm.msb = 0;
|
||||
parm.lsb = 0;
|
||||
}
|
||||
pform_cur_module->localparams[name].signed_flag = signed_flag;
|
||||
pform_cur_module->localparams[name].file = filename_strings.make(file);
|
||||
pform_cur_module->localparams[name].lineno = lineno;
|
||||
parm.signed_flag = signed_flag;
|
||||
parm.range = 0;
|
||||
}
|
||||
|
||||
void pform_set_specparam(perm_string name, PExpr*expr)
|
||||
@@ -1695,7 +1760,7 @@ void pform_set_specparam(perm_string name, PExpr*expr)
|
||||
void pform_set_defparam(const pform_name_t&name, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->defparms[name] = expr;
|
||||
pform_cur_module->defparms.push_back(make_pair(name,expr));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1785,13 +1850,13 @@ void pform_set_port_type(const struct vlltype&li,
|
||||
|
||||
static void pform_set_reg_integer(perm_string name)
|
||||
{
|
||||
PWire*cur = lexical_scope->wires_find(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
cur = new PWire(name, NetNet::INTEGER,
|
||||
NetNet::NOT_A_PORT,
|
||||
IVL_VT_LOGIC);
|
||||
cur->set_signed(true);
|
||||
lexical_scope->wires[name] = cur;
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
} else {
|
||||
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(rc);
|
||||
@@ -1819,10 +1884,10 @@ void pform_set_reg_integer(list<perm_string>*names)
|
||||
|
||||
static void pform_set_reg_time(perm_string name)
|
||||
{
|
||||
PWire*cur = lexical_scope->wires_find(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
|
||||
lexical_scope->wires[name] = cur;
|
||||
pform_put_wire_in_scope(name, cur);
|
||||
} else {
|
||||
bool rc = cur->set_wire_type(NetNet::REG);
|
||||
assert(rc);
|
||||
@@ -1881,11 +1946,7 @@ PProcess* pform_make_behavior(PProcess::Type type, Statement*st,
|
||||
delete attr;
|
||||
}
|
||||
|
||||
if (pform_cur_generate)
|
||||
pform_cur_generate->add_behavior(pp);
|
||||
else
|
||||
pform_cur_module->behaviors.push_back(pp);
|
||||
|
||||
pform_put_behavior_in_scope(pp);
|
||||
return pp;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
# include "PUdp.h"
|
||||
# include "PWire.h"
|
||||
# include "verinum.h"
|
||||
# include "discipline.h"
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <list>
|
||||
@@ -115,11 +116,19 @@ struct lgate {
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
|
||||
/* The lexor calls this function to change the default nettype. */
|
||||
extern void pform_set_default_nettype(NetNet::Type net,
|
||||
const char*file,
|
||||
unsigned lineno);
|
||||
|
||||
/*
|
||||
* Look for the given wire in the current lexical scope. If the wire
|
||||
* (including variables of any type) cannot be found in the current
|
||||
* scope, then return 0.
|
||||
*/
|
||||
extern PWire* pform_get_wire_in_scope(perm_string name);
|
||||
|
||||
/*
|
||||
* The parser uses startmodule and endmodule together to build up a
|
||||
* module as it parses it. The startmodule tells the pform code that a
|
||||
@@ -257,16 +266,22 @@ extern void pform_set_attrib(perm_string name, perm_string key,
|
||||
extern void pform_set_type_attrib(perm_string name, const string&key,
|
||||
char*value);
|
||||
|
||||
extern void pform_set_parameter(perm_string name,
|
||||
extern Module::range_t* pform_parameter_value_range(bool exclude_flag,
|
||||
bool low_open, PExpr*low_expr,
|
||||
bool hig_open, PExpr*hig_expr);
|
||||
|
||||
extern void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
ivl_variable_type_t type,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
extern void pform_set_localparam(perm_string name,
|
||||
PExpr*expr, Module::range_t*value_range);
|
||||
extern void pform_set_localparam(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
ivl_variable_type_t type,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
PExpr*expr);
|
||||
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
|
||||
|
||||
/*
|
||||
@@ -350,4 +365,28 @@ extern void pform_dump(ostream&out, Module*mod);
|
||||
*/
|
||||
extern void pform_error_nested_modules();
|
||||
|
||||
/* ** pform_discipline.cc
|
||||
* Functions for handling the parse of natures and disciplines. These
|
||||
* functions are in pform_disciplines.cc
|
||||
*/
|
||||
class discipline_t;
|
||||
|
||||
extern void pform_start_nature(const char*name);
|
||||
extern void pform_end_nature(const struct vlltype&loc);
|
||||
|
||||
extern void pform_nature_access(const struct vlltype&loc, const char*name);
|
||||
|
||||
extern void pform_start_discipline(const char*name);
|
||||
extern void pform_end_discipline(const struct vlltype&loc);
|
||||
|
||||
extern void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain);
|
||||
extern void pform_discipline_potential(const struct vlltype&loc, const char*name);
|
||||
extern void pform_discipline_flow(const struct vlltype&loc, const char*name);
|
||||
|
||||
extern void pform_attach_discipline(const struct vlltype&loc,
|
||||
discipline_t*discipline, list<perm_string>*names);
|
||||
|
||||
extern void pform_dump(ostream&out, const nature_t*);
|
||||
extern void pform_dump(ostream&out, const discipline_t*);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
# include "parse_misc.h"
|
||||
# include "discipline.h"
|
||||
|
||||
map<perm_string,nature_t*> natures;
|
||||
map<perm_string,discipline_t*> disciplines;
|
||||
|
||||
static perm_string nature_name = perm_string::perm_string();
|
||||
static perm_string nature_access = perm_string::perm_string();
|
||||
|
||||
void pform_start_nature(const char*name)
|
||||
{
|
||||
nature_name = lex_strings.make(name);
|
||||
}
|
||||
|
||||
void pform_nature_access(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (nature_access) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many access names for nature "
|
||||
<< nature_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
nature_access = lex_strings.make(name);
|
||||
}
|
||||
|
||||
void pform_end_nature(const struct vlltype&loc)
|
||||
{
|
||||
// The nature access function is required. If it is missing,
|
||||
// then signal an error. For a temporary expedient, we can set
|
||||
// the nature name as the access function, but don't expect it
|
||||
// to work.
|
||||
if (! nature_access) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Missing access name for nature "
|
||||
<< nature_name << "." << endl;
|
||||
error_count += 1;
|
||||
nature_access = nature_name;
|
||||
}
|
||||
|
||||
nature_t*tmp = new nature_t(nature_name, nature_access);
|
||||
natures[nature_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
nature_name = perm_string::perm_string();
|
||||
nature_access = perm_string::perm_string();
|
||||
}
|
||||
|
||||
|
||||
static perm_string discipline_name;
|
||||
static ddomain_t discipline_domain = DD_NONE;
|
||||
static nature_t* discipline_potential = 0;
|
||||
static nature_t* discipline_flow = 0;
|
||||
|
||||
void pform_start_discipline(const char*name)
|
||||
{
|
||||
discipline_name = lex_strings.make(name);
|
||||
discipline_domain = DD_NONE;
|
||||
}
|
||||
|
||||
void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain)
|
||||
{
|
||||
assert(use_domain != DD_NONE);
|
||||
|
||||
if (discipline_domain != DD_NONE) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many domain attributes for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
discipline_domain = use_domain;
|
||||
}
|
||||
|
||||
void pform_discipline_potential(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (discipline_potential) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many potential natures for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
perm_string key = lex_strings.make(name);
|
||||
discipline_potential = natures[key];
|
||||
|
||||
if (discipline_potential == 0) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "nature " << key << " is not declared." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_discipline_flow(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (discipline_flow) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many flow natures for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
perm_string key = lex_strings.make(name);
|
||||
discipline_flow = natures[key];
|
||||
|
||||
if (discipline_flow == 0) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "nature " << key << " is not declared." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_end_discipline(const struct vlltype&loc)
|
||||
{
|
||||
// If the domain is not otherwise specified, then take it to
|
||||
// be continuous if potential or flow natures are given.
|
||||
if (discipline_domain == DD_NONE && (discipline_potential||discipline_flow))
|
||||
discipline_domain = DD_CONTINUOUS;
|
||||
|
||||
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
|
||||
discipline_potential, discipline_flow);
|
||||
disciplines[discipline_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
/* Clear the static variables for the next item. */
|
||||
discipline_name = perm_string::perm_string();
|
||||
discipline_domain = DD_NONE;
|
||||
discipline_potential = 0;
|
||||
discipline_flow = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser uses this function to attach a discipline to a wire. The
|
||||
* wire may be declared by now, or will be declared further later. If
|
||||
* it is already declared, we just attach the discipline. If it is not
|
||||
* declared yet, then this is the declaration and we create the signal
|
||||
* in the current lexical scope.
|
||||
*/
|
||||
void pform_attach_discipline(const struct vlltype&loc,
|
||||
discipline_t*discipline, list<perm_string>*names)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; cur ++ ) {
|
||||
|
||||
PWire* cur_net = pform_get_wire_in_scope(*cur);
|
||||
if (cur_net == 0) {
|
||||
/* Not declared yet, declare it now. */
|
||||
pform_makewire(loc, *cur, NetNet::WIRE,
|
||||
NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
|
||||
cur_net = pform_get_wire_in_scope(*cur);
|
||||
assert(cur_net);
|
||||
}
|
||||
|
||||
if (discipline_t*tmp = cur_net->get_discipline()) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "discipline " << discipline->name()
|
||||
<< " cannot override existing discipline " << tmp->name()
|
||||
<< " on net " << cur_net->basename() << endl;
|
||||
error_count += 1;
|
||||
|
||||
} else {
|
||||
cur_net->set_discipline(discipline);
|
||||
}
|
||||
}
|
||||
}
|
||||
+82
-10
@@ -29,6 +29,7 @@
|
||||
# include "PEvent.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PSpec.h"
|
||||
# include "discipline.h"
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <typeinfo>
|
||||
@@ -128,6 +129,26 @@ ostream& operator<< (ostream&o, const pform_name_t&that)
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator << (std::ostream&out, ddomain_t dom)
|
||||
{
|
||||
switch (dom) {
|
||||
case DD_NONE:
|
||||
out << "no-domain";
|
||||
break;
|
||||
case DD_DISCRETE:
|
||||
out << "discrete";
|
||||
break;
|
||||
case DD_CONTINUOUS:
|
||||
out << "continuous";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
@@ -300,6 +321,10 @@ void PWire::dump(ostream&out, unsigned ind) const
|
||||
out << " signed";
|
||||
}
|
||||
|
||||
if (discipline_) {
|
||||
out << " discipline<" << discipline_->name() << ">";
|
||||
}
|
||||
|
||||
if (port_set_) {
|
||||
if (port_msb_ == 0) {
|
||||
out << " port<scalar>";
|
||||
@@ -912,8 +937,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const
|
||||
(*idx)->dump(out, indent+2);
|
||||
}
|
||||
|
||||
for (list<PGenerate*>::const_iterator idx = generates.begin()
|
||||
; idx != generates.end() ; idx++) {
|
||||
for (list<PGenerate*>::const_iterator idx = generate_schemes.begin()
|
||||
; idx != generate_schemes.end() ; idx++) {
|
||||
(*idx)->dump(out, indent+2);
|
||||
}
|
||||
|
||||
@@ -966,10 +991,9 @@ void Module::dump(ostream&out) const
|
||||
}
|
||||
|
||||
typedef map<perm_string,param_expr_t>::const_iterator parm_iter_t;
|
||||
typedef map<pform_name_t,PExpr*>::const_iterator parm_hiter_t;
|
||||
for (parm_iter_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
out << " parameter ";
|
||||
out << " parameter " << (*cur).second.type << " ";
|
||||
if ((*cur).second.signed_flag)
|
||||
out << "signed ";
|
||||
if ((*cur).second.msb)
|
||||
@@ -977,9 +1001,38 @@ void Module::dump(ostream&out) const
|
||||
<< *(*cur).second.lsb << "] ";
|
||||
out << (*cur).first << " = ";
|
||||
if ((*cur).second.expr)
|
||||
out << *(*cur).second.expr << ";" << endl;
|
||||
out << *(*cur).second.expr;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
out << "/* ERROR */";
|
||||
for (Module::range_t*tmp = (*cur).second.range
|
||||
; tmp ; tmp = tmp->next) {
|
||||
if (tmp->exclude_flag)
|
||||
out << " exclude ";
|
||||
else
|
||||
out << " from ";
|
||||
if (tmp->low_open_flag)
|
||||
out << "(";
|
||||
else
|
||||
out << "[";
|
||||
if (tmp->low_expr)
|
||||
out << *(tmp->low_expr);
|
||||
else if (tmp->low_open_flag==false)
|
||||
out << "-inf";
|
||||
else
|
||||
out << "<nil>";
|
||||
out << ":";
|
||||
if (tmp->high_expr)
|
||||
out << *(tmp->high_expr);
|
||||
else if (tmp->high_open_flag==false)
|
||||
out << "inf";
|
||||
else
|
||||
out << "<nil>";
|
||||
if (tmp->high_open_flag)
|
||||
out << ")";
|
||||
else
|
||||
out << "]";
|
||||
}
|
||||
out << ";" << endl;
|
||||
}
|
||||
|
||||
for (parm_iter_t cur = localparams.begin()
|
||||
@@ -1014,6 +1067,7 @@ void Module::dump(ostream&out) const
|
||||
<< *(*cur).second << ";" << endl;
|
||||
}
|
||||
|
||||
typedef list<Module::named_expr_t>::const_iterator parm_hiter_t;
|
||||
for (parm_hiter_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; cur ++) {
|
||||
out << " defparam " << (*cur).first << " = ";
|
||||
@@ -1035,8 +1089,8 @@ void Module::dump(ostream&out) const
|
||||
|
||||
// Dump the task definitions.
|
||||
typedef map<perm_string,PTask*>::const_iterator task_iter_t;
|
||||
for (task_iter_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++) {
|
||||
for (task_iter_t cur = tasks.begin()
|
||||
; cur != tasks.end() ; cur ++) {
|
||||
out << " task " << (*cur).first << ";" << endl;
|
||||
(*cur).second->dump(out, 6);
|
||||
out << " endtask;" << endl;
|
||||
@@ -1044,8 +1098,8 @@ void Module::dump(ostream&out) const
|
||||
|
||||
// Dump the function definitions.
|
||||
typedef map<perm_string,PFunction*>::const_iterator func_iter_t;
|
||||
for (func_iter_t cur = funcs_.begin()
|
||||
; cur != funcs_.end() ; cur ++) {
|
||||
for (func_iter_t cur = funcs.begin()
|
||||
; cur != funcs.end() ; cur ++) {
|
||||
out << " function " << (*cur).first << ";" << endl;
|
||||
(*cur).second->dump(out, 6);
|
||||
out << " endfunction;" << endl;
|
||||
@@ -1123,3 +1177,21 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
out << "endprimitive" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const nature_t*nat)
|
||||
{
|
||||
out << "nature " << nat->name() << endl;
|
||||
out << " access " << nat->access() << ";" << endl;
|
||||
out << "endnature" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const discipline_t*dis)
|
||||
{
|
||||
out << "discipline " << dis->name() << endl;
|
||||
out << " domain " << dis->domain() << ";" << endl;
|
||||
if (const nature_t*tmp = dis->potential())
|
||||
out << " potential " << tmp->name() << ";" << endl;
|
||||
if (const nature_t*tmp = dis->flow())
|
||||
out << " flow " << tmp->name() << ";" << endl;
|
||||
out << "enddiscipline" << endl;
|
||||
}
|
||||
|
||||
+1
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2007-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -16,17 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: pform_types.cc,v 1.1 2007/05/24 04:07:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
# include "pform_types.h"
|
||||
|
||||
bool operator < (const name_component_t&lef, const name_component_t&rig)
|
||||
{
|
||||
if (lef.name < rig.name)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+26
-6
@@ -1,7 +1,7 @@
|
||||
#ifndef __pform_types_H
|
||||
#define __pform_types_H
|
||||
/*
|
||||
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2007-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -18,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: pform_types.h,v 1.2 2007/06/04 02:19:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
// This for the perm_string type.
|
||||
# include "StringHeap.h"
|
||||
@@ -50,13 +47,36 @@ struct name_component_t {
|
||||
std::list<index_component_t>index;
|
||||
};
|
||||
|
||||
extern bool operator < (const name_component_t&lef, const name_component_t&rig);
|
||||
|
||||
/*
|
||||
* The pform_name_t is the general form for a hierarchical identifier.
|
||||
* The pform_name_t is the general form for a hierarchical
|
||||
* identifier. It is an ordered list of name components. Each name
|
||||
* component is an identifier and an optional list of bit/part
|
||||
* selects. The simplest name component is a simple identifier:
|
||||
*
|
||||
* foo
|
||||
*
|
||||
* The bit/part selects come from the source and are made part of the
|
||||
* name component. A bit select is a single number that may be a bit
|
||||
* select of a vector or a word select of an array:
|
||||
*
|
||||
* foo[5] -- a bit select/word index
|
||||
* foo[6:4] -- a part select
|
||||
*
|
||||
* The index components of a name component are collected into an
|
||||
* ordered list, so there may be many, for example:
|
||||
*
|
||||
* foo[5][6:4] -- a part select of an array word
|
||||
*
|
||||
* The pform_name_t, then, is an ordered list of these name
|
||||
* components. The list of names comes from a hierarchical name in the
|
||||
* source, like this:
|
||||
*
|
||||
* foo[5].bar[6:4] -- a part select of a vector in sub-scope foo[5].
|
||||
*/
|
||||
typedef std::list<name_component_t> pform_name_t;
|
||||
|
||||
|
||||
inline perm_string peek_head_name(const pform_name_t&that)
|
||||
{
|
||||
return that.front().name;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script manually creates a version.h file.
|
||||
#
|
||||
# It is used when creating a MinGW executable from a Cygwin
|
||||
# hosted git repository. It assumes that git is available.
|
||||
#
|
||||
# sh scripts/CREATE_VERSION.sh
|
||||
#
|
||||
|
||||
echo "Building version.h with git describe"
|
||||
tmp=`git describe | sed -e 's;\(.*\);#define VERSION_TAG "\1";'`
|
||||
echo "$tmp" > version.h
|
||||
@@ -7,7 +7,7 @@
|
||||
# sh scripts/MAKE_SNAPSHOT.sh 20080428 ~/tmp
|
||||
#
|
||||
# The above assumes that there is a tag "s20080428" at the point
|
||||
# to be snaphot. (The tag has the "s", but the argument to this
|
||||
# to be snapshot. (The tag has the "s", but the argument to this
|
||||
# script does not have the "s"). This script extracts based on the
|
||||
# tag, uses the temporary directory to stage intermediate results,
|
||||
# and finally creates a file called verilog-20080428.tar.gz that
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# This is a debug conf file that the scripts/devel-stub.sh script uses
|
||||
# to control the ivl core. The contents of this file are normally written
|
||||
# to a temporary file by the driver program, but for devel purposes, where
|
||||
# the driver program is not used, this config substitutes.
|
||||
#
|
||||
# NOTE: DO NOT INSTALL THIS FILE!
|
||||
#
|
||||
generation:2005
|
||||
generation:specify
|
||||
generation:xtypes
|
||||
generation:verilog-ams
|
||||
iwidth:32
|
||||
sys_func:vpi/system.sft
|
||||
sys_func:vpi/va_math.sft
|
||||
warnings:implicit
|
||||
debug:eval_tree
|
||||
debug:elaborate
|
||||
debug:scopes
|
||||
debug:synth2
|
||||
out:a.out
|
||||
ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp
|
||||
sys_func:scripts/devel-stub.sft
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
# This is an example function table.
|
||||
$realtime vpiSysFuncReal
|
||||
|
||||
$verywide vpiSysFuncSized 128 signed
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
# This is a little developer convenience script to run the ivl core program
|
||||
# in place with the stub target. It runs the ivl core verbose, with diagnostic
|
||||
# output files enable, and without the driver program or preprocessor.
|
||||
# It is useful only for development of the ivl core program.
|
||||
#
|
||||
# Run this script in the source directory for the ivl core program so that
|
||||
# the patch to the other components is correct.
|
||||
#
|
||||
# NOTE: DO NOT INSTALL THIS FILE.
|
||||
|
||||
./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl
|
||||
|
||||
echo "*** ivl command completed, rc=$?"
|
||||
@@ -598,7 +598,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
|
||||
delete expr_input;
|
||||
|
||||
/* Detect the case that this is a *synchronous* set/reset. It
|
||||
is not asyncronous because we know the condition is not
|
||||
is not asynchronous because we know the condition is not
|
||||
included in the sensitivity list, but if the if_ case is
|
||||
constant (has no inputs) then we can model this as a
|
||||
synchronous set/reset.
|
||||
|
||||
+127
-12
@@ -555,6 +555,28 @@ extern "C" unsigned ivl_file_table_size()
|
||||
return fn_vector.size();
|
||||
}
|
||||
|
||||
extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value)
|
||||
{
|
||||
if (flag >= net->flags.size()) {
|
||||
if (value == 0)
|
||||
return 0;
|
||||
else
|
||||
net->flags.resize(flag+1, false);
|
||||
}
|
||||
|
||||
int old_flag = net->flags[flag];
|
||||
net->flags[flag] = value != 0;
|
||||
return old_flag;
|
||||
}
|
||||
|
||||
extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag)
|
||||
{
|
||||
if (flag >= net->flags.size())
|
||||
return 0;
|
||||
else
|
||||
return net->flags[flag];
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
|
||||
{
|
||||
assert(net);
|
||||
@@ -782,7 +804,6 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
|
||||
switch (net->type) {
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.base;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -865,6 +886,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
||||
assert(net);
|
||||
switch (net->type) {
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_CAST_INT:
|
||||
case IVL_LPM_CAST_REAL:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.a;
|
||||
|
||||
@@ -918,7 +941,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx <= 1);
|
||||
if (idx == 0)
|
||||
return net->u_.part.a;
|
||||
@@ -1008,20 +1030,19 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
||||
switch (net->type) {
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_SUB:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.q;
|
||||
|
||||
case IVL_LPM_CAST_INT:
|
||||
case IVL_LPM_CAST_REAL:
|
||||
case IVL_LPM_CMP_GE:
|
||||
case IVL_LPM_CMP_GT:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_NE:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_NEE:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_SUB:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.q;
|
||||
|
||||
@@ -1061,7 +1082,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx == 0);
|
||||
return net->u_.part.q;
|
||||
|
||||
@@ -1125,6 +1145,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
return 0;
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_CAST_REAL:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_GE:
|
||||
@@ -1147,6 +1168,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
case IVL_LPM_SHIFTL:
|
||||
case IVL_LPM_SHIFTR:
|
||||
return net->u_.shift.signed_flag;
|
||||
case IVL_LPM_CAST_INT:
|
||||
case IVL_LPM_SIGN_EXT: // Sign extend is always signed.
|
||||
return 1;
|
||||
case IVL_LPM_SFUNC:
|
||||
@@ -1157,7 +1179,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
return 0;
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.signed_flag;
|
||||
case IVL_LPM_REPEAT:
|
||||
return 0;
|
||||
@@ -1338,6 +1359,15 @@ extern "C" ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net)
|
||||
return net->l.sig;
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net)
|
||||
{
|
||||
if (net == 0)
|
||||
return 0;
|
||||
if (net->type_ != __NEXUS_PTR_SWI)
|
||||
return 0;
|
||||
return net->l.swi;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_parameter_basename(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1408,6 +1438,18 @@ extern int ivl_path_source_negedge(ivl_delaypath_t net)
|
||||
return net->negedge ? 1 : 0;
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_process_file(ivl_process_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_process_lineno(ivl_process_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" ivl_process_type_t ivl_process_type(ivl_process_t net)
|
||||
{
|
||||
return net->type_;
|
||||
@@ -1627,6 +1669,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
|
||||
return net->sigs_[idx];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_switches(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->switches.size();
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx)
|
||||
{
|
||||
assert(net);
|
||||
assert(idx < net->switches.size());
|
||||
return net->switches[idx];
|
||||
}
|
||||
|
||||
extern "C" int ivl_scope_time_precision(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -2143,3 +2198,63 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_switch_basename(ivl_switch_t net)
|
||||
{
|
||||
return net->name;
|
||||
}
|
||||
|
||||
extern "C" ivl_scope_t ivl_switch_scope(ivl_switch_t net)
|
||||
{
|
||||
return net->scope;
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net)
|
||||
{
|
||||
return net->type;
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[0];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[1];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[2];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_width(ivl_switch_t net)
|
||||
{
|
||||
return net->width;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_part(ivl_switch_t net)
|
||||
{
|
||||
return net->part;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_offset(ivl_switch_t net)
|
||||
{
|
||||
return net->offset;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_switch_file(ivl_switch_t net)
|
||||
{
|
||||
return net->file;
|
||||
}
|
||||
|
||||
extern "C" ivl_island_t ivl_switch_island(ivl_switch_t net)
|
||||
{
|
||||
return net->island;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_lineno(ivl_switch_t net)
|
||||
{
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
+2
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -17,9 +17,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
||||
@@ -50,6 +47,7 @@ bool dll_target::process(const NetProcTop*net)
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
FILE_NAME(obj, net);
|
||||
|
||||
/* Save the scope of the process. */
|
||||
obj->scope_ = lookup_scope_(net->scope());
|
||||
@@ -745,4 +743,3 @@ void dll_target::proc_while(const NetWhile*net)
|
||||
net->emit_proc_recurse(this);
|
||||
stmt_cur_ = save_cur_;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
# include <stdlib.h>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
#if defined(__WIN32__)
|
||||
|
||||
@@ -380,6 +381,19 @@ static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
|
||||
nex->ptrs_[top-1].l.lpm= net;
|
||||
}
|
||||
|
||||
static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin)
|
||||
{
|
||||
unsigned top = nex->nptr_ + 1;
|
||||
nex->ptrs_ = (struct ivl_nexus_ptr_s*)
|
||||
realloc(nex->ptrs_, top*sizeof(struct ivl_nexus_ptr_s));
|
||||
nex->nptr_ = top;
|
||||
|
||||
nex->ptrs_[top-1].type_= __NEXUS_PTR_SWI;
|
||||
nex->ptrs_[top-1].drive0 = IVL_DR_HiZ;
|
||||
nex->ptrs_[top-1].drive1 = IVL_DR_HiZ;
|
||||
nex->ptrs_[top-1].pin_ = pin;
|
||||
nex->ptrs_[top-1].l.swi= net;
|
||||
}
|
||||
|
||||
void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
|
||||
{
|
||||
@@ -431,6 +445,11 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net)
|
||||
{
|
||||
scope->switches.push_back(net);
|
||||
}
|
||||
|
||||
ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
|
||||
const char*name)
|
||||
{
|
||||
@@ -470,8 +489,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
cur_par->file = (*cur_pit).second.get_file();
|
||||
cur_par->lineno = (*cur_pit).second.get_lineno();
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -484,8 +503,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
cur_par->file = (*cur_pit).second.get_file();
|
||||
cur_par->lineno = (*cur_pit).second.get_lineno();
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -520,6 +539,13 @@ void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp)
|
||||
|
||||
}
|
||||
|
||||
if (expr_ == 0) {
|
||||
cerr << etmp->get_fileline() << ": internal error: "
|
||||
<< "Parameter expression not reduced to constant? "
|
||||
<< *etmp << endl;
|
||||
}
|
||||
ivl_assert(*etmp, expr_);
|
||||
|
||||
cur_par->value = expr_;
|
||||
expr_ = 0;
|
||||
}
|
||||
@@ -621,6 +647,13 @@ int dll_target::end_design(const Design*)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void dll_target::switch_attributes(struct ivl_switch_s *obj,
|
||||
const NetNode*net)
|
||||
{
|
||||
obj->nattr = net->attr_cnt();
|
||||
obj->attr = fill_in_attributes(net);
|
||||
}
|
||||
|
||||
void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
|
||||
const NetNode*net)
|
||||
{
|
||||
@@ -1008,6 +1041,56 @@ void dll_target::logic(const NetLogic*net)
|
||||
scope_add_logic(scope, obj);
|
||||
}
|
||||
|
||||
bool dll_target::tran(const NetTran*net)
|
||||
{
|
||||
struct ivl_switch_s*obj = new struct ivl_switch_s;
|
||||
obj->type = net->type();
|
||||
obj->width = 0;
|
||||
obj->part = 0;
|
||||
obj->offset = 0;
|
||||
obj->name = net->name();
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
obj->island = net->island;
|
||||
assert(obj->scope);
|
||||
assert(obj->island);
|
||||
|
||||
const Nexus*nex;
|
||||
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[0] = nex->t_cookie();
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[1] = nex->t_cookie();
|
||||
|
||||
nexus_switch_add(obj->pins[0], obj, 0);
|
||||
nexus_switch_add(obj->pins[1], obj, 1);
|
||||
|
||||
if (net->pin_count() > 2) {
|
||||
nex = net->pin(2).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[2] = nex->t_cookie();
|
||||
nexus_switch_add(obj->pins[2], obj, 2);
|
||||
} else {
|
||||
obj->pins[2] = 0;
|
||||
}
|
||||
|
||||
if (obj->type == IVL_SW_TRAN_VP) {
|
||||
obj->width = net->vector_width();
|
||||
obj->part = net->part_width();
|
||||
obj->offset= net->part_offset();
|
||||
}
|
||||
|
||||
obj->file = net->get_file();
|
||||
obj->lineno = net->get_lineno();
|
||||
|
||||
switch_attributes(obj, net);
|
||||
scope_add_switch(obj->scope, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dll_target::sign_extend(const NetSignExtend*net)
|
||||
{
|
||||
struct ivl_lpm_s*obj = new struct ivl_lpm_s;
|
||||
@@ -1475,6 +1558,71 @@ void dll_target::lpm_clshift(const NetCLShift*net)
|
||||
scope_add_lpm(obj->scope, obj);
|
||||
}
|
||||
|
||||
bool dll_target::lpm_cast_int(const NetCastInt*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_CAST_INT;
|
||||
obj->name = net->name(); // NetCastInt names are permallocated
|
||||
assert(net->scope());
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
obj->width = net->width();
|
||||
|
||||
const Nexus*nex;
|
||||
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.arith.q = nex->t_cookie();
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->u_.arith.a = nex->t_cookie();
|
||||
|
||||
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
make_lpm_delays_(obj, net);
|
||||
|
||||
scope_add_lpm(obj->scope, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dll_target::lpm_cast_real(const NetCastReal*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_CAST_REAL;
|
||||
obj->name = net->name(); // NetCastReal names are permallocated
|
||||
assert(net->scope());
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
obj->width = 0;
|
||||
obj->u_.arith.signed_flag = net->signed_flag()? 1 : 0;
|
||||
|
||||
const Nexus*nex;
|
||||
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.arith.q = nex->t_cookie();
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->u_.arith.a = nex->t_cookie();
|
||||
|
||||
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
make_lpm_delays_(obj, net);
|
||||
|
||||
scope_add_lpm(obj->scope, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make out of the NetCompare object an ivl_lpm_s object. The
|
||||
* comparators in ivl_target do not support < or <=, but they can be
|
||||
@@ -1806,7 +1954,7 @@ void dll_target::lpm_mux(const NetMux*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_MUX;
|
||||
obj->name = net->name(); // The NetMux perallocates its name.
|
||||
obj->name = net->name(); // The NetMux permallocates its name.
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
@@ -1930,9 +2078,6 @@ bool dll_target::part_select(const NetPartSelect*net)
|
||||
case NetPartSelect::PV:
|
||||
obj->type = IVL_LPM_PART_PV;
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
obj->type = IVL_LPM_PART_BI;
|
||||
break;
|
||||
}
|
||||
obj->name = net->name(); // NetPartSelect names are permallocated.
|
||||
assert(net->scope());
|
||||
@@ -1986,35 +2131,12 @@ bool dll_target::part_select(const NetPartSelect*net)
|
||||
obj->u_.part.a = nex->t_cookie();
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
/* For now, handle this exactly the same as a PV */
|
||||
|
||||
/* NetPartSelect:pin(0) is the output pin. */
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.q = nex->t_cookie();
|
||||
|
||||
/* NetPartSelect:pin(1) is the input pin. */
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.a = nex->t_cookie();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
|
||||
/* If the device is a PART_BI, then the "input" is also a
|
||||
strength aware output, so attach it to the nexus with
|
||||
strong driver. */
|
||||
if (obj->type == IVL_LPM_PART_BI)
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
else
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
/* The select input is optional. */
|
||||
if (obj->u_.part.s)
|
||||
@@ -2252,8 +2374,7 @@ void dll_target::signal(const NetNet*net)
|
||||
object, or creating the sigs_ array if this is the first
|
||||
signal. */
|
||||
obj->scope_ = find_scope(des_, net->scope());
|
||||
obj->file = perm_string::literal("N/A");
|
||||
obj->lineno = 0;
|
||||
FILE_NAME(obj, net);
|
||||
assert(obj->scope_);
|
||||
|
||||
if (obj->scope_->nsigs_ == 0) {
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
|
||||
# include "target.h"
|
||||
# include "ivl_target.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include "StringHeap.h"
|
||||
# include "netlist.h"
|
||||
# include <vector>
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#include <windows.h>
|
||||
@@ -67,12 +69,15 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
bool bufz(const NetBUFZ*);
|
||||
void event(const NetEvent*);
|
||||
void logic(const NetLogic*);
|
||||
bool tran(const NetTran*);
|
||||
bool ureduce(const NetUReduce*);
|
||||
void net_case_cmp(const NetCaseCmp*);
|
||||
void udp(const NetUDP*);
|
||||
void lpm_abs(const NetAbs*);
|
||||
void lpm_add_sub(const NetAddSub*);
|
||||
bool lpm_array_dq(const NetArrayDq*);
|
||||
bool lpm_cast_int(const NetCastInt*);
|
||||
bool lpm_cast_real(const NetCastReal*);
|
||||
void lpm_clshift(const NetCLShift*);
|
||||
void lpm_compare(const NetCompare*);
|
||||
void lpm_divide(const NetDivide*);
|
||||
@@ -146,6 +151,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
ivl_scope_t lookup_scope_(const NetScope*scope);
|
||||
|
||||
ivl_attribute_s* fill_in_attributes(const Attrib*net);
|
||||
void switch_attributes(struct ivl_switch_s *obj, const NetNode*net);
|
||||
void logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net);
|
||||
|
||||
private:
|
||||
@@ -445,6 +451,23 @@ struct ivl_net_logic_s {
|
||||
ivl_expr_t delay[3];
|
||||
};
|
||||
|
||||
struct ivl_switch_s {
|
||||
ivl_switch_type_t type;
|
||||
unsigned width;
|
||||
unsigned part;
|
||||
unsigned offset;
|
||||
|
||||
perm_string name;
|
||||
ivl_scope_t scope;
|
||||
ivl_island_t island;
|
||||
|
||||
struct ivl_attribute_s*attr;
|
||||
unsigned nattr;
|
||||
|
||||
ivl_nexus_t pins[3];
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
/*
|
||||
* UDP definition.
|
||||
@@ -481,12 +504,14 @@ struct ivl_nexus_ptr_s {
|
||||
ivl_net_logic_t log; /* type 1 */
|
||||
ivl_net_const_t con; /* type 2 */
|
||||
ivl_lpm_t lpm; /* type 3 */
|
||||
ivl_switch_t swi; /* type 4 */
|
||||
} l;
|
||||
};
|
||||
# define __NEXUS_PTR_SIG 0
|
||||
# define __NEXUS_PTR_LOG 1
|
||||
# define __NEXUS_PTR_CON 2
|
||||
# define __NEXUS_PTR_LPM 3
|
||||
# define __NEXUS_PTR_SWI 4
|
||||
|
||||
/*
|
||||
* NOTE: ONLY allocate ivl_nexus_s objects with the included "new" operator.
|
||||
@@ -514,7 +539,7 @@ struct ivl_parameter_s {
|
||||
unsigned lineno;
|
||||
};
|
||||
/*
|
||||
* All we know about a process it its type (initial or always) and the
|
||||
* All we know about a process is its type (initial or always) and the
|
||||
* single statement that is it. A process also has a scope, although
|
||||
* that generally only matters for VPI calls.
|
||||
*/
|
||||
@@ -522,6 +547,8 @@ struct ivl_process_s {
|
||||
ivl_process_type_t type_;
|
||||
ivl_scope_t scope_;
|
||||
ivl_statement_t stmt_;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
|
||||
struct ivl_attribute_s*attr;
|
||||
unsigned nattr;
|
||||
@@ -567,6 +594,8 @@ struct ivl_scope_s {
|
||||
unsigned ports;
|
||||
ivl_signal_t*port;
|
||||
|
||||
std::vector<ivl_switch_t>switches;
|
||||
|
||||
signed int time_precision :8;
|
||||
signed int time_units :8;
|
||||
|
||||
@@ -730,4 +759,22 @@ static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info)
|
||||
scope->def_lineno = info->get_def_lineno();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info)
|
||||
{
|
||||
net->file = info->get_file();
|
||||
net->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_process_t net, const LineInfo*info)
|
||||
{
|
||||
net->file = info->get_file();
|
||||
net->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_signal_t net, const LineInfo*info)
|
||||
{
|
||||
net->file = info->get_file();
|
||||
net->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -61,6 +61,13 @@ void target_t::logic(const NetLogic*)
|
||||
"Unhandled logic gate" << endl;
|
||||
}
|
||||
|
||||
bool target_t::tran(const NetTran*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
<< "TRAN devices not supported." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool target_t::bufz(const NetBUFZ*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -100,6 +107,20 @@ bool target_t::lpm_array_dq(const NetArrayDq*)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool target_t::lpm_cast_int(const NetCastInt*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetCastInt." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool target_t::lpm_cast_real(const NetCastReal*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetCastReal." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::lpm_clshift(const NetCLShift*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
||||
@@ -72,6 +72,8 @@ struct target_t {
|
||||
virtual void lpm_add_sub(const NetAddSub*);
|
||||
virtual bool lpm_array_dq(const NetArrayDq*);
|
||||
virtual void lpm_clshift(const NetCLShift*);
|
||||
virtual bool lpm_cast_int(const NetCastInt*);
|
||||
virtual bool lpm_cast_real(const NetCastReal*);
|
||||
virtual void lpm_compare(const NetCompare*);
|
||||
virtual void lpm_divide(const NetDivide*);
|
||||
virtual void lpm_modulo(const NetModulo*);
|
||||
@@ -86,6 +88,7 @@ struct target_t {
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(const NetLogic*);
|
||||
virtual bool tran(const NetTran*);
|
||||
virtual bool ureduce(const NetUReduce*); /* unary reduction operator */
|
||||
virtual bool bufz(const NetBUFZ*);
|
||||
virtual void udp(const NetUDP*);
|
||||
|
||||
@@ -160,7 +160,7 @@ device pins are connected.
|
||||
.SH EXAMPLES
|
||||
|
||||
.TB 8
|
||||
.I COMPILING WITH XILINX FOUNDATION/iSE
|
||||
.I COMPILING WITH XILINX FOUNDATION/ISE
|
||||
Compile a single-file design with command line tools like so:
|
||||
|
||||
.nf
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.11 2004/02/10 19:25:01 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep null.tgt
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.20 2007/02/06 05:07:32 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep stub.tgt
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
@@ -51,7 +50,7 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = stub.o expression.o statement.o
|
||||
O = stub.o expression.o statement.o switches.o
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
|
||||
@@ -178,6 +178,11 @@ void show_unary_expression(ivl_expr_t net, unsigned ind)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ivl_expr_opcode(net) == '!' && ivl_expr_type(net)==IVL_VT_REAL) {
|
||||
fprintf(out, "%*sERROR: Real argument to unary ! !?\n", ind,"");
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
|
||||
name, width, sign, vt);
|
||||
show_expression(ivl_expr_oper1(net), ind+4);
|
||||
|
||||
@@ -35,6 +35,15 @@ extern FILE*out;
|
||||
*/
|
||||
extern int stub_errors;
|
||||
|
||||
/*
|
||||
* This function finds the vector width of a signal. It relies on the
|
||||
* assumption that all the signal inputs to the nexus have the same
|
||||
* width. The ivl_target API should assert that condition.
|
||||
*/
|
||||
extern unsigned width_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* Show the details of the expression.
|
||||
*/
|
||||
@@ -45,6 +54,8 @@ extern void show_expression(ivl_expr_t net, unsigned ind);
|
||||
*/
|
||||
extern void show_statement(ivl_statement_t net, unsigned ind);
|
||||
|
||||
extern void show_switch(ivl_switch_t net);
|
||||
|
||||
/*
|
||||
*/
|
||||
extern const char*data_type_string(ivl_variable_type_t vtype);
|
||||
|
||||
@@ -288,7 +288,7 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||
break;
|
||||
|
||||
case IVL_ST_DELAY:
|
||||
fprintf(out, "%*s#%llu\n", ind, "", ivl_stmt_delay_val(net));
|
||||
fprintf(out, "%*s#%" PRIu64 "\n", ind, "", ivl_stmt_delay_val(net));
|
||||
show_statement(ivl_stmt_sub_stmt(net), ind+2);
|
||||
break;
|
||||
|
||||
|
||||
+67
-37
@@ -240,6 +240,56 @@ static void show_lpm_array(ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_cast_int(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
||||
fprintf(out, " LPM_CAST_INT %s: <width=%u>\n",
|
||||
ivl_lpm_basename(net), width);
|
||||
|
||||
ivl_nexus_t q = ivl_lpm_q(net,0);
|
||||
ivl_nexus_t a = ivl_lpm_data(net,0);
|
||||
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
|
||||
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
|
||||
|
||||
if (type_of_nexus(q) == IVL_VT_REAL) {
|
||||
fprintf(out, " ERROR: Data type of Q is %s, expecting !real\n",
|
||||
data_type_string(type_of_nexus(q)));
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
if (type_of_nexus(a) != IVL_VT_REAL) {
|
||||
fprintf(out, " ERROR: Data type of A is %s, expecting real\n",
|
||||
data_type_string(type_of_nexus(a)));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_cast_real(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
||||
fprintf(out, " LPM_CAST_REAL %s: <width=%u>\n",
|
||||
ivl_lpm_basename(net), width);
|
||||
|
||||
ivl_nexus_t q = ivl_lpm_q(net,0);
|
||||
ivl_nexus_t a = ivl_lpm_data(net,0);
|
||||
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
|
||||
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
|
||||
|
||||
if (type_of_nexus(q) != IVL_VT_REAL) {
|
||||
fprintf(out, " ERROR: Data type of Q is %s, expecting real\n",
|
||||
data_type_string(type_of_nexus(q)));
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
if (type_of_nexus(a) == IVL_VT_REAL) {
|
||||
fprintf(out, " ERROR: Data type of A is %s, expecting !real\n",
|
||||
data_type_string(type_of_nexus(a)));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_divide(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
@@ -555,38 +605,6 @@ static void show_lpm_part(ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
ivl_nexus_t port_p = ivl_lpm_q(net,0);
|
||||
ivl_nexus_t port_v = ivl_lpm_data(net,0);
|
||||
|
||||
fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
|
||||
ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
|
||||
fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
|
||||
fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
|
||||
width_of_nexus(port_v));
|
||||
|
||||
|
||||
/* The data(0) port must be large enough for the part select. */
|
||||
if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
|
||||
fprintf(out, " ERROR: Part select is out of range."
|
||||
" Data nexus width=%u, width+base=%u\n",
|
||||
width_of_nexus(ivl_lpm_data(net,0)), width+base);
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
/* The Q vector must be exactly the width of the part select. */
|
||||
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
|
||||
fprintf(out, " ERROR: Part select input mismatch."
|
||||
" Nexus width=%u, expect width=%u\n",
|
||||
width_of_nexus(ivl_lpm_q(net,0)), width);
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The reduction operators have similar characteristics and are
|
||||
* displayed here.
|
||||
@@ -834,6 +852,14 @@ static void show_lpm(ivl_lpm_t net)
|
||||
show_lpm_array(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_CAST_INT:
|
||||
show_lpm_cast_int(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_CAST_REAL:
|
||||
show_lpm_cast_real(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_DIVIDE:
|
||||
show_lpm_divide(net);
|
||||
break;
|
||||
@@ -905,11 +931,6 @@ static void show_lpm(ivl_lpm_t net)
|
||||
show_lpm_part(net);
|
||||
break;
|
||||
|
||||
/* The BI part select is slightly special. */
|
||||
case IVL_LPM_PART_BI:
|
||||
show_lpm_part_bi(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_REPEAT:
|
||||
show_lpm_repeat(net);
|
||||
break;
|
||||
@@ -1059,6 +1080,7 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
|
||||
ivl_net_logic_t log;
|
||||
ivl_lpm_t lpm;
|
||||
ivl_signal_t sig;
|
||||
ivl_switch_t swt;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
|
||||
@@ -1092,6 +1114,11 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
|
||||
ivl_scope_name(ivl_lpm_scope(lpm)),
|
||||
ivl_lpm_basename(lpm), dr0, dr1);
|
||||
|
||||
} else if ((swt = ivl_nexus_ptr_switch(ptr))) {
|
||||
fprintf(out, " SWITCH %s.%s\n",
|
||||
ivl_scope_name(ivl_switch_scope(swt)),
|
||||
ivl_switch_basename(swt));
|
||||
|
||||
} else if ((con = ivl_nexus_ptr_con(ptr))) {
|
||||
signal_nexus_const(net, ptr, con);
|
||||
|
||||
@@ -1478,6 +1505,9 @@ static int show_scope(ivl_scope_t net, void*x)
|
||||
for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1)
|
||||
show_lpm(ivl_scope_lpm(net, idx));
|
||||
|
||||
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1)
|
||||
show_switch(ivl_scope_switch(net, idx));
|
||||
|
||||
switch (ivl_scope_type(net)) {
|
||||
case IVL_SCT_FUNCTION:
|
||||
case IVL_SCT_TASK:
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
# include "config.h"
|
||||
# include "priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
void show_switch(ivl_switch_t net)
|
||||
{
|
||||
const char*name = ivl_switch_basename(net);
|
||||
int has_enable = 0;
|
||||
|
||||
switch (ivl_switch_type(net)) {
|
||||
case IVL_SW_TRAN:
|
||||
fprintf(out, " tran %s", name);
|
||||
break;
|
||||
case IVL_SW_RTRAN:
|
||||
fprintf(out, " rtran %s", name);
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
fprintf(out, " tranif0 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_RTRANIF0:
|
||||
fprintf(out, " rtranif0 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
fprintf(out, " tranif1 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_RTRANIF1:
|
||||
fprintf(out, " rtranif1 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
fprintf(out, " tran(VP wid=%u, part=%u, off=%u) %s",
|
||||
ivl_switch_width(net), ivl_switch_part(net),
|
||||
ivl_switch_offset(net), name);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(out, " island=%p\n", ivl_switch_island(net));
|
||||
|
||||
ivl_nexus_t nexa = ivl_switch_a(net);
|
||||
const char*nex_name = nexa? ivl_nexus_name(nexa) : "";
|
||||
ivl_variable_type_t nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
|
||||
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
|
||||
|
||||
ivl_nexus_t nexb = ivl_switch_b(net);
|
||||
nex_name = nexb? ivl_nexus_name(nexb) : "";
|
||||
ivl_variable_type_t nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
|
||||
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
|
||||
|
||||
/* The A/B pins of the switch must be present, and must match. */
|
||||
if (nex_type_a == IVL_VT_NO_TYPE) {
|
||||
fprintf(out, " A: ERROR: Type missing for pin A\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (nex_type_b == IVL_VT_NO_TYPE) {
|
||||
fprintf(out, " B: ERROR: Type missing for pin B\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (nex_type_a != nex_type_b) {
|
||||
fprintf(out, " A/B: ERROR: Type mismatch between pins A and B\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
|
||||
/* The TRAN_VP nodes are special in that the specific
|
||||
width matters for each port and should be exactly
|
||||
right for both. */
|
||||
if (width_of_nexus(nexa) != ivl_switch_width(net)) {
|
||||
fprintf(out, " A: ERROR: part vector nexus "
|
||||
"width=%u, expecting width=%u\n",
|
||||
width_of_nexus(nexa), ivl_switch_width(net));
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (width_of_nexus(nexb) != ivl_switch_part(net)) {
|
||||
fprintf(out, " B: ERROR: part select nexus "
|
||||
"width=%u, expecting width=%u\n",
|
||||
width_of_nexus(nexb), ivl_switch_part(net));
|
||||
stub_errors += 1;
|
||||
}
|
||||
} else {
|
||||
/* All other TRAN nodes will have matching vector
|
||||
widths, but the actual value doesn't matter. */
|
||||
if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
|
||||
fprintf(out, " A/B: ERROR: Width of ports don't match"
|
||||
": A=%u, B=%u\n",
|
||||
width_of_nexus(nexa), width_of_nexus(nexb));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_enable) {
|
||||
ivl_nexus_t nexe = ivl_switch_enable(net);
|
||||
nex_name = nexe? ivl_nexus_name(nexe) : "";
|
||||
fprintf(out, " E: %s\n", nex_name);
|
||||
if (width_of_nexus(nexe) != 1) {
|
||||
fprintf(out, " E: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nexe));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#
|
||||
# This source code is free software; you can redistribute it
|
||||
# and/or modify it in source code form under the terms of the GNU
|
||||
# Library 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 Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this program; if not, write to the Free
|
||||
# Software Foundation, Inc.,
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
|
||||
prefix = @prefix@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
srcdir = @srcdir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CXX = @CXX@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@
|
||||
CXXFLAGS = -Wall @CXXFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep vhdl.tgt vhdl.conf
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
%.o: %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \
|
||||
stmt.o expr.o lpm.o display.o support.o cast.o logic.o
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
TGTDEPLIBS=../libivl.a
|
||||
else
|
||||
TGTLDFLAGS=
|
||||
TGTDEPLIBS=
|
||||
endif
|
||||
|
||||
vhdl.tgt: $O $(TGTDEPLIBS)
|
||||
$(CXX) @shared@ -o $@ $O $(TGTLDFLAGS)
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
|
||||
clean:
|
||||
rm -rf $(O) dep vhdl.tgt
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.status config.log config.cache vhdl_config.h
|
||||
|
||||
check: all
|
||||
|
||||
install: all installdirs $(libdir)/ivl/vhdl.tgt $(libdir)/ivl/vhdl.conf
|
||||
|
||||
$(libdir)/ivl/vhdl.tgt: ./vhdl.tgt
|
||||
$(INSTALL_PROGRAM) ./vhdl.tgt $(libdir)/ivl/vhdl.tgt
|
||||
|
||||
$(libdir)/ivl/vhdl.conf: vhdl.conf
|
||||
$(INSTALL_DATA) $< $(libdir)/ivl/vhdl.conf
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(libdir)/ivl
|
||||
|
||||
uninstall:
|
||||
rm -f $(libdir)/ivl/vhdl.tgt $(libdir)/ivl/vhdl.conf
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Generate code to convert between VHDL types.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_syntax.hh"
|
||||
|
||||
#include "vhdl_target.h"
|
||||
#include "support.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
|
||||
{
|
||||
//std::cout << "Cast: from=" << type_->get_string()
|
||||
// << " (" << type_->get_width() << ") "
|
||||
// << " to=" << to->get_string() << " ("
|
||||
// << to->get_width() << ")" << std::endl;
|
||||
|
||||
if (to->get_name() == type_->get_name()) {
|
||||
if (to->get_width() == type_->get_width())
|
||||
return this; // Identical
|
||||
else
|
||||
return resize(to->get_width());
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_BOOLEAN) {
|
||||
if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
// '1' is true all else are false
|
||||
vhdl_const_bit *one = new vhdl_const_bit('1');
|
||||
return new vhdl_binop_expr
|
||||
(this, VHDL_BINOP_EQ, one, vhdl_type::boolean());
|
||||
}
|
||||
else if (type_->get_name() == VHDL_TYPE_UNSIGNED) {
|
||||
// Need to use a support function for this conversion
|
||||
require_support_function(SF_UNSIGNED_TO_BOOLEAN);
|
||||
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN),
|
||||
vhdl_type::boolean());
|
||||
conv->add_expr(this);
|
||||
return conv;
|
||||
}
|
||||
else if (type_->get_name() == VHDL_TYPE_SIGNED) {
|
||||
require_support_function(SF_SIGNED_TO_BOOLEAN);
|
||||
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN),
|
||||
vhdl_type::boolean());
|
||||
conv->add_expr(this);
|
||||
return conv;
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_INTEGER) {
|
||||
vhdl_fcall *conv;
|
||||
if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
require_support_function(SF_LOGIC_TO_INTEGER);
|
||||
conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER),
|
||||
vhdl_type::integer());
|
||||
}
|
||||
else
|
||||
conv = new vhdl_fcall("To_Integer", new vhdl_type(*to));
|
||||
|
||||
conv->add_expr(this);
|
||||
|
||||
return conv;
|
||||
}
|
||||
else if ((to->get_name() == VHDL_TYPE_UNSIGNED
|
||||
|| to->get_name() == VHDL_TYPE_SIGNED
|
||||
|| to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) &&
|
||||
type_->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
|
||||
vhdl_expr *others = to->get_width() == 1 ? NULL : new vhdl_const_bit('0');
|
||||
vhdl_bit_spec_expr *bs =
|
||||
new vhdl_bit_spec_expr(new vhdl_type(*to), others);
|
||||
bs->add_bit(0, this);
|
||||
|
||||
return bs;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_STD_LOGIC &&
|
||||
type_->get_name() == VHDL_TYPE_BOOLEAN) {
|
||||
require_support_function(SF_BOOLEAN_TO_LOGIC);
|
||||
|
||||
vhdl_fcall *ah =
|
||||
new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC),
|
||||
vhdl_type::std_logic());
|
||||
ah->add_expr(this);
|
||||
|
||||
return ah;
|
||||
}
|
||||
else {
|
||||
// We have to cast the expression before resizing or the
|
||||
// wrong sign bit may be extended (i.e. when casting between
|
||||
// signed/unsigned *and* resizing)
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to));
|
||||
conv->add_expr(this);
|
||||
|
||||
if (to->get_width() != type_->get_width())
|
||||
return conv->resize(to->get_width());
|
||||
else
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_expr::resize(int newwidth)
|
||||
{
|
||||
vhdl_type *rtype;
|
||||
assert(type_);
|
||||
if (type_->get_name() == VHDL_TYPE_SIGNED)
|
||||
rtype = vhdl_type::nsigned(newwidth);
|
||||
else if (type_->get_name() == VHDL_TYPE_UNSIGNED)
|
||||
rtype = vhdl_type::nunsigned(newwidth);
|
||||
else
|
||||
return this; // Doesn't make sense to resize non-vector type
|
||||
|
||||
vhdl_fcall *resize = new vhdl_fcall("Resize", rtype);
|
||||
resize->add_expr(this);
|
||||
resize->add_expr(new vhdl_const_int(newwidth));
|
||||
|
||||
return resize;
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_const_int::cast(const vhdl_type *to)
|
||||
{
|
||||
if (to->get_name() == VHDL_TYPE_SIGNED
|
||||
|| to->get_name() == VHDL_TYPE_UNSIGNED) {
|
||||
|
||||
const char *fname = to->get_name() == VHDL_TYPE_SIGNED
|
||||
? "To_Signed" : "To_Unsigned";
|
||||
vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(*to));
|
||||
conv->add_expr(this);
|
||||
conv->add_expr(new vhdl_const_int(to->get_width()));
|
||||
|
||||
return conv;
|
||||
}
|
||||
else
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
|
||||
int vhdl_const_bits::bits_to_int() const
|
||||
{
|
||||
char msb = value_[value_.size() - 1];
|
||||
int result = 0, bit;
|
||||
for (int i = sizeof(int)*8 - 1; i >= 0; i--) {
|
||||
if (i > (int)value_.size() - 1)
|
||||
bit = msb == '1' ? 1 : 0;
|
||||
else
|
||||
bit = value_[i] == '1' ? 1 : 0;
|
||||
result = (result << 1) | bit;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to)
|
||||
{
|
||||
if (to->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
// VHDL won't let us cast directly between a vector and
|
||||
// a scalar type
|
||||
// But we don't need to here as we have the bits available
|
||||
|
||||
// Take the least significant bit
|
||||
char lsb = value_[0];
|
||||
|
||||
return new vhdl_const_bit(lsb);
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) {
|
||||
// Don't need to do anything
|
||||
return this;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_SIGNED
|
||||
|| to->get_name() == VHDL_TYPE_UNSIGNED) {
|
||||
|
||||
// Extend with sign bit
|
||||
value_.resize(to->get_width(), value_[0]);
|
||||
return this;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_INTEGER)
|
||||
return new vhdl_const_int(bits_to_int());
|
||||
else
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to)
|
||||
{
|
||||
if (to->get_name() == VHDL_TYPE_INTEGER)
|
||||
return new vhdl_const_int(bit_ == '1' ? 1 : 0);
|
||||
else if (to->get_name() == VHDL_TYPE_BOOLEAN)
|
||||
return new vhdl_const_bool(bit_ == '1');
|
||||
else
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(vhdl.cc)
|
||||
AC_CONFIG_HEADER(vhdl_config.h)
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
# $host
|
||||
|
||||
# Combined check for Microsoft-related bogosities; sets WIN32 if found
|
||||
AX_WIN32
|
||||
|
||||
AC_CHECK_HEADERS(malloc.h stdint.h inttypes.h)
|
||||
|
||||
# may modify CPPFLAGS and CFLAGS
|
||||
AX_CPP_PRECOMP
|
||||
|
||||
# Compiler option for position independent code, needed when making shared objects.
|
||||
AX_C_PICFLAG
|
||||
|
||||
# linker options when building a shared library
|
||||
AX_LD_SHAREDLIB_OPTS
|
||||
|
||||
AX_CPP_IDENT
|
||||
|
||||
AC_OUTPUT(Makefile)
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* VHDL implementation of $display.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
|
||||
static const char *DISPLAY_LINE = "Verilog_Display_Line";
|
||||
|
||||
/*
|
||||
* Write a VHDL expression into the current display line.
|
||||
*/
|
||||
static void display_write(stmt_container *container, vhdl_expr *expr)
|
||||
{
|
||||
vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
|
||||
vhdl_var_ref *ref =
|
||||
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
|
||||
write->add_expr(ref);
|
||||
|
||||
vhdl_type_name_t type = expr->get_type()->get_name();
|
||||
if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) {
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
write->add_expr(expr->cast(&integer));
|
||||
}
|
||||
else if (type != VHDL_TYPE_STRING) {
|
||||
// Need to add a call to Type'Image for types not
|
||||
// supported by std.textio
|
||||
std::string name(expr->get_type()->get_string());
|
||||
name += "'Image";
|
||||
|
||||
vhdl_fcall *cast
|
||||
= new vhdl_fcall(name.c_str(), vhdl_type::string());
|
||||
cast->add_expr(expr);
|
||||
|
||||
write->add_expr(cast);
|
||||
}
|
||||
else
|
||||
write->add_expr(expr);
|
||||
|
||||
container->add_stmt(write);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the value of DISPLAY_LINE to the output.
|
||||
*/
|
||||
static void display_line(stmt_container *container)
|
||||
{
|
||||
vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
|
||||
vhdl_var_ref *output_ref =
|
||||
new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
|
||||
write_line->add_expr(output_ref);
|
||||
vhdl_var_ref *ref =
|
||||
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
|
||||
write_line->add_expr(ref);
|
||||
container->add_stmt(write_line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an octal escape sequence.
|
||||
*/
|
||||
static char parse_octal(const char *p)
|
||||
{
|
||||
assert(*p && *(p+1) && *(p+2));
|
||||
assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));
|
||||
|
||||
return (*p - '0') * 64
|
||||
+ (*(p+1) - '0') * 8
|
||||
+ (*(p+2) - '0') * 1;
|
||||
}
|
||||
|
||||
static void flush_string(std::ostringstream &ss, stmt_container *container)
|
||||
{
|
||||
display_write(container, new vhdl_const_string(ss.str().c_str()));
|
||||
|
||||
// Clear the stream
|
||||
ss.str("");
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL for the $display system task.
|
||||
* This is implemented using the functions in std.textio. Each
|
||||
* parameter is written to a line variable in the process and
|
||||
* then the line is written to the special variable `Output'
|
||||
* (which represents the console). Subsequent $displays will
|
||||
* use the same line variable.
|
||||
*
|
||||
* It's possible, although quite unlikely, that there will be
|
||||
* name collision with an existing variable called
|
||||
* `Verilog_Display_Line' -- do something about this?
|
||||
*/
|
||||
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool newline)
|
||||
{
|
||||
if (!proc->get_scope()->have_declared(DISPLAY_LINE)) {
|
||||
vhdl_var_decl *line_var =
|
||||
new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line());
|
||||
line_var->set_comment("For generating $display output");
|
||||
proc->get_scope()->add_decl(line_var);
|
||||
}
|
||||
|
||||
// Write the data into the line
|
||||
int count = ivl_stmt_parm_count(stmt), i = 0;
|
||||
while (i < count) {
|
||||
// $display may have an empty parameter, in which case
|
||||
// the expression will be null
|
||||
// The behaviour here seems to be to output a space
|
||||
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
|
||||
if (net == NULL) {
|
||||
display_write(container, new vhdl_const_string(" "));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ivl_expr_type(net) == IVL_EX_STRING) {
|
||||
ostringstream ss;
|
||||
for (const char *p = ivl_expr_string(net); *p; p++) {
|
||||
if (*p == '\\') {
|
||||
// Octal escape
|
||||
char ch = parse_octal(p+1);
|
||||
if (ch == '\n') {
|
||||
flush_string(ss, container);
|
||||
display_line(container);
|
||||
}
|
||||
else
|
||||
ss << ch;
|
||||
p += 3;
|
||||
}
|
||||
else if (*p == '%' && *(++p) != '%') {
|
||||
flush_string(ss, container);
|
||||
|
||||
// Skip over width for now
|
||||
while (isdigit(*p)) ++p;
|
||||
|
||||
// TODO: This needs to be re-written
|
||||
// ...it does not handle format codes at all!
|
||||
// Unfortunately, there is no printf-like
|
||||
// function in VHDL
|
||||
|
||||
assert(i < count);
|
||||
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
|
||||
assert(net);
|
||||
|
||||
vhdl_expr *base = translate_expr(net);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
display_write(container, base);
|
||||
}
|
||||
else
|
||||
ss << *p;
|
||||
}
|
||||
|
||||
display_write(container, new vhdl_const_string(ss.str().c_str()));
|
||||
}
|
||||
else {
|
||||
vhdl_expr *base = translate_expr(net);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
display_write(container, base);
|
||||
}
|
||||
}
|
||||
|
||||
if (newline)
|
||||
display_line(container);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* VHDL code generation for expressions.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
#include "support.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
/*
|
||||
* Change the signedness of a vector.
|
||||
*/
|
||||
static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned)
|
||||
{
|
||||
int msb = e->get_type()->get_msb();
|
||||
int lsb = e->get_type()->get_lsb();
|
||||
vhdl_type u(issigned ? VHDL_TYPE_SIGNED : VHDL_TYPE_UNSIGNED, msb, lsb);
|
||||
|
||||
return e->cast(&u);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a constant Verilog string to a constant VHDL string.
|
||||
*/
|
||||
static vhdl_expr *translate_string(ivl_expr_t e)
|
||||
{
|
||||
// TODO: May need to inspect or escape parts of this
|
||||
const char *str = ivl_expr_string(e);
|
||||
return new vhdl_const_string(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* A reference to a signal in an expression. It's assumed that the
|
||||
* signal has already been defined elsewhere.
|
||||
*/
|
||||
static vhdl_var_ref *translate_signal(ivl_expr_t e)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(e);
|
||||
|
||||
const vhdl_scope *scope = find_scope_for_signal(sig);
|
||||
assert(scope);
|
||||
|
||||
const char *renamed = get_renamed_signal(sig).c_str();
|
||||
|
||||
vhdl_decl *decl = scope->get_decl(renamed);
|
||||
assert(decl);
|
||||
|
||||
// Can't generate a constant initialiser for this signal
|
||||
// later as it has already been read
|
||||
if (scope->initializing())
|
||||
decl->set_initial(NULL);
|
||||
|
||||
vhdl_var_ref *ref =
|
||||
new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type()));
|
||||
|
||||
ivl_expr_t off;
|
||||
if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) {
|
||||
// Select from an array
|
||||
vhdl_expr *vhd_off = translate_expr(off);
|
||||
if (NULL == vhd_off)
|
||||
return NULL;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
ref->set_slice(vhd_off->cast(&integer));
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/*
|
||||
* A numeric literal ends up as std_logic bit string.
|
||||
*/
|
||||
static vhdl_expr *translate_number(ivl_expr_t e)
|
||||
{
|
||||
if (ivl_expr_width(e) == 1)
|
||||
return new vhdl_const_bit(ivl_expr_bits(e)[0]);
|
||||
else
|
||||
return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e),
|
||||
ivl_expr_signed(e) != 0);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_ulong(ivl_expr_t e)
|
||||
{
|
||||
return new vhdl_const_int(ivl_expr_uvalue(e));
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_reduction(support_function_t f, bool neg,
|
||||
vhdl_expr *operand)
|
||||
{
|
||||
vhdl_expr *result;
|
||||
if (operand->get_type()->get_name() == VHDL_TYPE_STD_LOGIC)
|
||||
result = operand;
|
||||
else {
|
||||
require_support_function(f);
|
||||
vhdl_fcall *fcall =
|
||||
new vhdl_fcall(support_function::function_name(f),
|
||||
vhdl_type::std_logic());
|
||||
|
||||
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
|
||||
fcall->add_expr(operand->cast(&std_logic_vector));
|
||||
|
||||
result = fcall;
|
||||
}
|
||||
|
||||
if (neg)
|
||||
return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, result,
|
||||
vhdl_type::std_logic());
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_unary(ivl_expr_t e)
|
||||
{
|
||||
vhdl_expr *operand = translate_expr(ivl_expr_oper1(e));
|
||||
if (NULL == operand)
|
||||
return NULL;
|
||||
|
||||
bool should_be_signed = ivl_expr_signed(e) != 0;
|
||||
|
||||
if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED
|
||||
&& should_be_signed) {
|
||||
//operand->print();
|
||||
//std::cout << "^ should be signed but is not" << std::endl;
|
||||
|
||||
operand = change_signedness(operand, true);
|
||||
}
|
||||
else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED
|
||||
&& !should_be_signed) {
|
||||
//operand->print();
|
||||
//std::cout << "^ should be unsigned but is not" << std::endl;
|
||||
|
||||
operand = change_signedness(operand, false);
|
||||
}
|
||||
|
||||
char opcode = ivl_expr_opcode(e);
|
||||
switch (opcode) {
|
||||
case '!':
|
||||
case '~':
|
||||
return new vhdl_unaryop_expr
|
||||
(VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type()));
|
||||
case '-':
|
||||
operand = change_signedness(operand, true);
|
||||
return new vhdl_unaryop_expr
|
||||
(VHDL_UNARYOP_NEG, operand, new vhdl_type(*operand->get_type()));
|
||||
case 'N': // NOR
|
||||
return translate_reduction(SF_REDUCE_OR, true, operand);
|
||||
case '|':
|
||||
return translate_reduction(SF_REDUCE_OR, false, operand);
|
||||
case 'A': // NAND
|
||||
return translate_reduction(SF_REDUCE_AND, true, operand);
|
||||
case '&':
|
||||
return translate_reduction(SF_REDUCE_AND, false, operand);
|
||||
default:
|
||||
error("No translation for unary opcode '%c'\n",
|
||||
ivl_expr_opcode(e));
|
||||
delete operand;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a numeric binary operator (+, -, etc.) to
|
||||
* a VHDL equivalent using the numeric_std package.
|
||||
*/
|
||||
static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs,
|
||||
vhdl_binop_t op)
|
||||
{
|
||||
// May need to make either side Boolean for operators
|
||||
// to work
|
||||
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
|
||||
if (lhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN)
|
||||
rhs = rhs->cast(&boolean);
|
||||
else if (rhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN)
|
||||
lhs = lhs->cast(&boolean);
|
||||
|
||||
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
|
||||
return new vhdl_binop_expr(lhs, op, rhs, rtype);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs,
|
||||
vhdl_binop_t op)
|
||||
{
|
||||
// Generate any necessary casts
|
||||
// Arbitrarily, the RHS is casted to the type of the LHS
|
||||
vhdl_expr *r_cast = rhs->cast(lhs->get_type());
|
||||
|
||||
return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean());
|
||||
}
|
||||
|
||||
/*
|
||||
* Like translate_relation but both operands must be Boolean.
|
||||
*/
|
||||
static vhdl_expr *translate_logical(vhdl_expr *lhs, vhdl_expr *rhs,
|
||||
vhdl_binop_t op)
|
||||
{
|
||||
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
|
||||
|
||||
return translate_relation(lhs->cast(&boolean), rhs->cast(&boolean), op);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs,
|
||||
vhdl_binop_t op)
|
||||
{
|
||||
// The RHS must be an integer
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
vhdl_expr *r_cast = rhs->cast(&integer);
|
||||
|
||||
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
|
||||
return new vhdl_binop_expr(lhs, op, r_cast, rtype);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_binary(ivl_expr_t e)
|
||||
{
|
||||
vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e));
|
||||
if (NULL == lhs)
|
||||
return NULL;
|
||||
|
||||
vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e));
|
||||
if (NULL == rhs)
|
||||
return NULL;
|
||||
|
||||
int lwidth = lhs->get_type()->get_width();
|
||||
int rwidth = rhs->get_type()->get_width();
|
||||
int result_width = ivl_expr_width(e);
|
||||
|
||||
// For === and !== we need to compare std_logic_vectors
|
||||
// rather than signeds
|
||||
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0);
|
||||
vhdl_type_name_t ltype = lhs->get_type()->get_name();
|
||||
vhdl_type_name_t rtype = rhs->get_type()->get_name();
|
||||
bool vectorop =
|
||||
(ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) &&
|
||||
(rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED);
|
||||
|
||||
// May need to resize the left or right hand side
|
||||
if (vectorop) {
|
||||
if (lwidth < rwidth)
|
||||
lhs = lhs->resize(rwidth);
|
||||
else if (rwidth < lwidth)
|
||||
rhs = rhs->resize(lwidth);
|
||||
}
|
||||
|
||||
vhdl_expr *result;
|
||||
switch (ivl_expr_opcode(e)) {
|
||||
case '+':
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_ADD);
|
||||
break;
|
||||
case '-':
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_SUB);
|
||||
break;
|
||||
case '*':
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT);
|
||||
break;
|
||||
case '/':
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_DIV);
|
||||
break;
|
||||
case '%':
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_MOD);
|
||||
break;
|
||||
case 'e':
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
|
||||
break;
|
||||
case 'E':
|
||||
if (vectorop)
|
||||
result = translate_relation(lhs->cast(&std_logic_vector),
|
||||
rhs->cast(&std_logic_vector), VHDL_BINOP_EQ);
|
||||
else
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
|
||||
break;
|
||||
case 'n':
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
|
||||
break;
|
||||
case 'N':
|
||||
if (vectorop)
|
||||
result = translate_relation(lhs->cast(&std_logic_vector),
|
||||
rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ);
|
||||
else
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
|
||||
break;
|
||||
case '&': // Bitwise AND
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_AND);
|
||||
break;
|
||||
case 'a': // Logical AND
|
||||
result = translate_logical(lhs, rhs, VHDL_BINOP_AND);
|
||||
break;
|
||||
case 'A': // Bitwise NAND
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_NAND);
|
||||
break;
|
||||
case 'O': // Bitwise NOR
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_NOR);
|
||||
break;
|
||||
case 'X': // Bitwise XNOR
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_XNOR);
|
||||
break;
|
||||
case '|': // Bitwise OR
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_OR);
|
||||
break;
|
||||
case 'o': // Logical OR
|
||||
result = translate_logical(lhs, rhs, VHDL_BINOP_OR);
|
||||
break;
|
||||
case '<':
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_LT);
|
||||
break;
|
||||
case 'L':
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_LEQ);
|
||||
break;
|
||||
case '>':
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_GT);
|
||||
break;
|
||||
case 'G':
|
||||
result = translate_relation(lhs, rhs, VHDL_BINOP_GEQ);
|
||||
break;
|
||||
case 'l':
|
||||
result = translate_shift(lhs, rhs, VHDL_BINOP_SL);
|
||||
break;
|
||||
case 'r':
|
||||
result = translate_shift(lhs, rhs, VHDL_BINOP_SR);
|
||||
break;
|
||||
case '^':
|
||||
result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR);
|
||||
break;
|
||||
default:
|
||||
error("No translation for binary opcode '%c'\n",
|
||||
ivl_expr_opcode(e));
|
||||
delete lhs;
|
||||
delete rhs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (NULL == result)
|
||||
return NULL;
|
||||
|
||||
if (vectorop) {
|
||||
bool should_be_signed = ivl_expr_signed(e) != 0;
|
||||
|
||||
if (result->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) {
|
||||
//result->print();
|
||||
//std::cout << "^ should be signed but is not" << std::endl;
|
||||
|
||||
result = change_signedness(result, true);
|
||||
}
|
||||
else if (result->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) {
|
||||
//result->print();
|
||||
//std::cout << "^ should be unsigned but is not" << std::endl;
|
||||
|
||||
result = change_signedness(result, false);
|
||||
}
|
||||
|
||||
int actual_width = result->get_type()->get_width();
|
||||
if (actual_width != result_width) {
|
||||
//result->print();
|
||||
//std::cout << "^ should be " << result_width << " but is " << actual_width << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_select(ivl_expr_t e)
|
||||
{
|
||||
vhdl_var_ref *from =
|
||||
dynamic_cast<vhdl_var_ref*>(translate_expr(ivl_expr_oper1(e)));
|
||||
if (NULL == from) {
|
||||
error("Can only select from variable reference");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ivl_expr_t o2 = ivl_expr_oper2(e);
|
||||
if (o2) {
|
||||
vhdl_expr *base = translate_expr(ivl_expr_oper2(e));
|
||||
if (NULL == base)
|
||||
return NULL;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
from->set_slice(base->cast(&integer), ivl_expr_width(e) - 1);
|
||||
return from;
|
||||
}
|
||||
else
|
||||
return from->resize(ivl_expr_width(e));
|
||||
}
|
||||
|
||||
static vhdl_type *expr_to_vhdl_type(ivl_expr_t e)
|
||||
{
|
||||
if (ivl_expr_signed(e))
|
||||
return vhdl_type::nsigned(ivl_expr_width(e));
|
||||
else
|
||||
return vhdl_type::nunsigned(ivl_expr_width(e));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static T *translate_parms(T *t, ivl_expr_t e)
|
||||
{
|
||||
int nparams = ivl_expr_parms(e);
|
||||
for (int i = 0; i < nparams; i++) {
|
||||
vhdl_expr *param = translate_expr(ivl_expr_parm(e, i));
|
||||
if (NULL == param)
|
||||
return NULL;
|
||||
|
||||
t->add_expr(param);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_ufunc(ivl_expr_t e)
|
||||
{
|
||||
ivl_scope_t defscope = ivl_expr_def(e);
|
||||
ivl_scope_t parentscope = ivl_scope_parent(defscope);
|
||||
assert(ivl_scope_type(parentscope) == IVL_SCT_MODULE);
|
||||
|
||||
// A function is always declared in a module, which should have
|
||||
// a corresponding entity by this point: so we can get type
|
||||
// information, etc. from the declaration
|
||||
vhdl_entity *parent_ent = find_entity(ivl_scope_name(parentscope));
|
||||
assert(parent_ent);
|
||||
|
||||
const char *funcname = ivl_scope_tname(defscope);
|
||||
|
||||
vhdl_type *rettype = expr_to_vhdl_type(e);
|
||||
vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype);
|
||||
|
||||
return translate_parms<vhdl_fcall>(fcall, e);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_ternary(ivl_expr_t e)
|
||||
{
|
||||
support_function_t sf;
|
||||
int width = ivl_expr_width(e);
|
||||
bool issigned = ivl_expr_signed(e) != 0;
|
||||
if (width == 1)
|
||||
sf = SF_TERNARY_LOGIC;
|
||||
else if (issigned)
|
||||
sf = SF_TERNARY_SIGNED;
|
||||
else
|
||||
sf = SF_TERNARY_UNSIGNED;
|
||||
|
||||
require_support_function(sf);
|
||||
|
||||
vhdl_expr *test = translate_expr(ivl_expr_oper1(e));
|
||||
vhdl_expr *true_part = translate_expr(ivl_expr_oper2(e));
|
||||
vhdl_expr *false_part = translate_expr(ivl_expr_oper3(e));
|
||||
if (!test || !true_part || !false_part)
|
||||
return NULL;
|
||||
|
||||
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
|
||||
test = test->cast(&boolean);
|
||||
|
||||
vhdl_fcall *fcall =
|
||||
new vhdl_fcall(support_function::function_name(sf),
|
||||
vhdl_type::type_for(width, issigned));
|
||||
fcall->add_expr(test);
|
||||
fcall->add_expr(true_part);
|
||||
fcall->add_expr(false_part);
|
||||
|
||||
return fcall;
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_concat(ivl_expr_t e)
|
||||
{
|
||||
vhdl_type *rtype = expr_to_vhdl_type(e);
|
||||
vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype);
|
||||
|
||||
int nrepeat = ivl_expr_repeat(e);
|
||||
while (nrepeat--)
|
||||
translate_parms<vhdl_binop_expr>(concat, e);
|
||||
|
||||
return concat;
|
||||
}
|
||||
|
||||
vhdl_expr *translate_sfunc_time(ivl_expr_t e)
|
||||
{
|
||||
cerr << "warning: no translation for time (returning 0)" << endl;
|
||||
return new vhdl_const_int(0);
|
||||
}
|
||||
|
||||
vhdl_expr *translate_sfunc(ivl_expr_t e)
|
||||
{
|
||||
const char *name = ivl_expr_name(e);
|
||||
if (strcmp(name, "$time") == 0)
|
||||
return translate_sfunc_time(e);
|
||||
else {
|
||||
error("No translation for system function %s", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a VHDL expression from a Verilog expression.
|
||||
*/
|
||||
vhdl_expr *translate_expr(ivl_expr_t e)
|
||||
{
|
||||
assert(e);
|
||||
ivl_expr_type_t type = ivl_expr_type(e);
|
||||
|
||||
switch (type) {
|
||||
case IVL_EX_STRING:
|
||||
return translate_string(e);
|
||||
case IVL_EX_SIGNAL:
|
||||
return translate_signal(e);
|
||||
case IVL_EX_NUMBER:
|
||||
return translate_number(e);
|
||||
case IVL_EX_ULONG:
|
||||
return translate_ulong(e);
|
||||
case IVL_EX_UNARY:
|
||||
return translate_unary(e);
|
||||
case IVL_EX_BINARY:
|
||||
return translate_binary(e);
|
||||
case IVL_EX_SELECT:
|
||||
return translate_select(e);
|
||||
case IVL_EX_UFUNC:
|
||||
return translate_ufunc(e);
|
||||
case IVL_EX_TERNARY:
|
||||
return translate_ternary(e);
|
||||
case IVL_EX_CONCAT:
|
||||
return translate_concat(e);
|
||||
case IVL_EX_SFUNC:
|
||||
return translate_sfunc(e);
|
||||
default:
|
||||
error("No VHDL translation for expression at %s:%d (type = %d)",
|
||||
ivl_expr_file(e), ivl_expr_lineno(e), type);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate an expression into a time. This is achieved simply
|
||||
* by multiplying the expression by 1ns.
|
||||
*/
|
||||
vhdl_expr *translate_time_expr(ivl_expr_t e)
|
||||
{
|
||||
vhdl_expr *time = translate_expr(e);
|
||||
if (NULL == time)
|
||||
return NULL;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
time = time->cast(&integer);
|
||||
|
||||
vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS);
|
||||
return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1,
|
||||
vhdl_type::time());
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* VHDL code generation for logic devices.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
#include "vhdl_element.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/*
|
||||
* Convert the inputs of a logic gate to a binary expression.
|
||||
*/
|
||||
static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
|
||||
ivl_net_logic_t log)
|
||||
{
|
||||
// Not always std_logic but this is probably OK since
|
||||
// the program has already been type checked
|
||||
vhdl_binop_expr *gate =
|
||||
new vhdl_binop_expr(op, vhdl_type::std_logic());
|
||||
|
||||
int npins = ivl_logic_pins(log);
|
||||
for (int i = 1; i < npins; i++) {
|
||||
ivl_nexus_t input = ivl_logic_pin(log, i);
|
||||
gate->add_expr(nexus_to_var_ref(scope, input));
|
||||
}
|
||||
|
||||
return gate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a gate intput to an unary expression.
|
||||
*/
|
||||
static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
|
||||
ivl_net_logic_t log)
|
||||
{
|
||||
ivl_nexus_t input = ivl_logic_pin(log, 1);
|
||||
assert(input);
|
||||
|
||||
vhdl_expr *operand = nexus_to_var_ref(scope, input);
|
||||
return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
|
||||
}
|
||||
|
||||
static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
|
||||
{
|
||||
ivl_nexus_t output = ivl_logic_pin(log, 0);
|
||||
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
|
||||
assert(lhs);
|
||||
|
||||
vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
|
||||
assert(val);
|
||||
|
||||
vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
|
||||
assert(val);
|
||||
|
||||
vhdl_expr *cmp;
|
||||
if (ivl_logic_width(log) == 1) {
|
||||
vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
|
||||
cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);
|
||||
}
|
||||
else {
|
||||
vhdl_expr *zero = (new vhdl_const_int(0))->cast(sel->get_type());
|
||||
vhdl_binop_t op = if0 ? VHDL_BINOP_EQ : VHDL_BINOP_NEQ;
|
||||
cmp = new vhdl_binop_expr(sel, op, zero, NULL);
|
||||
}
|
||||
|
||||
|
||||
ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
|
||||
char zbit;
|
||||
switch (ivl_signal_type(sig)) {
|
||||
case IVL_SIT_TRI0:
|
||||
zbit = '0';
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
zbit = '1';
|
||||
break;
|
||||
case IVL_SIT_TRI:
|
||||
default:
|
||||
zbit = 'Z';
|
||||
}
|
||||
|
||||
vhdl_expr *z = new vhdl_const_bit(zbit);
|
||||
if (ivl_logic_width(log) > 1)
|
||||
z = new vhdl_bit_spec_expr(NULL, z);
|
||||
vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
|
||||
cass->add_condition(val, cmp);
|
||||
|
||||
arch->add_stmt(cass);
|
||||
}
|
||||
|
||||
static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
|
||||
{
|
||||
ivl_udp_t udp = ivl_logic_udp(log);
|
||||
|
||||
// As with regular case statements, the expression in a
|
||||
// `with .. select' statement must be "locally static".
|
||||
// This is achieved by first combining the inputs into
|
||||
// a temporary
|
||||
|
||||
ostringstream ss;
|
||||
ss << ivl_logic_basename(log) << "_Tmp";
|
||||
int msb = ivl_udp_nin(udp) - 1;
|
||||
vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0);
|
||||
vhdl_signal_decl *tmp_decl =
|
||||
new vhdl_signal_decl(ss.str().c_str(), tmp_type);
|
||||
arch->get_scope()->add_decl(tmp_decl);
|
||||
|
||||
int nin = ivl_udp_nin(udp);
|
||||
vhdl_expr *tmp_rhs;
|
||||
if (nin == 1) {
|
||||
tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
|
||||
tmp_rhs = tmp_rhs->cast(tmp_type);
|
||||
}
|
||||
else
|
||||
tmp_rhs = inputs_to_expr(arch->get_scope(), VHDL_BINOP_CONCAT, log);
|
||||
|
||||
ss.str("");
|
||||
ss << "Input to " << ivl_logic_basename(log) << " "
|
||||
<< ivl_udp_name(udp) << " UDP";
|
||||
tmp_decl->set_comment(ss.str());
|
||||
|
||||
vhdl_var_ref *tmp_ref =
|
||||
new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL);
|
||||
arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs));
|
||||
|
||||
// Now we can implement the UDP as a `with .. select' statement
|
||||
// by reading values out of the table
|
||||
ivl_nexus_t output_nex = ivl_logic_pin(log, 0);
|
||||
vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), output_nex);
|
||||
vhdl_with_select_stmt *ws =
|
||||
new vhdl_with_select_stmt(new vhdl_var_ref(*tmp_ref), out);
|
||||
|
||||
int nrows = ivl_udp_rows(udp);
|
||||
for (int i = 0; i < nrows; i++) {
|
||||
const char *row = ivl_udp_row(udp, i);
|
||||
|
||||
vhdl_expr *value = new vhdl_const_bit(row[nin]);
|
||||
vhdl_expr *cond = new vhdl_const_bits(row, nin, false);
|
||||
|
||||
ivl_expr_t delay_ex = ivl_logic_delay(log, 1);
|
||||
vhdl_expr *delay = NULL;
|
||||
if (delay_ex)
|
||||
delay = translate_time_expr(delay_ex);
|
||||
|
||||
ws->add_condition(value, cond, delay);
|
||||
}
|
||||
|
||||
ss.str("");
|
||||
ss << "UDP " << ivl_udp_name(udp);
|
||||
ws->set_comment(ss.str());
|
||||
|
||||
arch->add_stmt(ws);
|
||||
}
|
||||
|
||||
static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
|
||||
{
|
||||
ivl_udp_t udp = ivl_logic_udp(log);
|
||||
|
||||
// These will be translated to a process with a single
|
||||
// case statement
|
||||
|
||||
vhdl_process *proc = new vhdl_process(ivl_logic_basename(log));
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Generated from UDP " << ivl_udp_name(udp);
|
||||
proc->set_comment(ss.str().c_str());
|
||||
|
||||
// Create a variable to hold the concatenation of the inputs
|
||||
int msb = ivl_udp_nin(udp) - 1;
|
||||
vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0);
|
||||
proc->get_scope()->add_decl(new vhdl_var_decl("UDP_Inputs", tmp_type));
|
||||
|
||||
// Concatenate the inputs into a single expression that can be
|
||||
// used as the test in a case statement (this can't be inserted
|
||||
// directly into the case statement due to the requirement that
|
||||
// the test expression be "locally static")
|
||||
int nin = ivl_udp_nin(udp);
|
||||
vhdl_expr *tmp_rhs = NULL;
|
||||
if (nin == 1) {
|
||||
vhdl_var_ref *ref =
|
||||
nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
|
||||
tmp_rhs = ref->cast(tmp_type);
|
||||
proc->add_sensitivity(ref->get_name());
|
||||
}
|
||||
else {
|
||||
vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, NULL);
|
||||
|
||||
for (int i = 1; i < nin; i++) {
|
||||
vhdl_var_ref *ref =
|
||||
nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, i));
|
||||
concat->add_expr(ref);
|
||||
proc->add_sensitivity(ref->get_name());
|
||||
}
|
||||
|
||||
tmp_rhs = concat;
|
||||
}
|
||||
|
||||
proc->get_container()->add_stmt
|
||||
(new vhdl_assign_stmt(new vhdl_var_ref("UDP_Inputs", NULL), tmp_rhs));
|
||||
|
||||
arch->add_stmt(proc);
|
||||
}
|
||||
|
||||
static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
|
||||
{
|
||||
if (ivl_udp_sequ(ivl_logic_udp(log)))
|
||||
seq_udp_logic(arch, log);
|
||||
else
|
||||
comb_udp_logic(arch, log);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log)
|
||||
{
|
||||
switch (ivl_logic_type(log)) {
|
||||
case IVL_LO_NOT:
|
||||
return input_to_expr(scope, VHDL_UNARYOP_NOT, log);
|
||||
case IVL_LO_AND:
|
||||
return inputs_to_expr(scope, VHDL_BINOP_AND, log);
|
||||
case IVL_LO_OR:
|
||||
return inputs_to_expr(scope, VHDL_BINOP_OR, log);
|
||||
case IVL_LO_NAND:
|
||||
return inputs_to_expr(scope, VHDL_BINOP_NAND, log);
|
||||
case IVL_LO_NOR:
|
||||
return inputs_to_expr(scope, VHDL_BINOP_NOR, log);
|
||||
case IVL_LO_XOR:
|
||||
return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
|
||||
case IVL_LO_XNOR:
|
||||
return inputs_to_expr(scope, VHDL_BINOP_XNOR, log);
|
||||
case IVL_LO_BUF:
|
||||
case IVL_LO_BUFZ:
|
||||
return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
|
||||
case IVL_LO_PULLUP:
|
||||
return new vhdl_const_bit('1');
|
||||
case IVL_LO_PULLDOWN:
|
||||
return new vhdl_const_bit('0');
|
||||
default:
|
||||
error("Don't know how to translate logic type = %d to expression",
|
||||
ivl_logic_type(log));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_logic(vhdl_arch *arch, ivl_net_logic_t log)
|
||||
{
|
||||
switch (ivl_logic_type(log)) {
|
||||
case IVL_LO_BUFIF0:
|
||||
bufif_logic(arch, log, true);
|
||||
break;
|
||||
case IVL_LO_BUFIF1:
|
||||
bufif_logic(arch, log, false);
|
||||
break;
|
||||
case IVL_LO_UDP:
|
||||
udp_logic(arch, log);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// The output is always pin zero
|
||||
ivl_nexus_t output = ivl_logic_pin(log, 0);
|
||||
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
|
||||
|
||||
vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log);
|
||||
vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);
|
||||
|
||||
ivl_expr_t delay = ivl_logic_delay(log, 1);
|
||||
if (delay)
|
||||
ass->set_after(translate_time_expr(delay));
|
||||
|
||||
arch->add_stmt(ass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* VHDL code generation for LPM devices.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
/*
|
||||
* Return the base of a part select.
|
||||
*/
|
||||
static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_expr *off;
|
||||
ivl_nexus_t base = ivl_lpm_data(lpm, 1);
|
||||
if (base != NULL)
|
||||
off = nexus_to_var_ref(scope, base);
|
||||
else
|
||||
off = new vhdl_const_int(ivl_lpm_base(lpm));
|
||||
|
||||
// Array indexes must be integers
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
return off->cast(&integer);
|
||||
}
|
||||
|
||||
static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_type *result_type =
|
||||
vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
|
||||
vhdl_binop_expr *expr =
|
||||
new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);
|
||||
|
||||
for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
|
||||
{
|
||||
unsigned out_width = ivl_lpm_width(lpm);
|
||||
vhdl_type *result_type =
|
||||
vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0);
|
||||
vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e->cast(result_type));
|
||||
}
|
||||
|
||||
if (op == VHDL_BINOP_MULT) {
|
||||
// Need to resize the output to the desired size,
|
||||
// as this does not happen automatically in VHDL
|
||||
|
||||
vhdl_fcall *resize =
|
||||
new vhdl_fcall("Resize", vhdl_type::nsigned(out_width));
|
||||
resize->add_expr(expr);
|
||||
resize->add_expr(new vhdl_const_int(out_width));
|
||||
|
||||
return resize;
|
||||
}
|
||||
else
|
||||
return expr;
|
||||
}
|
||||
|
||||
static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
|
||||
{
|
||||
vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean());
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e);
|
||||
}
|
||||
|
||||
// Need to make sure output is std_logic rather than Boolean
|
||||
vhdl_type std_logic(VHDL_TYPE_STD_LOGIC);
|
||||
return expr->cast(&std_logic);
|
||||
}
|
||||
|
||||
static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
if (NULL == selfrom)
|
||||
return NULL;
|
||||
|
||||
vhdl_expr *off = part_select_base(scope, lpm);;
|
||||
if (NULL == off)
|
||||
return NULL;
|
||||
|
||||
selfrom->set_slice(off, ivl_lpm_width(lpm) - 1);
|
||||
return selfrom;
|
||||
}
|
||||
|
||||
|
||||
static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
return nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
}
|
||||
|
||||
static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
ivl_scope_t f_scope = ivl_lpm_define(lpm);
|
||||
vhdl_fcall *fcall = new vhdl_fcall(ivl_scope_basename(f_scope), NULL);
|
||||
|
||||
for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) {
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == ref)
|
||||
return NULL;
|
||||
|
||||
fcall->add_expr(ref);
|
||||
}
|
||||
|
||||
return fcall;
|
||||
}
|
||||
|
||||
static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
|
||||
support_function_t f, bool invert)
|
||||
{
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
if (NULL == ref)
|
||||
return NULL;
|
||||
|
||||
vhdl_expr *result;
|
||||
if (ref->get_type()->get_name() == VHDL_TYPE_STD_LOGIC)
|
||||
result = ref;
|
||||
else {
|
||||
require_support_function(f);
|
||||
vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f),
|
||||
vhdl_type::std_logic());
|
||||
|
||||
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
|
||||
fcall->add_expr(ref->cast(&std_logic_vector));
|
||||
|
||||
result = fcall;
|
||||
}
|
||||
|
||||
if (invert)
|
||||
return new vhdl_unaryop_expr
|
||||
(VHDL_UNARYOP_NOT, result, vhdl_type::std_logic());
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
if (ref)
|
||||
return ref->resize(ivl_lpm_width(lpm));
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
ivl_signal_t array = ivl_lpm_array(lpm);
|
||||
if (!seen_signal_before(array))
|
||||
return NULL;
|
||||
|
||||
const char *renamed = get_renamed_signal(array).c_str();
|
||||
|
||||
vhdl_decl *adecl = scope->get_decl(renamed);
|
||||
assert(adecl);
|
||||
|
||||
vhdl_type *atype = new vhdl_type(*adecl->get_type());
|
||||
|
||||
vhdl_expr *select = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
|
||||
if (NULL == select)
|
||||
return NULL;
|
||||
|
||||
vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype);
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
ref->set_slice(select->cast(&integer));
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
|
||||
vhdl_binop_t shift_op)
|
||||
{
|
||||
vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
|
||||
if (!lhs || !rhs)
|
||||
return NULL;
|
||||
|
||||
// The RHS must be an integer
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
vhdl_expr *r_cast = rhs->cast(&integer);
|
||||
|
||||
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
|
||||
return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype);
|
||||
}
|
||||
|
||||
static vhdl_expr *repeat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_expr *in = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
return new vhdl_bit_spec_expr(NULL, in);
|
||||
}
|
||||
|
||||
static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
switch (ivl_lpm_type(lpm)) {
|
||||
case IVL_LPM_ADD:
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD);
|
||||
case IVL_LPM_SUB:
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB);
|
||||
case IVL_LPM_MULT:
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT);
|
||||
case IVL_LPM_DIVIDE:
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_DIV);
|
||||
case IVL_LPM_MOD:
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MOD);
|
||||
case IVL_LPM_CONCAT:
|
||||
return concat_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_CMP_GE:
|
||||
return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ);
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ);
|
||||
case IVL_LPM_PART_VP:
|
||||
return part_select_vp_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_PART_PV:
|
||||
return part_select_pv_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_UFUNC:
|
||||
return ufunc_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_RE_AND:
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, false);
|
||||
case IVL_LPM_RE_NAND:
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, true);
|
||||
case IVL_LPM_RE_NOR:
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true);
|
||||
case IVL_LPM_RE_OR:
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false);
|
||||
case IVL_LPM_RE_XOR:
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false);
|
||||
case IVL_LPM_RE_XNOR:
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, true);
|
||||
case IVL_LPM_SIGN_EXT:
|
||||
return sign_extend_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_ARRAY:
|
||||
return array_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_SHIFTL:
|
||||
return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL);
|
||||
case IVL_LPM_SHIFTR:
|
||||
return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR);
|
||||
case IVL_LPM_REPEAT:
|
||||
return repeat_lpm_to_expr(scope, lpm);
|
||||
default:
|
||||
error("Unsupported LPM type: %d", ivl_lpm_type(lpm));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_mux_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
|
||||
{
|
||||
int nselects = ivl_lpm_selects(lpm);
|
||||
|
||||
if (nselects > 1) {
|
||||
error("Only 1 LPM select bit supported at the moment");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vhdl_scope *scope = arch->get_scope();
|
||||
|
||||
vhdl_expr *s0 = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
vhdl_expr *s1 = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
|
||||
|
||||
vhdl_expr *sel = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
|
||||
vhdl_expr *b1 = new vhdl_const_bit('1');
|
||||
vhdl_expr *t1 =
|
||||
new vhdl_binop_expr(sel, VHDL_BINOP_EQ, b1, vhdl_type::boolean());
|
||||
|
||||
vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0));
|
||||
|
||||
vhdl_cassign_stmt *s = new vhdl_cassign_stmt(out, s0);
|
||||
s->add_condition(s1, t1);
|
||||
|
||||
arch->add_stmt(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
|
||||
{
|
||||
if (ivl_lpm_type(lpm) == IVL_LPM_MUX)
|
||||
return draw_mux_lpm(arch, lpm);
|
||||
|
||||
vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm);
|
||||
if (NULL == f)
|
||||
return 1;
|
||||
|
||||
vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0));
|
||||
if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) {
|
||||
vhdl_expr *off = part_select_base(arch->get_scope(), lpm);
|
||||
assert(off);
|
||||
|
||||
out->set_slice(off, ivl_lpm_width(lpm) - 1);
|
||||
}
|
||||
|
||||
arch->add_stmt(new vhdl_cassign_stmt(out, f));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* VHDL code generation for processes.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
#include "vhdl_element.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
/*
|
||||
* Convert a Verilog process to VHDL and add it to the architecture
|
||||
* of the given entity.
|
||||
*/
|
||||
static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
|
||||
{
|
||||
set_active_entity(ent);
|
||||
|
||||
// Create a new process and store it in the entity's
|
||||
// architecture. This needs to be done first or the
|
||||
// parent link won't be valid (and draw_stmt needs this
|
||||
// to add information to the architecture)
|
||||
vhdl_process *vhdl_proc = new vhdl_process();
|
||||
ent->get_arch()->add_stmt(vhdl_proc);
|
||||
|
||||
// If this is an initial process, push signal initialisation
|
||||
// into the declarations
|
||||
vhdl_proc->get_scope()->set_initializing
|
||||
(ivl_process_type(proc) == IVL_PR_INITIAL);
|
||||
|
||||
ivl_statement_t stmt = ivl_process_stmt(proc);
|
||||
int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
// Initial processes are translated to VHDL processes with
|
||||
// no sensitivity list and and indefinite wait statement at
|
||||
// the end
|
||||
// However, if no statements were added to the container
|
||||
// by draw_stmt, don't bother adding a wait as `emit'
|
||||
// will optimise the process out of the output
|
||||
if (ivl_process_type(proc) == IVL_PR_INITIAL
|
||||
&& !vhdl_proc->get_container()->empty()) {
|
||||
vhdl_wait_stmt *wait = new vhdl_wait_stmt();
|
||||
vhdl_proc->get_container()->add_stmt(wait);
|
||||
}
|
||||
|
||||
// Add a comment indicating where it came from
|
||||
ivl_scope_t scope = ivl_process_scope(proc);
|
||||
const char *type = ivl_process_type(proc) == IVL_PR_INITIAL
|
||||
? "initial" : "always";
|
||||
std::ostringstream ss;
|
||||
ss << "Generated from " << type << " process in "
|
||||
<< ivl_scope_tname(scope) << " ("
|
||||
<< ivl_process_file(proc) << ":"
|
||||
<< ivl_process_lineno(proc) << ")";
|
||||
vhdl_proc->set_comment(ss.str());
|
||||
|
||||
set_active_entity(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_process(ivl_process_t proc, void *cd)
|
||||
{
|
||||
ivl_scope_t scope = ivl_process_scope(proc);
|
||||
|
||||
// A process should occur in a module scope, therefore it
|
||||
// should have already been assigned a VHDL entity
|
||||
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
|
||||
assert(ent != NULL);
|
||||
|
||||
return generate_vhdl_process(ent, proc);
|
||||
}
|
||||
@@ -0,0 +1,819 @@
|
||||
/*
|
||||
* VHDL code generation for scopes.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
#include "vhdl_element.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
static string make_safe_name(ivl_signal_t sig);
|
||||
|
||||
static vhdl_entity *g_active_entity = NULL;
|
||||
|
||||
vhdl_entity *get_active_entity()
|
||||
{
|
||||
return g_active_entity;
|
||||
}
|
||||
|
||||
void set_active_entity(vhdl_entity *ent)
|
||||
{
|
||||
g_active_entity = ent;
|
||||
}
|
||||
|
||||
/*
|
||||
* This represents the portion of a nexus that is visible within
|
||||
* a VHDL scope. If that nexus portion does not contain a signal,
|
||||
* then `tmpname' gives the name of the temporary that will be
|
||||
* used when this nexus is used in `scope' (e.g. for LPMs that
|
||||
* appear in instantiations). The list `connect' lists all the
|
||||
* signals that should be joined together to re-create the net.
|
||||
*/
|
||||
struct scope_nexus_t {
|
||||
vhdl_scope *scope;
|
||||
ivl_signal_t sig; // A real signal
|
||||
unsigned pin; // The pin this signal is connected to
|
||||
string tmpname; // A new temporary signal
|
||||
list<ivl_signal_t> connect; // Other signals to wire together
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is stored in the private part of each nexus.
|
||||
* It stores a scope_nexus_t for each VHDL scope which is
|
||||
* connected to that nexus. It's stored as a list so we can use
|
||||
* contained_within to allow several nested scopes to reference
|
||||
* the same signal.
|
||||
*/
|
||||
struct nexus_private_t {
|
||||
list<scope_nexus_t> signals;
|
||||
vhdl_expr *const_driver;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the scope_nexus_t of this nexus visible within scope.
|
||||
*/
|
||||
static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope)
|
||||
{
|
||||
list<scope_nexus_t>::iterator it;
|
||||
for (it = priv->signals.begin(); it != priv->signals.end(); ++it) {
|
||||
if (scope->contained_within((*it).scope))
|
||||
return &*it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember that a signal in `scope' is part of this nexus. The
|
||||
* first signal passed to this function for a scope will be used
|
||||
* as the canonical representation of this nexus when we need to
|
||||
* convert it to a variable reference (e.g. in a LPM input/output).
|
||||
*/
|
||||
static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope,
|
||||
ivl_signal_t sig, unsigned pin)
|
||||
{
|
||||
scope_nexus_t *sn;
|
||||
if ((sn = visible_nexus(priv, scope))) {
|
||||
assert(sn->tmpname == "");
|
||||
|
||||
sn->connect.push_back(sig);
|
||||
}
|
||||
else {
|
||||
scope_nexus_t new_sn = { scope, sig, pin, "" };
|
||||
priv->signals.push_back(new_sn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a temporary the representative of this nexus in scope.
|
||||
*/
|
||||
static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope,
|
||||
const string &name)
|
||||
{
|
||||
scope_nexus_t new_sn = { scope, NULL, 0, name };
|
||||
priv->signals.push_back(new_sn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the name of the nexus signal within this scope.
|
||||
*/
|
||||
static string visible_nexus_signal_name(nexus_private_t *priv, vhdl_scope *scope,
|
||||
unsigned *pin)
|
||||
{
|
||||
scope_nexus_t *sn = visible_nexus(priv, scope);
|
||||
assert(sn);
|
||||
|
||||
*pin = sn->pin;
|
||||
return sn->sig ? get_renamed_signal(sn->sig) : sn->tmpname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates VHDL code to fully represent a nexus.
|
||||
*/
|
||||
void draw_nexus(ivl_nexus_t nexus)
|
||||
{
|
||||
nexus_private_t *priv = new nexus_private_t;
|
||||
priv->const_driver = NULL;
|
||||
|
||||
int nptrs = ivl_nexus_ptrs(nexus);
|
||||
|
||||
// First pass through connect all the signals up
|
||||
for (int i = 0; i < nptrs; i++) {
|
||||
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
|
||||
|
||||
ivl_signal_t sig;
|
||||
if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
|
||||
vhdl_scope *scope = find_scope_for_signal(sig);
|
||||
unsigned pin = ivl_nexus_ptr_pin(nexus_ptr);
|
||||
link_scope_to_nexus_signal(priv, scope, sig, pin);
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass through make sure logic/LPMs have signal
|
||||
// inputs and outputs
|
||||
for (int i = 0; i < nptrs; i++) {
|
||||
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
|
||||
|
||||
ivl_net_logic_t log;
|
||||
ivl_lpm_t lpm;
|
||||
ivl_net_const_t con;
|
||||
if ((log = ivl_nexus_ptr_log(nexus_ptr))) {
|
||||
ivl_scope_t log_scope = ivl_logic_scope(log);
|
||||
vhdl_scope *vhdl_scope =
|
||||
find_entity(ivl_scope_name(log_scope))->get_arch()->get_scope();
|
||||
|
||||
if (visible_nexus(priv, vhdl_scope)) {
|
||||
// Already seen this signal in vhdl_scope
|
||||
}
|
||||
else {
|
||||
// Create a temporary signal to connect it to the nexus
|
||||
vhdl_type *type =
|
||||
vhdl_type::type_for(ivl_logic_width(log), false);
|
||||
|
||||
ostringstream ss;
|
||||
ss << "LO" << ivl_logic_basename(log);
|
||||
vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type));
|
||||
|
||||
link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str());
|
||||
}
|
||||
}
|
||||
else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) {
|
||||
ivl_scope_t lpm_scope = ivl_lpm_scope(lpm);
|
||||
vhdl_scope *vhdl_scope =
|
||||
find_entity(ivl_scope_name(lpm_scope))->get_arch()->get_scope();
|
||||
|
||||
if (visible_nexus(priv, vhdl_scope)) {
|
||||
// Already seen this signal in vhdl_scope
|
||||
}
|
||||
else {
|
||||
// Create a temporary signal to connect the nexus
|
||||
// TODO: we could avoid this for IVL_LPM_PART_PV
|
||||
vhdl_type *type = vhdl_type::type_for(ivl_lpm_width(lpm),
|
||||
ivl_lpm_signed(lpm) != 0);
|
||||
ostringstream ss;
|
||||
ss << "LPM" << ivl_lpm_basename(lpm);
|
||||
vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type));
|
||||
|
||||
link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str());
|
||||
}
|
||||
}
|
||||
else if ((con = ivl_nexus_ptr_con(nexus_ptr))) {
|
||||
if (ivl_const_width(con) == 1)
|
||||
priv->const_driver = new vhdl_const_bit(ivl_const_bits(con)[0]);
|
||||
else
|
||||
priv->const_driver =
|
||||
new vhdl_const_bits(ivl_const_bits(con), ivl_const_width(con),
|
||||
ivl_const_signed(con) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the private data in the nexus
|
||||
ivl_nexus_set_private(nexus, priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that a nexus has been initialised. I.e. all the necessary
|
||||
* statements, declarations, etc. have been generated.
|
||||
*/
|
||||
static void seen_nexus(ivl_nexus_t nexus)
|
||||
{
|
||||
if (ivl_nexus_get_private(nexus) == NULL)
|
||||
draw_nexus(nexus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a nexus to a variable reference. Given a nexus and a
|
||||
* scope, this function returns a reference to a signal that is
|
||||
* connected to the nexus and within the given scope. This signal
|
||||
* might not exist in the original Verilog source (even as a
|
||||
* compiler-generated temporary). If this nexus hasn't been
|
||||
* encountered before, the necessary code to connect up the nexus
|
||||
* will be generated.
|
||||
*/
|
||||
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus)
|
||||
{
|
||||
seen_nexus(nexus);
|
||||
|
||||
nexus_private_t *priv =
|
||||
static_cast<nexus_private_t*>(ivl_nexus_get_private(nexus));
|
||||
unsigned pin;
|
||||
string renamed(visible_nexus_signal_name(priv, scope, &pin));
|
||||
|
||||
vhdl_decl *decl = scope->get_decl(renamed);
|
||||
assert(decl);
|
||||
|
||||
vhdl_type *type = new vhdl_type(*(decl->get_type()));
|
||||
vhdl_var_ref *ref = new vhdl_var_ref(renamed.c_str(), type);
|
||||
|
||||
if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
|
||||
ref->set_slice(new vhdl_const_int(pin), 0);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate all the primitive logic gates into concurrent
|
||||
* signal assignments.
|
||||
*/
|
||||
static void declare_logic(vhdl_arch *arch, ivl_scope_t scope)
|
||||
{
|
||||
int nlogs = ivl_scope_logs(scope);
|
||||
for (int i = 0; i < nlogs; i++)
|
||||
draw_logic(arch, ivl_scope_log(scope, i));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure a signal name conforms to VHDL naming rules.
|
||||
*/
|
||||
static string make_safe_name(ivl_signal_t sig)
|
||||
{
|
||||
const char *base = ivl_signal_basename(sig);
|
||||
if (base[0] == '_')
|
||||
return string("VL") + base;
|
||||
|
||||
const char *vhdl_reserved[] = {
|
||||
"in", "out", "entity", "architecture", "inout", "array",
|
||||
"is", "not", "and", "or", "bus", "bit", "line", // Etc...
|
||||
NULL
|
||||
};
|
||||
for (const char **p = vhdl_reserved; *p != NULL; p++) {
|
||||
if (strcasecmp(*p, base) == 0) {
|
||||
return string("VL_") + base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return string(base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Declare all signals and ports for a scope.
|
||||
*/
|
||||
static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
|
||||
{
|
||||
int nsigs = ivl_scope_sigs(scope);
|
||||
for (int i = 0; i < nsigs; i++) {
|
||||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
remember_signal(sig, ent->get_arch()->get_scope());
|
||||
|
||||
string name(make_safe_name(sig));
|
||||
rename_signal(sig, name);
|
||||
|
||||
vhdl_type *sig_type;
|
||||
unsigned dimensions = ivl_signal_dimensions(sig);
|
||||
if (dimensions > 0) {
|
||||
// Arrays are implemented by generating a separate type
|
||||
// declaration for each array, and then declaring a
|
||||
// signal of that type
|
||||
|
||||
if (dimensions > 1) {
|
||||
error("> 1 dimension arrays not implemented yet");
|
||||
return;
|
||||
}
|
||||
|
||||
string type_name = name + "_Type";
|
||||
vhdl_type *base_type =
|
||||
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
|
||||
|
||||
int lsb = ivl_signal_array_base(sig);
|
||||
int msb = lsb + ivl_signal_array_count(sig) - 1;
|
||||
|
||||
vhdl_type *array_type =
|
||||
vhdl_type::array_of(base_type, type_name, msb, lsb);
|
||||
vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type);
|
||||
ent->get_arch()->get_scope()->add_decl(array_decl);
|
||||
|
||||
sig_type = new vhdl_type(*array_type);
|
||||
}
|
||||
else
|
||||
sig_type =
|
||||
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
|
||||
|
||||
ivl_signal_port_t mode = ivl_signal_port(sig);
|
||||
switch (mode) {
|
||||
case IVL_SIP_NONE:
|
||||
{
|
||||
vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type);
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Declared at " << ivl_signal_file(sig) << ":"
|
||||
<< ivl_signal_lineno(sig);
|
||||
decl->set_comment(ss.str().c_str());
|
||||
|
||||
ent->get_arch()->get_scope()->add_decl(decl);
|
||||
}
|
||||
break;
|
||||
case IVL_SIP_INPUT:
|
||||
ent->get_scope()->add_decl
|
||||
(new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN));
|
||||
break;
|
||||
case IVL_SIP_OUTPUT:
|
||||
{
|
||||
vhdl_port_decl *decl =
|
||||
new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT);
|
||||
ent->get_scope()->add_decl(decl);
|
||||
}
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
||||
// A registered output
|
||||
// In Verilog the output and reg can have the
|
||||
// same name: this is not valid in VHDL
|
||||
// Instead a new signal foo_Reg is created
|
||||
// which represents the register
|
||||
std::string newname(name);
|
||||
newname += "_Reg";
|
||||
rename_signal(sig, newname.c_str());
|
||||
|
||||
vhdl_type *reg_type = new vhdl_type(*sig_type);
|
||||
ent->get_arch()->get_scope()->add_decl
|
||||
(new vhdl_signal_decl(newname.c_str(), reg_type));
|
||||
|
||||
// Create a concurrent assignment statement to
|
||||
// connect the register to the output
|
||||
ent->get_arch()->add_stmt
|
||||
(new vhdl_cassign_stmt
|
||||
(new vhdl_var_ref(name.c_str(), NULL),
|
||||
new vhdl_var_ref(newname.c_str(), NULL)));
|
||||
}
|
||||
break;
|
||||
case IVL_SIP_INOUT:
|
||||
ent->get_scope()->add_decl
|
||||
(new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL for LPM instances in a module.
|
||||
*/
|
||||
static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope)
|
||||
{
|
||||
int nlpms = ivl_scope_lpms(scope);
|
||||
for (int i = 0; i < nlpms; i++) {
|
||||
ivl_lpm_t lpm = ivl_scope_lpm(scope, i);
|
||||
if (draw_lpm(arch, lpm) != 0)
|
||||
error("Failed to translate LPM %s", ivl_lpm_name(lpm));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map two signals together in an instantiation.
|
||||
* The signals are joined by a nexus.
|
||||
*/
|
||||
static void map_signal(ivl_signal_t to, vhdl_entity *parent,
|
||||
vhdl_comp_inst *inst)
|
||||
{
|
||||
// TODO: Work for multiple words
|
||||
ivl_nexus_t nexus = ivl_signal_nex(to, 0);
|
||||
seen_nexus(nexus);
|
||||
|
||||
vhdl_scope *arch_scope = parent->get_arch()->get_scope();
|
||||
|
||||
nexus_private_t *priv =
|
||||
static_cast<nexus_private_t*>(ivl_nexus_get_private(nexus));
|
||||
assert(priv);
|
||||
if (!visible_nexus(priv, arch_scope)) {
|
||||
// This nexus isn't attached to anything in the parent
|
||||
return;
|
||||
}
|
||||
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus);
|
||||
|
||||
string name = make_safe_name(to);
|
||||
|
||||
// If we're mapping an output of this entity to an output of
|
||||
// the child entity, then VHDL will not let us read the value
|
||||
// of the signal (i.e. it must pass straight through).
|
||||
// However, Verilog allows the signal to be read in the parent.
|
||||
// The VHDL equivalent of this is to make *both* output ports
|
||||
// a `buffer'.
|
||||
vhdl_decl *decl =
|
||||
parent->get_arch()->get_scope()->get_decl(ref->get_name());
|
||||
vhdl_port_decl *pdecl;
|
||||
if ((pdecl = dynamic_cast<vhdl_port_decl*>(decl))
|
||||
&& pdecl->get_mode() == VHDL_PORT_OUT) {
|
||||
|
||||
// First change the mode in the parent entity
|
||||
pdecl->set_mode(VHDL_PORT_BUFFER);
|
||||
|
||||
// Now change the mode in the child entity
|
||||
vhdl_port_decl *to_pdecl =
|
||||
dynamic_cast<vhdl_port_decl*>(find_scope_for_signal(to)->get_decl(name));
|
||||
assert(to_pdecl);
|
||||
to_pdecl->set_mode(VHDL_PORT_BUFFER);
|
||||
}
|
||||
|
||||
inst->map_port(name.c_str(), ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all the port mappings of a module instantiation.
|
||||
*/
|
||||
static void port_map(ivl_scope_t scope, vhdl_entity *parent,
|
||||
vhdl_comp_inst *inst)
|
||||
{
|
||||
// Find all the port mappings
|
||||
int nsigs = ivl_scope_sigs(scope);
|
||||
for (int i = 0; i < nsigs; i++) {
|
||||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
|
||||
ivl_signal_port_t mode = ivl_signal_port(sig);
|
||||
switch (mode) {
|
||||
case IVL_SIP_NONE:
|
||||
// Internal signals don't appear in the port map
|
||||
break;
|
||||
case IVL_SIP_INPUT:
|
||||
case IVL_SIP_OUTPUT:
|
||||
case IVL_SIP_INOUT:
|
||||
map_signal(sig, parent, inst);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a VHDL function from a Verilog function definition.
|
||||
*/
|
||||
static int draw_function(ivl_scope_t scope, ivl_scope_t parent)
|
||||
{
|
||||
assert(ivl_scope_type(scope) == IVL_SCT_FUNCTION);
|
||||
|
||||
// Find the containing entity
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(parent));
|
||||
assert(ent);
|
||||
|
||||
const char *funcname = ivl_scope_tname(scope);
|
||||
|
||||
assert(!ent->get_arch()->get_scope()->have_declared(funcname));
|
||||
|
||||
// The return type is worked out from the output port
|
||||
vhdl_function *func = new vhdl_function(funcname, NULL);
|
||||
|
||||
int nsigs = ivl_scope_sigs(scope);
|
||||
for (int i = 0; i < nsigs; i++) {
|
||||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
vhdl_type *sigtype =
|
||||
vhdl_type::type_for(ivl_signal_width(sig),
|
||||
ivl_signal_signed(sig) != 0);
|
||||
|
||||
string signame(make_safe_name(sig));
|
||||
|
||||
switch (ivl_signal_port(sig)) {
|
||||
case IVL_SIP_INPUT:
|
||||
func->add_param(new vhdl_param_decl(signame.c_str(), sigtype));
|
||||
break;
|
||||
case IVL_SIP_OUTPUT:
|
||||
// The magic variable Verilog_Result holds the return value
|
||||
signame = "Verilog_Result";
|
||||
func->set_type(new vhdl_type(*sigtype));
|
||||
default:
|
||||
func->get_scope()->add_decl
|
||||
(new vhdl_var_decl(signame.c_str(), sigtype));
|
||||
}
|
||||
|
||||
remember_signal(sig, func->get_scope());
|
||||
rename_signal(sig, signame);
|
||||
}
|
||||
|
||||
// Non-blocking assignment not allowed in functions
|
||||
func->get_scope()->set_allow_signal_assignment(false);
|
||||
|
||||
set_active_entity(ent);
|
||||
{
|
||||
draw_stmt(func, func->get_container(), ivl_scope_def(scope));
|
||||
}
|
||||
set_active_entity(NULL);
|
||||
|
||||
// Add a forward declaration too in case it is called by
|
||||
// another function that has already been added
|
||||
ent->get_arch()->get_scope()->add_forward_decl
|
||||
(new vhdl_forward_fdecl(func));
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Generated from function " << funcname << " at "
|
||||
<< ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope);
|
||||
func->set_comment(ss.str().c_str());
|
||||
|
||||
ent->get_arch()->get_scope()->add_decl(func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create the signals necessary to expand this task later.
|
||||
*/
|
||||
static int draw_task(ivl_scope_t scope, ivl_scope_t parent)
|
||||
{
|
||||
assert(ivl_scope_type(scope) == IVL_SCT_TASK);
|
||||
|
||||
// Find the containing entity
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(parent));
|
||||
assert(ent);
|
||||
|
||||
const char *taskname = ivl_scope_tname(scope);
|
||||
|
||||
int nsigs = ivl_scope_sigs(scope);
|
||||
for (int i = 0; i < nsigs; i++) {
|
||||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
vhdl_type *sigtype =
|
||||
vhdl_type::type_for(ivl_signal_width(sig),
|
||||
ivl_signal_signed(sig) != 0);
|
||||
|
||||
string signame(make_safe_name(sig));
|
||||
|
||||
// Check this signal isn't declared in the outer scope
|
||||
if (ent->get_arch()->get_scope()->have_declared(signame)) {
|
||||
signame += "_";
|
||||
signame += taskname;
|
||||
}
|
||||
|
||||
vhdl_signal_decl *decl = new vhdl_signal_decl(signame.c_str(), sigtype);
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Declared at " << ivl_signal_file(sig) << ":"
|
||||
<< ivl_signal_lineno(sig) << " (in task " << taskname << ")";
|
||||
decl->set_comment(ss.str().c_str());
|
||||
|
||||
ent->get_arch()->get_scope()->add_decl(decl);
|
||||
|
||||
remember_signal(sig, ent->get_arch()->get_scope());
|
||||
rename_signal(sig, signame);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an empty VHDL entity for a Verilog module.
|
||||
*/
|
||||
static void create_skeleton_entity_for(ivl_scope_t scope)
|
||||
{
|
||||
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
|
||||
|
||||
// The type name will become the entity name
|
||||
const char *tname = ivl_scope_tname(scope);
|
||||
|
||||
// Remember the scope name this entity was derived from so
|
||||
// the correct processes can be added later
|
||||
const char *derived_from = ivl_scope_name(scope);
|
||||
|
||||
// Verilog does not have the entity/architecture distinction
|
||||
// so we always create a pair and associate the architecture
|
||||
// with the entity for convenience (this also means that we
|
||||
// retain a 1-to-1 mapping of scope to VHDL element)
|
||||
vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog");
|
||||
vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch);
|
||||
|
||||
// Build a comment to add to the entity/architecture
|
||||
ostringstream ss;
|
||||
ss << "Generated from Verilog module " << ivl_scope_tname(scope)
|
||||
<< " (" << ivl_scope_def_file(scope) << ":"
|
||||
<< ivl_scope_def_lineno(scope) << ")";
|
||||
|
||||
arch->set_comment(ss.str());
|
||||
ent->set_comment(ss.str());
|
||||
|
||||
remember_entity(ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* A first pass through the hierarchy: create VHDL entities for
|
||||
* each unique Verilog module type.
|
||||
*/
|
||||
static int draw_skeleton_scope(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
if (ivl_scope_type(scope) == IVL_SCT_MODULE)
|
||||
create_skeleton_entity_for(scope);
|
||||
|
||||
return ivl_scope_children(scope, draw_skeleton_scope, scope);
|
||||
}
|
||||
|
||||
static int draw_all_signals(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
if (ivl_scope_type(scope) == IVL_SCT_MODULE) {
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
|
||||
assert(ent);
|
||||
|
||||
declare_signals(ent, scope);
|
||||
}
|
||||
|
||||
return ivl_scope_children(scope, draw_all_signals, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw all tasks and functions in the hierarchy.
|
||||
*/
|
||||
static int draw_functions(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
ivl_scope_t parent = static_cast<ivl_scope_t>(_parent);
|
||||
if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) {
|
||||
if (draw_function(scope, parent) != 0)
|
||||
return 1;
|
||||
}
|
||||
else if (ivl_scope_type(scope) == IVL_SCT_TASK) {
|
||||
if (draw_task(scope, parent) != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ivl_scope_children(scope, draw_functions, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make concurrent assignments for constants in nets. This works
|
||||
* bottom-up so that the driver is in the lowest instance it can.
|
||||
* This also has the side effect of generating all the necessary
|
||||
* nexus code.
|
||||
*/
|
||||
static int draw_constant_drivers(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
ivl_scope_children(scope, draw_constant_drivers, scope);
|
||||
|
||||
if (ivl_scope_type(scope) == IVL_SCT_MODULE) {
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
|
||||
assert(ent);
|
||||
|
||||
int nsigs = ivl_scope_sigs(scope);
|
||||
for (int i = 0; i < nsigs; i++) {
|
||||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
|
||||
for (unsigned i = ivl_signal_array_base(sig);
|
||||
i < ivl_signal_array_count(sig);
|
||||
i++) {
|
||||
// Make sure the nexus code is generated
|
||||
ivl_nexus_t nex = ivl_signal_nex(sig, i);
|
||||
seen_nexus(nex);
|
||||
|
||||
nexus_private_t *priv =
|
||||
static_cast<nexus_private_t*>(ivl_nexus_get_private(nex));
|
||||
assert(priv);
|
||||
|
||||
vhdl_scope *arch_scope = ent->get_arch()->get_scope();
|
||||
|
||||
if (priv->const_driver) {
|
||||
assert(i == 0); // TODO: Make work for more words
|
||||
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex);
|
||||
|
||||
ent->get_arch()->add_stmt
|
||||
(new vhdl_cassign_stmt(ref, priv->const_driver));
|
||||
priv->const_driver = NULL;
|
||||
}
|
||||
|
||||
scope_nexus_t *sn = visible_nexus(priv, arch_scope);
|
||||
for (list<ivl_signal_t>::const_iterator it = sn->connect.begin();
|
||||
it != sn->connect.end();
|
||||
++it) {
|
||||
vhdl_var_ref *rref =
|
||||
new vhdl_var_ref(get_renamed_signal(sn->sig).c_str(), NULL);
|
||||
vhdl_var_ref *lref =
|
||||
new vhdl_var_ref(get_renamed_signal(*it).c_str(), NULL);
|
||||
ent->get_arch()->add_stmt(new vhdl_cassign_stmt(lref, rref));
|
||||
}
|
||||
sn->connect.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
if (ivl_scope_type(scope) == IVL_SCT_MODULE) {
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
|
||||
assert(ent);
|
||||
|
||||
set_active_entity(ent);
|
||||
{
|
||||
declare_logic(ent->get_arch(), scope);
|
||||
declare_lpm(ent->get_arch(), scope);
|
||||
}
|
||||
set_active_entity(NULL);
|
||||
}
|
||||
|
||||
return ivl_scope_children(scope, draw_all_logic_and_lpm, scope);
|
||||
}
|
||||
|
||||
static int draw_hierarchy(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) {
|
||||
ivl_scope_t parent = static_cast<ivl_scope_t>(_parent);
|
||||
|
||||
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
|
||||
assert(ent);
|
||||
|
||||
vhdl_entity *parent_ent = find_entity(ivl_scope_name(parent));
|
||||
assert(parent_ent);
|
||||
|
||||
vhdl_arch *parent_arch = parent_ent->get_arch();
|
||||
assert(parent_arch != NULL);
|
||||
|
||||
// Create a forward declaration for it
|
||||
if (!parent_arch->get_scope()->have_declared(ent->get_name())) {
|
||||
vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent);
|
||||
parent_arch->get_scope()->add_decl(comp_decl);
|
||||
}
|
||||
|
||||
// And an instantiation statement
|
||||
string inst_name(ivl_scope_basename(scope));
|
||||
if (inst_name == ent->get_name()) {
|
||||
// Cannot have instance name the same as type in VHDL
|
||||
inst_name += "_Inst";
|
||||
}
|
||||
|
||||
// Need to replace any [ and ] characters that result
|
||||
// from generate statements
|
||||
string::size_type loc = inst_name.find('[', 0);
|
||||
if (loc != string::npos)
|
||||
inst_name.erase(loc, 1);
|
||||
|
||||
loc = inst_name.find(']', 0);
|
||||
if (loc != string::npos)
|
||||
inst_name.erase(loc, 1);
|
||||
|
||||
vhdl_comp_inst *inst =
|
||||
new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str());
|
||||
port_map(scope, parent_ent, inst);
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Generated from instantiation at "
|
||||
<< ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope);
|
||||
inst->set_comment(ss.str().c_str());
|
||||
|
||||
parent_arch->add_stmt(inst);
|
||||
}
|
||||
|
||||
return ivl_scope_children(scope, draw_hierarchy, scope);
|
||||
}
|
||||
|
||||
int draw_scope(ivl_scope_t scope, void *_parent)
|
||||
{
|
||||
int rc = draw_skeleton_scope(scope, _parent);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = draw_all_signals(scope, _parent);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = draw_all_logic_and_lpm(scope, _parent);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = draw_hierarchy(scope, _parent);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = draw_functions(scope, _parent);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = draw_constant_drivers(scope, _parent);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,697 @@
|
||||
/*
|
||||
* VHDL code generation for statements.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
|
||||
/*
|
||||
* VHDL has no real equivalent of Verilog's $finish task. The
|
||||
* current solution is to use `assert false ...' to terminate
|
||||
* the simulator. This isn't great, as the simulator will
|
||||
* return a failure exit code when in fact it completed
|
||||
* successfully.
|
||||
*
|
||||
* An alternative is to use the VHPI interface supported by
|
||||
* some VHDL simulators and implement the $finish funcitonality
|
||||
* in C. This function can be enabled with the flag
|
||||
* -puse-vhpi-finish=1.
|
||||
*/
|
||||
static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
const char *use_vhpi = ivl_design_flag(get_vhdl_design(), "use-vhpi-finish");
|
||||
if (strcmp(use_vhpi, "1") == 0) {
|
||||
//get_active_entity()->requires_package("work.Verilog_Support");
|
||||
container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish"));
|
||||
}
|
||||
else {
|
||||
container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL for system tasks (like $display). Not all of
|
||||
* these are supported.
|
||||
*/
|
||||
static int draw_stask(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
const char *name = ivl_stmt_name(stmt);
|
||||
|
||||
if (strcmp(name, "$display") == 0)
|
||||
return draw_stask_display(proc, container, stmt, true);
|
||||
else if (strcmp(name, "$write") == 0)
|
||||
return draw_stask_display(proc, container, stmt, false);
|
||||
else if (strcmp(name, "$finish") == 0)
|
||||
return draw_stask_finish(proc, container, stmt);
|
||||
else {
|
||||
error("No VHDL translation for system task %s", name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL for a block of Verilog statements. This doesn't
|
||||
* actually do anything, other than recursively translate the
|
||||
* block's statements and add them to the process. This is OK as
|
||||
* the stmt_container class behaves like a Verilog block.
|
||||
*/
|
||||
static int draw_block(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
int count = ivl_stmt_block_count(stmt);
|
||||
for (int i = 0; i < count; i++) {
|
||||
ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i);
|
||||
if (draw_stmt(proc, container, stmt_i, is_last && i == count - 1) != 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A no-op statement. This corresponds to a `null' statement in VHDL.
|
||||
*/
|
||||
static int draw_noop(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
container->add_stmt(new vhdl_null_stmt());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
if (!sig) {
|
||||
error("Only signals as lvals supported at the moment");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vhdl_expr *base = NULL;
|
||||
ivl_expr_t e_off = ivl_lval_part_off(lval);
|
||||
if (NULL == e_off)
|
||||
e_off = ivl_lval_idx(lval);
|
||||
if (e_off) {
|
||||
if ((base = translate_expr(e_off)) == NULL)
|
||||
return NULL;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
base = base->cast(&integer);
|
||||
}
|
||||
|
||||
unsigned lval_width = ivl_lval_width(lval);
|
||||
|
||||
string signame(get_renamed_signal(sig));
|
||||
vhdl_decl *decl = scope->get_decl(signame);
|
||||
assert(decl);
|
||||
|
||||
vhdl_type *ltype = new vhdl_type(*decl->get_type());
|
||||
vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype);
|
||||
if (base) {
|
||||
if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
|
||||
lval_ref->set_slice(base, 0);
|
||||
else
|
||||
lval_ref->set_slice(base, lval_width - 1);
|
||||
}
|
||||
|
||||
return lval_ref;
|
||||
}
|
||||
|
||||
static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc,
|
||||
list<vhdl_var_ref*> &lvals)
|
||||
{
|
||||
int nlvals = ivl_stmt_lvals(stmt);
|
||||
for (int i = 0; i < nlvals; i++) {
|
||||
ivl_lval_t lval = ivl_stmt_lval(stmt, i);
|
||||
vhdl_var_ref *lhs = make_assign_lhs(lval, proc->get_scope());
|
||||
if (NULL == lhs)
|
||||
return false;
|
||||
|
||||
lvals.push_back(lhs);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an assignment of type T for the Verilog statement stmt.
|
||||
*/
|
||||
template <class T>
|
||||
void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool blocking)
|
||||
{
|
||||
list<vhdl_var_ref*> lvals;
|
||||
if (!assignment_lvals(stmt, proc, lvals))
|
||||
return;
|
||||
|
||||
vhdl_expr *rhs, *rhs2 = NULL;
|
||||
ivl_expr_t rval = ivl_stmt_rval(stmt);
|
||||
if (ivl_expr_type(rval) == IVL_EX_TERNARY) {
|
||||
rhs = translate_expr(ivl_expr_oper2(rval));
|
||||
rhs2 = translate_expr(ivl_expr_oper3(rval));
|
||||
}
|
||||
else
|
||||
rhs = translate_expr(rval);
|
||||
if (rhs == NULL)
|
||||
return;
|
||||
|
||||
if (lvals.size() == 1) {
|
||||
vhdl_var_ref *lhs = lvals.front();
|
||||
rhs = rhs->cast(lhs->get_type());
|
||||
|
||||
ivl_expr_t i_delay;
|
||||
vhdl_expr *after = NULL;
|
||||
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
|
||||
after = translate_time_expr(i_delay);
|
||||
|
||||
// A small optimisation is to expand ternary RHSs into an
|
||||
// if statement (eliminates a function call and produces
|
||||
// more idiomatic code)
|
||||
if (ivl_expr_type(rval) == IVL_EX_TERNARY) {
|
||||
rhs2 = rhs2->cast(lhs->get_type());
|
||||
vhdl_var_ref *lhs2 =
|
||||
make_assign_lhs(ivl_stmt_lval(stmt, 0), proc->get_scope());
|
||||
|
||||
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
|
||||
if (NULL == test)
|
||||
return;
|
||||
|
||||
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
|
||||
|
||||
// True part
|
||||
{
|
||||
T *a = new T(lhs, rhs);
|
||||
if (after)
|
||||
a->set_after(after);
|
||||
vhdif->get_then_container()->add_stmt(a);
|
||||
}
|
||||
|
||||
// False part
|
||||
{
|
||||
T *a = new T(lhs2, rhs2);
|
||||
if (after)
|
||||
a->set_after(translate_time_expr(i_delay));
|
||||
vhdif->get_else_container()->add_stmt(a);
|
||||
}
|
||||
|
||||
container->add_stmt(vhdif);
|
||||
return;
|
||||
}
|
||||
|
||||
// Where possible, move constant assignments into the
|
||||
// declaration as initializers. This optimisation is only
|
||||
// performed on assignments of constant values to prevent
|
||||
// ordering problems.
|
||||
|
||||
// This also has another application: If this is an `inital'
|
||||
// process and we haven't yet generated a `wait' statement then
|
||||
// moving the assignment to the initialization preserves the
|
||||
// expected Verilog behaviour: VHDL does not distinguish
|
||||
// `initial' and `always' processes so an `always' process might
|
||||
// be activatated before an `initial' process at time 0. The
|
||||
// `always' process may then use the uninitialized signal value.
|
||||
// The second test ensures that we only try to initialise
|
||||
// internal signals not ports
|
||||
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
|
||||
if (proc->get_scope()->initializing()
|
||||
&& ivl_signal_port(ivl_lval_sig(lval)) == IVL_SIP_NONE
|
||||
&& !decl->has_initial()
|
||||
&& rhs->constant()
|
||||
&& decl->get_type()->get_name() != VHDL_TYPE_ARRAY) {
|
||||
|
||||
// If this assignment is not in the top-level container
|
||||
// it will not be made on all paths through the code
|
||||
// This precludes any future extraction of an initialiser
|
||||
if (container != proc->get_container())
|
||||
decl->set_initial(NULL); // Default initial value
|
||||
else {
|
||||
decl->set_initial(rhs);
|
||||
delete lhs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
T *a = new T(lhs, rhs);
|
||||
container->add_stmt(a);
|
||||
|
||||
if (after != NULL)
|
||||
a->set_after(after);
|
||||
}
|
||||
else {
|
||||
// Multiple lvals are implemented by first assigning the complete
|
||||
// RHS to a temporary, and then assigning each lval in turn as
|
||||
// bit-selects of the temporary
|
||||
|
||||
static int tmp_count = 0;
|
||||
ostringstream ss;
|
||||
ss << "Verilog_Assign_Tmp_" << tmp_count++;
|
||||
string tmpname = ss.str();
|
||||
|
||||
proc->get_scope()->add_decl
|
||||
(new vhdl_var_decl(tmpname.c_str(), new vhdl_type(*rhs->get_type())));
|
||||
|
||||
vhdl_var_ref *tmp_ref =
|
||||
new vhdl_var_ref(tmpname.c_str(), new vhdl_type(*rhs->get_type()));
|
||||
container->add_stmt(new vhdl_assign_stmt(tmp_ref, rhs));
|
||||
|
||||
list<vhdl_var_ref*>::iterator it;
|
||||
int width_so_far = 0;
|
||||
for (it = lvals.begin(); it != lvals.end(); ++it) {
|
||||
vhdl_var_ref *tmp_rhs =
|
||||
new vhdl_var_ref(tmpname.c_str(), new vhdl_type(*rhs->get_type()));
|
||||
|
||||
int lval_width = (*it)->get_type()->get_width();
|
||||
vhdl_expr *slice_base = new vhdl_const_int(width_so_far);
|
||||
tmp_rhs->set_slice(slice_base, lval_width - 1);
|
||||
|
||||
ivl_expr_t i_delay;
|
||||
vhdl_expr *after = NULL;
|
||||
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
|
||||
after = translate_time_expr(i_delay);
|
||||
|
||||
T *a = new T(*it, tmp_rhs);
|
||||
if (after)
|
||||
a->set_after(after);
|
||||
|
||||
container->add_stmt(a);
|
||||
|
||||
width_so_far += lval_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A non-blocking assignment inside a process. The semantics for
|
||||
* this are essentially the same as VHDL's non-blocking signal
|
||||
* assignment.
|
||||
*/
|
||||
static int draw_nbassign(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
assert(proc->get_scope()->allow_signal_assignment());
|
||||
|
||||
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_assign(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
if (proc->get_scope()->allow_signal_assignment()) {
|
||||
// Blocking assignment is implemented as non-blocking assignment
|
||||
// followed by a zero-time wait
|
||||
// This follows the Verilog semantics fairly closely.
|
||||
|
||||
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
|
||||
|
||||
// Don't generate a zero-wait if this is the last statement in
|
||||
// the process
|
||||
if (!is_last)
|
||||
container->add_stmt
|
||||
(new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0)));
|
||||
}
|
||||
else
|
||||
make_assignment<vhdl_assign_stmt>(proc, container, stmt, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delay statements are equivalent to the `wait for' form of the
|
||||
* VHDL wait statement.
|
||||
*/
|
||||
static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
// This currently ignores the time units and precision
|
||||
// of the enclosing scope
|
||||
// A neat way to do this would be to make these values
|
||||
// constants in the scope (type is Time), and have the
|
||||
// VHDL wait statement compute the value from that.
|
||||
// The other solution is to add them as parameters to
|
||||
// the vhdl_process class
|
||||
vhdl_expr *time;
|
||||
if (ivl_statement_type(stmt) == IVL_ST_DELAY) {
|
||||
uint64_t value = ivl_stmt_delay_val(stmt);
|
||||
time = new vhdl_const_time(value, TIME_UNIT_NS);
|
||||
}
|
||||
else {
|
||||
time = translate_time_expr(ivl_stmt_delay_expr(stmt));
|
||||
if (NULL == time)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
|
||||
vhdl_wait_stmt *wait =
|
||||
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
||||
container->add_stmt(wait);
|
||||
|
||||
// Expand the sub-statement as well
|
||||
// Often this would result in a useless `null' statement which
|
||||
// is caught here instead
|
||||
if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP)
|
||||
draw_stmt(proc, container, sub_stmt);
|
||||
|
||||
// Any further assignments occur after simulation time 0
|
||||
// so they cannot be used to initialize signal declarations
|
||||
// (if this scope is an initial process)
|
||||
proc->get_scope()->set_initializing(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A wait statement waits for a level change on a @(..) list of
|
||||
* signals. Purely combinatorial processes (i.e. no posedge/negedge
|
||||
* events) produce a `wait on' statement at the end of the process.
|
||||
* Sequential processes produce a `wait until' statement at the
|
||||
* start of the process.
|
||||
*/
|
||||
static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
// Wait statements only occur in processes
|
||||
vhdl_process *proc = dynamic_cast<vhdl_process*>(_proc);
|
||||
assert(proc); // Catch not process
|
||||
|
||||
vhdl_binop_expr *test =
|
||||
new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean());
|
||||
|
||||
int nevents = ivl_stmt_nevent(stmt);
|
||||
|
||||
bool combinatorial = true; // True if no negedge/posedge events
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
ivl_event_t event = ivl_stmt_events(stmt, i);
|
||||
if (ivl_event_npos(event) > 0 || ivl_event_nneg(event) > 0)
|
||||
combinatorial = false;
|
||||
}
|
||||
|
||||
if (combinatorial) {
|
||||
vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_ON);
|
||||
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
ivl_event_t event = ivl_stmt_events(stmt, i);
|
||||
|
||||
int nany = ivl_event_nany(event);
|
||||
for (int i = 0; i < nany; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_any(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
|
||||
wait->add_sensitivity(ref->get_name());
|
||||
delete ref;
|
||||
}
|
||||
}
|
||||
|
||||
draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true);
|
||||
container->add_stmt(wait);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
ivl_event_t event = ivl_stmt_events(stmt, i);
|
||||
|
||||
int nany = ivl_event_nany(event);
|
||||
for (int i = 0; i < nany; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_any(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
|
||||
ref->set_name(ref->get_name() + "'Event");
|
||||
test->add_expr(ref);
|
||||
}
|
||||
|
||||
int nneg = ivl_event_nneg(event);
|
||||
for (int i = 0; i < nneg; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_neg(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
vhdl_fcall *detect =
|
||||
new vhdl_fcall("falling_edge", vhdl_type::boolean());
|
||||
detect->add_expr(ref);
|
||||
|
||||
test->add_expr(detect);
|
||||
}
|
||||
|
||||
int npos = ivl_event_npos(event);
|
||||
for (int i = 0; i < npos; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_pos(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
vhdl_fcall *detect =
|
||||
new vhdl_fcall("rising_edge", vhdl_type::boolean());
|
||||
detect->add_expr(ref);
|
||||
|
||||
test->add_expr(detect);
|
||||
}
|
||||
}
|
||||
|
||||
container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test));
|
||||
draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_if(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
|
||||
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
|
||||
|
||||
ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt);
|
||||
if (cond_true_stmt)
|
||||
draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt, is_last);
|
||||
|
||||
ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt);
|
||||
if (cond_false_stmt)
|
||||
draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last);
|
||||
|
||||
container->add_stmt(vhdif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
|
||||
// VHDL case expressions are required to be quite simple: variable
|
||||
// references or slices. So we may need to create a temporary
|
||||
// variable to hold the result of the expression evaluation
|
||||
if (typeid(*test) != typeid(vhdl_var_ref)) {
|
||||
const char *tmp_name = "Verilog_Case_Ex";
|
||||
vhdl_type *test_type = new vhdl_type(*test->get_type());
|
||||
|
||||
if (!proc->get_scope()->have_declared(tmp_name)) {
|
||||
proc->get_scope()->add_decl
|
||||
(new vhdl_var_decl(tmp_name, new vhdl_type(*test_type)));
|
||||
}
|
||||
|
||||
vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL);
|
||||
container->add_stmt(new vhdl_assign_stmt(tmp_ref, test));
|
||||
|
||||
test = new vhdl_var_ref(tmp_name, test_type);
|
||||
}
|
||||
|
||||
vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test);
|
||||
container->add_stmt(vhdlcase);
|
||||
|
||||
// VHDL is more strict than Verilog about covering every
|
||||
// possible case. So make sure we add an 'others' branch
|
||||
// if there isn't a default one.
|
||||
bool have_others = false;
|
||||
|
||||
int nbranches = ivl_stmt_case_count(stmt);
|
||||
for (int i = 0; i < nbranches; i++) {
|
||||
vhdl_expr *when;
|
||||
ivl_expr_t net = ivl_stmt_case_expr(stmt, i);
|
||||
if (net) {
|
||||
when = translate_expr(net)->cast(test->get_type());
|
||||
if (NULL == when)
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
when = new vhdl_var_ref("others", NULL);
|
||||
have_others = true;
|
||||
}
|
||||
|
||||
vhdl_case_branch *branch = new vhdl_case_branch(when);
|
||||
vhdlcase->add_branch(branch);
|
||||
|
||||
ivl_statement_t stmt_i = ivl_stmt_case_stmt(stmt, i);
|
||||
draw_stmt(proc, branch->get_container(), stmt_i, is_last);
|
||||
}
|
||||
|
||||
if (!have_others) {
|
||||
vhdl_case_branch *others =
|
||||
new vhdl_case_branch(new vhdl_var_ref("others", NULL));
|
||||
others->get_container()->add_stmt(new vhdl_null_stmt());
|
||||
vhdlcase->add_branch(others);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_while(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
|
||||
// The test must be a Boolean (and std_logic and (un)signed types
|
||||
// must be explicitly cast unlike in Verilog)
|
||||
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
|
||||
test = test->cast(&boolean);
|
||||
|
||||
vhdl_while_stmt *loop = new vhdl_while_stmt(test);
|
||||
container->add_stmt(loop);
|
||||
|
||||
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_forever(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
vhdl_loop_stmt *loop = new vhdl_loop_stmt;
|
||||
container->add_stmt(loop);
|
||||
|
||||
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_repeat(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
vhdl_expr *times = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||
if (NULL == times)
|
||||
return 1;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
times = times->cast(&integer);
|
||||
|
||||
const char *it_name = "Verilog_Repeat";
|
||||
vhdl_for_stmt *loop =
|
||||
new vhdl_for_stmt(it_name, new vhdl_const_int(1), times);
|
||||
container->add_stmt(loop);
|
||||
|
||||
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tasks are difficult to translate to VHDL since they allow things
|
||||
* not allowed by VHDL's corresponding procedures (e.g. updating
|
||||
* global variables. The solution here is to expand tasks in-line.
|
||||
*/
|
||||
int draw_utask(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
ivl_scope_t tscope = ivl_stmt_call(stmt);
|
||||
|
||||
// TODO: adding some comments to the output would be helpful
|
||||
|
||||
// TOOD: this completely ignores paremeters!
|
||||
draw_stmt(proc, container, ivl_scope_def(tscope), false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL statements for the given Verilog statement and
|
||||
* add them to the given VHDL process. The container is the
|
||||
* location to add statements: e.g. the process body, a branch
|
||||
* of an if statement, etc.
|
||||
*
|
||||
* The flag is_last should be set if this is the final statement
|
||||
* in a block or process. It avoids generating useless `wait for 0ns'
|
||||
* statements if the next statement would be a wait anyway.
|
||||
*/
|
||||
int draw_stmt(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
assert(stmt);
|
||||
|
||||
switch (ivl_statement_type(stmt)) {
|
||||
case IVL_ST_STASK:
|
||||
return draw_stask(proc, container, stmt);
|
||||
case IVL_ST_BLOCK:
|
||||
return draw_block(proc, container, stmt, is_last);
|
||||
case IVL_ST_NOOP:
|
||||
return draw_noop(proc, container, stmt);
|
||||
case IVL_ST_ASSIGN:
|
||||
return draw_assign(proc, container, stmt, is_last);
|
||||
case IVL_ST_ASSIGN_NB:
|
||||
return draw_nbassign(proc, container, stmt);
|
||||
case IVL_ST_DELAY:
|
||||
case IVL_ST_DELAYX:
|
||||
return draw_delay(proc, container, stmt);
|
||||
case IVL_ST_WAIT:
|
||||
return draw_wait(proc, container, stmt);
|
||||
case IVL_ST_CONDIT:
|
||||
return draw_if(proc, container, stmt, is_last);
|
||||
case IVL_ST_CASE:
|
||||
return draw_case(proc, container, stmt, is_last);
|
||||
case IVL_ST_WHILE:
|
||||
return draw_while(proc, container, stmt);
|
||||
case IVL_ST_FOREVER:
|
||||
return draw_forever(proc, container, stmt);
|
||||
case IVL_ST_REPEAT:
|
||||
return draw_repeat(proc, container, stmt);
|
||||
case IVL_ST_UTASK:
|
||||
return draw_utask(proc, container, stmt);
|
||||
case IVL_ST_FORCE:
|
||||
case IVL_ST_RELEASE:
|
||||
error("force/release statements cannot be translated to VHDL");
|
||||
return 1;
|
||||
case IVL_ST_DISABLE:
|
||||
error("disable statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
case IVL_ST_CASEX:
|
||||
error("casex statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
case IVL_ST_FORK:
|
||||
error("fork statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
case IVL_ST_CASSIGN:
|
||||
case IVL_ST_DEASSIGN:
|
||||
error("continuous procedural assignment cannot be translated to VHDL");
|
||||
return 1;
|
||||
default:
|
||||
error("No VHDL translation for statement at %s:%d (type = %d)",
|
||||
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt),
|
||||
ivl_statement_type(stmt));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Support functions for VHDL output.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
#include "support.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
void require_support_function(support_function_t f)
|
||||
{
|
||||
vhdl_scope *scope = get_active_entity()->get_arch()->get_scope();
|
||||
if (!scope->have_declared(support_function::function_name(f)))
|
||||
scope->add_decl(new support_function(f));
|
||||
}
|
||||
|
||||
const char *support_function::function_name(support_function_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case SF_UNSIGNED_TO_BOOLEAN: return "Unsigned_To_Boolean";
|
||||
case SF_SIGNED_TO_BOOLEAN: return "Signed_To_Boolean";
|
||||
case SF_BOOLEAN_TO_LOGIC: return "Boolean_To_Logic";
|
||||
case SF_REDUCE_OR: return "Reduce_OR";
|
||||
case SF_REDUCE_AND: return "Reduce_AND";
|
||||
case SF_REDUCE_XOR: return "Reduce_XOR";
|
||||
case SF_TERNARY_LOGIC: return "Ternary_Logic";
|
||||
case SF_TERNARY_UNSIGNED: return "Ternary_Unsigned";
|
||||
case SF_TERNARY_SIGNED: return "Ternary_Signed";
|
||||
case SF_LOGIC_TO_INTEGER: return "Logic_To_Integer";
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
vhdl_type *support_function::function_type(support_function_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case SF_UNSIGNED_TO_BOOLEAN:
|
||||
case SF_SIGNED_TO_BOOLEAN:
|
||||
return vhdl_type::boolean();
|
||||
case SF_BOOLEAN_TO_LOGIC:
|
||||
case SF_REDUCE_OR:
|
||||
case SF_REDUCE_AND:
|
||||
case SF_REDUCE_XOR:
|
||||
case SF_TERNARY_LOGIC:
|
||||
return vhdl_type::std_logic();
|
||||
case SF_TERNARY_SIGNED:
|
||||
return new vhdl_type(VHDL_TYPE_SIGNED);
|
||||
case SF_TERNARY_UNSIGNED:
|
||||
return new vhdl_type(VHDL_TYPE_UNSIGNED);
|
||||
case SF_LOGIC_TO_INTEGER:
|
||||
return vhdl_type::integer();
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void support_function::emit_ternary(std::ostream &of, int level) const
|
||||
{
|
||||
of << nl_string(level) << "begin" << nl_string(indent(level))
|
||||
<< "if T then return X; else return Y; end if;";
|
||||
}
|
||||
|
||||
void support_function::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << nl_string(level) << "function " << function_name(type_);
|
||||
|
||||
switch (type_) {
|
||||
case SF_UNSIGNED_TO_BOOLEAN:
|
||||
of << "(X : unsigned) return Boolean is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "return X /= To_Unsigned(0, X'Length);";
|
||||
break;
|
||||
case SF_SIGNED_TO_BOOLEAN:
|
||||
of << "(X : signed) return Boolean is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "return X /= To_Signed(0, X'Length);";
|
||||
break;
|
||||
case SF_BOOLEAN_TO_LOGIC:
|
||||
of << "(B : Boolean) return std_logic is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "if B then" << nl_string(indent(indent(level)))
|
||||
<< "return '1';" << nl_string(indent(level))
|
||||
<< "else" << nl_string(indent(indent(level)))
|
||||
<< "return '0';" << nl_string(indent(level))
|
||||
<< "end if;";
|
||||
break;
|
||||
case SF_REDUCE_OR:
|
||||
of << "(X : std_logic_vector) return std_logic is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
|
||||
<< "if X(I) = '1' then" << nl_string(indent(indent(indent(level))))
|
||||
<< "return '1';" << nl_string(indent(indent(level)))
|
||||
<< "end if;" << nl_string(indent(level))
|
||||
<< "end loop;" << nl_string(indent(level))
|
||||
<< "return '0';";
|
||||
break;
|
||||
case SF_REDUCE_AND:
|
||||
of << "(X : std_logic_vector) return std_logic is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
|
||||
<< "if X(I) = '0' then" << nl_string(indent(indent(indent(level))))
|
||||
<< "return '0';" << nl_string(indent(indent(level)))
|
||||
<< "end if;" << nl_string(indent(level))
|
||||
<< "end loop;" << nl_string(indent(level))
|
||||
<< "return '1';";
|
||||
break;
|
||||
case SF_REDUCE_XOR:
|
||||
of << "(X : std_logic_vector) return std_logic is"
|
||||
<< nl_string(indent(level))
|
||||
<< "variable R : std_logic := '0';" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
|
||||
<< "R := X(I) xor R;" << nl_string(indent(level))
|
||||
<< "end loop;" << nl_string(indent(level))
|
||||
<< "return R;";
|
||||
break;
|
||||
case SF_TERNARY_LOGIC:
|
||||
of << "(T : Boolean; X, Y : std_logic) return std_logic is";
|
||||
emit_ternary(of, level);
|
||||
break;
|
||||
case SF_TERNARY_SIGNED:
|
||||
of << "(T : Boolean; X, Y : signed) return signed is";
|
||||
emit_ternary(of, level);
|
||||
break;
|
||||
case SF_TERNARY_UNSIGNED:
|
||||
of << "(T : Boolean; X, Y : unsigned) return unsigned is";
|
||||
emit_ternary(of, level);
|
||||
break;
|
||||
case SF_LOGIC_TO_INTEGER:
|
||||
of << "(X : std_logic) return integer is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "if X = '1' then return 1; else return 0; end if;";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
of << nl_string(level) << "end function;";
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Support functions for VHDL output.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INC_SUPPORT_HH
|
||||
#define INC_SUPPORT_HH
|
||||
|
||||
#include "vhdl_syntax.hh"
|
||||
|
||||
enum support_function_t {
|
||||
SF_UNSIGNED_TO_BOOLEAN = 0,
|
||||
SF_SIGNED_TO_BOOLEAN,
|
||||
SF_BOOLEAN_TO_LOGIC,
|
||||
SF_REDUCE_OR,
|
||||
SF_REDUCE_AND,
|
||||
SF_REDUCE_XOR,
|
||||
SF_TERNARY_LOGIC,
|
||||
SF_TERNARY_UNSIGNED,
|
||||
SF_TERNARY_SIGNED,
|
||||
SF_LOGIC_TO_INTEGER,
|
||||
};
|
||||
|
||||
class support_function : public vhdl_function {
|
||||
public:
|
||||
support_function(support_function_t type)
|
||||
: vhdl_function(function_name(type), function_type(type)),
|
||||
type_(type) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
static const char *function_name(support_function_t type);
|
||||
static vhdl_type *function_type(support_function_t type);
|
||||
|
||||
private:
|
||||
void emit_ternary(std::ostream &of, int level) const;
|
||||
|
||||
support_function_t type_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* VHDL code generator for Icarus Verilog.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_target.h"
|
||||
#include "vhdl_element.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
/*
|
||||
* Maps a signal to the scope it is defined within. Also
|
||||
* provides a mechanism for renaming signals -- i.e. when
|
||||
* an output has the same name as register: valid in Verilog
|
||||
* but not in VHDL, so two separate signals need to be
|
||||
* defined.
|
||||
*/
|
||||
struct signal_defn_t {
|
||||
std::string renamed; // The name of the VHDL signal
|
||||
vhdl_scope *scope; // The scope where it is defined
|
||||
};
|
||||
|
||||
typedef std::map<ivl_signal_t, signal_defn_t> signal_defn_map_t;
|
||||
|
||||
|
||||
static int g_errors = 0; // Total number of errors encountered
|
||||
static entity_list_t g_entities; // All entities to emit
|
||||
static signal_defn_map_t g_known_signals;
|
||||
static ivl_design_t g_design;
|
||||
|
||||
|
||||
/*
|
||||
* Called when an unrecoverable problem is encountered.
|
||||
*/
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
std::va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
std::printf("VHDL conversion error: "); // Source/line number?
|
||||
std::vprintf(fmt, args);
|
||||
std::putchar('\n');
|
||||
va_end(args);
|
||||
|
||||
g_errors++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an entity given a scope name.
|
||||
*/
|
||||
vhdl_entity *find_entity(const std::string &sname)
|
||||
{
|
||||
entity_list_t::const_iterator it;
|
||||
for (it = g_entities.begin(); it != g_entities.end(); ++it) {
|
||||
if ((*it)->get_derived_from() == sname)
|
||||
return *it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an entity/architecture pair to the list of entities
|
||||
* to emit.
|
||||
*/
|
||||
void remember_entity(vhdl_entity* ent)
|
||||
{
|
||||
assert(find_entity(ent->get_derived_from()) == NULL);
|
||||
g_entities.push_back(ent);
|
||||
}
|
||||
|
||||
bool seen_signal_before(ivl_signal_t sig)
|
||||
{
|
||||
return g_known_signals.find(sig) != g_known_signals.end();
|
||||
}
|
||||
|
||||
/*
|
||||
* Remeber the association of signal to entity.
|
||||
*/
|
||||
void remember_signal(ivl_signal_t sig, vhdl_scope *scope)
|
||||
{
|
||||
assert(!seen_signal_before(sig));
|
||||
|
||||
signal_defn_t defn = { ivl_signal_basename(sig), scope };
|
||||
g_known_signals[sig] = defn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the VHDL name of a Verilog signal.
|
||||
*/
|
||||
void rename_signal(ivl_signal_t sig, const std::string &renamed)
|
||||
{
|
||||
assert(seen_signal_before(sig));
|
||||
|
||||
g_known_signals[sig].renamed = renamed;
|
||||
}
|
||||
|
||||
vhdl_scope *find_scope_for_signal(ivl_signal_t sig)
|
||||
{
|
||||
assert(seen_signal_before(sig));
|
||||
|
||||
return g_known_signals[sig].scope;
|
||||
}
|
||||
|
||||
const std::string &get_renamed_signal(ivl_signal_t sig)
|
||||
{
|
||||
assert(seen_signal_before(sig));
|
||||
|
||||
return g_known_signals[sig].renamed;
|
||||
}
|
||||
|
||||
ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope)
|
||||
{
|
||||
signal_defn_map_t::const_iterator it;
|
||||
for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) {
|
||||
if (((*it).second.scope == scope
|
||||
|| (*it).second.scope == scope->get_parent())
|
||||
&& (*it).second.renamed == name)
|
||||
return (*it).first;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ivl_design_t get_vhdl_design()
|
||||
{
|
||||
return g_design;
|
||||
}
|
||||
|
||||
extern "C" int target_design(ivl_design_t des)
|
||||
{
|
||||
ivl_scope_t *roots;
|
||||
unsigned int nroots;
|
||||
ivl_design_roots(des, &roots, &nroots);
|
||||
|
||||
g_design = des;
|
||||
|
||||
for (unsigned int i = 0; i < nroots; i++)
|
||||
draw_scope(roots[i], NULL);
|
||||
|
||||
ivl_design_process(des, draw_process, NULL);
|
||||
|
||||
// Write the generated elements to the output file
|
||||
// only if there are no errors
|
||||
if (0 == g_errors) {
|
||||
const char *ofname = ivl_design_flag(des, "-o");
|
||||
ofstream outfile(ofname);
|
||||
|
||||
// Make sure we only emit one example of each type of entity
|
||||
set<string> seen_entities;
|
||||
|
||||
for (entity_list_t::iterator it = g_entities.begin();
|
||||
it != g_entities.end();
|
||||
++it) {
|
||||
if (seen_entities.find((*it)->get_name()) == seen_entities.end()) {
|
||||
(*it)->emit(outfile);
|
||||
seen_entities.insert((*it)->get_name());
|
||||
}
|
||||
}
|
||||
|
||||
outfile.close();
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for (entity_list_t::iterator it = g_entities.begin();
|
||||
it != g_entities.end();
|
||||
++it)
|
||||
delete (*it);
|
||||
g_entities.clear();
|
||||
|
||||
return g_errors;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
functor:cprop
|
||||
functor:nodangle
|
||||
-t:dll
|
||||
flag:DLL=vhdl.tgt
|
||||
@@ -0,0 +1,49 @@
|
||||
/* vhdl_config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* VHDL abstract syntax elements.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "vhdl_element.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
static const int VHDL_INDENT = 2; // Spaces to indent
|
||||
|
||||
int indent(int level)
|
||||
{
|
||||
return level + VHDL_INDENT;
|
||||
}
|
||||
|
||||
std::string nl_string(int level)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
newline(ss, level);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a newline and indent to the correct level.
|
||||
*/
|
||||
void newline(std::ostream &of, int level)
|
||||
{
|
||||
of << std::endl;
|
||||
while (level--)
|
||||
of << ' ';
|
||||
}
|
||||
|
||||
void blank_line(std::ostream &of, int level)
|
||||
{
|
||||
of << std::endl;
|
||||
newline(of, level);
|
||||
}
|
||||
|
||||
void vhdl_element::set_comment(std::string comment)
|
||||
{
|
||||
comment_ = comment;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the comment for any element. The comment is either on
|
||||
* a line before the element (end_of_line is false) or at the
|
||||
* end of the line containing the element (end_of_line is true).
|
||||
*/
|
||||
void vhdl_element::emit_comment(std::ostream &of, int level,
|
||||
bool end_of_line) const
|
||||
{
|
||||
if (comment_.size() > 0) {
|
||||
if (end_of_line)
|
||||
of << " ";
|
||||
of << "-- " << comment_;
|
||||
if (!end_of_line)
|
||||
newline(of, level);
|
||||
}
|
||||
}
|
||||
|
||||
void vhdl_element::print() const
|
||||
{
|
||||
emit(std::cout, 0);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* VHDL abstract syntax elements.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INC_VHDL_ELEMENT_HH
|
||||
#define INC_VHDL_ELEMENT_HH
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
typedef std::list<std::string> string_list_t;
|
||||
|
||||
/*
|
||||
* Any VHDL syntax element. Each element can also contain a comment.
|
||||
*/
|
||||
class vhdl_element {
|
||||
public:
|
||||
virtual ~vhdl_element() {}
|
||||
|
||||
virtual void emit(std::ostream &of, int level=0) const = 0;
|
||||
void print() const;
|
||||
|
||||
void set_comment(std::string comment);
|
||||
protected:
|
||||
void emit_comment(std::ostream &of, int level,
|
||||
bool end_of_line=false) const;
|
||||
private:
|
||||
std::string comment_;
|
||||
};
|
||||
|
||||
typedef std::list<vhdl_element*> element_list_t;
|
||||
|
||||
int indent(int level);
|
||||
void newline(std::ostream &of, int level);
|
||||
std::string nl_string(int level);
|
||||
void blank_line(std::ostream &of, int level);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user