mirror of https://github.com/YosysHQ/yosys.git
Compare commits
1025 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
1801abf30a | |
|
|
d8587f44f0 | |
|
|
4230ebff71 | |
|
|
715bc4d7d2 | |
|
|
1414012676 | |
|
|
7fef67a141 | |
|
|
d6106f141c | |
|
|
680bb69d85 | |
|
|
94ec78b6e8 | |
|
|
6f111118de | |
|
|
9d0cdb8551 | |
|
|
4c8e61a52b | |
|
|
07924a3c62 | |
|
|
2b3f4c37f5 | |
|
|
15e09163cd | |
|
|
c0779f488a | |
|
|
5c6de04467 | |
|
|
ffa8618413 | |
|
|
2159a0e634 | |
|
|
0c2786be1f | |
|
|
1c831aa50d | |
|
|
d322e2fbe0 | |
|
|
7bcda9d304 | |
|
|
8b68ac04f7 | |
|
|
35d13e1c32 | |
|
|
4a4c3a3be6 | |
|
|
ef092e1f15 | |
|
|
75dcbe03c6 | |
|
|
8bbc3c359c | |
|
|
59c1bc35cb | |
|
|
e87a9bd9a7 | |
|
|
4b3165dd50 | |
|
|
1d87cefd80 | |
|
|
36eceed720 | |
|
|
992eceaaa0 | |
|
|
e4a3b44e8e | |
|
|
8022b5445b | |
|
|
c16e0352f7 | |
|
|
b423cc3bd6 | |
|
|
965a3e67f0 | |
|
|
4a7878b17f | |
|
|
9580ebabc5 | |
|
|
58df27ce7c | |
|
|
c6f53aec5f | |
|
|
70b17181b4 | |
|
|
6ac8758e7e | |
|
|
27ae62f492 | |
|
|
e20a57b09e | |
|
|
6d4e5f5ad0 | |
|
|
9070c83145 | |
|
|
9182329fa1 | |
|
|
105011a53b | |
|
|
81219c58b2 | |
|
|
1ef6311e5b | |
|
|
25459bd8b9 | |
|
|
90e019e319 | |
|
|
6ff6f8fb3c | |
|
|
1e28e8ccab | |
|
|
2046a23a2f | |
|
|
74efc883c7 | |
|
|
90c26fe671 | |
|
|
3a150f2883 | |
|
|
4eb1c61bd5 | |
|
|
b06f9bdf18 | |
|
|
6f16a5cf5f | |
|
|
b85cad6347 | |
|
|
3c619da259 | |
|
|
b61bc1eee0 | |
|
|
54866d154f | |
|
|
84605d89b7 | |
|
|
7fe32137bd | |
|
|
40c1485828 | |
|
|
fb83719745 | |
|
|
e41b969da2 | |
|
|
89d83a3410 | |
|
|
1f02343268 | |
|
|
db258e6dd9 | |
|
|
3f68ee851b | |
|
|
bfc09777e6 | |
|
|
3f354eb03b | |
|
|
10dc0d48b8 | |
|
|
425d47ad2c | |
|
|
687e5442f2 | |
|
|
f4a10a4808 | |
|
|
4e35ed5955 | |
|
|
cb6209506e | |
|
|
f8a50e7174 | |
|
|
3b26a9e45e | |
|
|
ab316c14d2 | |
|
|
de1dd3b1c5 | |
|
|
fecea911ff | |
|
|
0641b7a725 | |
|
|
7de7d04d7c | |
|
|
fff034d2f8 | |
|
|
49b4f6d813 | |
|
|
50266c8aa8 | |
|
|
73e15f2144 | |
|
|
b864f70e52 | |
|
|
8427bd3a35 | |
|
|
67fac1879c | |
|
|
7fa660fc60 | |
|
|
16b893bd88 | |
|
|
239e3c2849 | |
|
|
6cd784e52c | |
|
|
df1fb14b0c | |
|
|
ca88868902 | |
|
|
5dfe1937a0 | |
|
|
18b832247b | |
|
|
805c302411 | |
|
|
92287d4857 | |
|
|
d2f7fecef5 | |
|
|
0d3923d086 | |
|
|
a966d06524 | |
|
|
cfa66f5335 | |
|
|
4dbae6a473 | |
|
|
627b691578 | |
|
|
6b78731792 | |
|
|
5197b9c8ce | |
|
|
3187275184 | |
|
|
c03c0d5f9d | |
|
|
59b3b6d4e4 | |
|
|
c5a8c3cca5 | |
|
|
ec0a102302 | |
|
|
30a914167f | |
|
|
e0b833ac1a | |
|
|
4abaca273e | |
|
|
10bbda93f7 | |
|
|
a2dafce910 | |
|
|
25b9b796c4 | |
|
|
390f09b89a | |
|
|
23a05fcf35 | |
|
|
e69341cd5f | |
|
|
2dc69a7578 | |
|
|
14d0138d0c | |
|
|
dc570e3d55 | |
|
|
14b0efeced | |
|
|
7e7336cdb8 | |
|
|
d795a4f1d2 | |
|
|
afac9a28b0 | |
|
|
5d4d94a5dd | |
|
|
94a215b4f7 | |
|
|
edd3ad525e | |
|
|
9143178343 | |
|
|
bc83311dd8 | |
|
|
64e7ce2f57 | |
|
|
f213a34427 | |
|
|
70ee009dd9 | |
|
|
3ccbd38cc6 | |
|
|
a89e8fd869 | |
|
|
ed5d122174 | |
|
|
2da90a5ad6 | |
|
|
240f7030b2 | |
|
|
22ef992189 | |
|
|
33fba24158 | |
|
|
89d360aa4a | |
|
|
aba5b279c6 | |
|
|
b4c081c70b | |
|
|
a666712687 | |
|
|
5737d2db35 | |
|
|
76732497b9 | |
|
|
bfd3e150fa | |
|
|
f04532bbac | |
|
|
8bed9bd824 | |
|
|
a490f1c3c4 | |
|
|
9c3d79b041 | |
|
|
1aad357370 | |
|
|
5ffa0b1dd7 | |
|
|
686267ea81 | |
|
|
bfd639f6a0 | |
|
|
f087a94470 | |
|
|
f42800d4d3 | |
|
|
c272bfbdc3 | |
|
|
149e2f343a | |
|
|
4a89ae66ff | |
|
|
1c76cadac7 | |
|
|
fdccbe584d | |
|
|
514c55f53f | |
|
|
3ceeb3b00c | |
|
|
58e0473e29 | |
|
|
ee31950770 | |
|
|
4a9dc33098 | |
|
|
1effec2029 | |
|
|
c15bcca25a | |
|
|
0ba9a0fb16 | |
|
|
d1dc23d9f8 | |
|
|
652bbd2b41 | |
|
|
68e01a03d7 | |
|
|
2bc46e77c8 | |
|
|
1231bd5397 | |
|
|
5a06a79c0c | |
|
|
2a8d369be3 | |
|
|
1bfb95513c | |
|
|
474d0d7b2e | |
|
|
8953007483 | |
|
|
f96fa5ff00 | |
|
|
8ff28a2a86 | |
|
|
336a06d091 | |
|
|
c04d724337 | |
|
|
45bb0413bf | |
|
|
b361569abf | |
|
|
ced2521b03 | |
|
|
a2e1fbcfc6 | |
|
|
2f9e35acb8 | |
|
|
712ce93501 | |
|
|
999255e40c | |
|
|
2774671346 | |
|
|
fc55f16fae | |
|
|
3c2adfb523 | |
|
|
ff2dcef53f | |
|
|
8f7e5e9449 | |
|
|
5494000fd7 | |
|
|
c99855535a | |
|
|
0b3d03e69c | |
|
|
3e45f9729e | |
|
|
413169663d | |
|
|
4506dffa9f | |
|
|
fc71719e6e | |
|
|
c3c577f333 | |
|
|
135812ab02 | |
|
|
847a8941e9 | |
|
|
a02c238874 | |
|
|
4bbffecf98 | |
|
|
42c309347b | |
|
|
b6d656e932 | |
|
|
b6a8feec22 | |
|
|
67e145618b | |
|
|
4f4c820f73 | |
|
|
9cc2e7d95e | |
|
|
0f61ba5299 | |
|
|
9dc408eea7 | |
|
|
5d90bcc792 | |
|
|
fc9adae9a2 | |
|
|
ab1c423692 | |
|
|
b64b75db7a | |
|
|
cfee6bb4af | |
|
|
6b0caedcdd | |
|
|
335cce4895 | |
|
|
7183016910 | |
|
|
1a4a41812c | |
|
|
4c4c5cf15a | |
|
|
e69914b8be | |
|
|
46df888191 | |
|
|
90b906c4fc | |
|
|
d51a5535c7 | |
|
|
564c617721 | |
|
|
a54bca5493 | |
|
|
8449dd4700 | |
|
|
dbc6911f40 | |
|
|
7c714b8acc | |
|
|
a4b6a8c580 | |
|
|
9a0842b76a | |
|
|
cb56f01971 | |
|
|
1f6559a5cf | |
|
|
74070911cd | |
|
|
6d2c445aeb | |
|
|
86448c0001 | |
|
|
f7b19774b7 | |
|
|
6b5cd74d7e | |
|
|
6d715784cd | |
|
|
f09afcf581 | |
|
|
b485173428 | |
|
|
d586af0074 | |
|
|
9b9e334c79 | |
|
|
cc3827c80c | |
|
|
2572b1e3df | |
|
|
9385928bc2 | |
|
|
d6518f1b9a | |
|
|
342b0e5fc1 | |
|
|
8bf42c01ce | |
|
|
d75d513402 | |
|
|
a96cf8cc2b | |
|
|
41b69df2cb | |
|
|
cd49dc7be8 | |
|
|
41b41fefb3 | |
|
|
2033df5958 | |
|
|
37ca545b65 | |
|
|
d58e0447c7 | |
|
|
52243e10fb | |
|
|
cdf549a493 | |
|
|
b55fd6718b | |
|
|
cede13a742 | |
|
|
ecaaea8734 | |
|
|
568a31c83a | |
|
|
162eeea29a | |
|
|
240439bdb0 | |
|
|
903695892a | |
|
|
6a5fea1b27 | |
|
|
0f87fd8ef6 | |
|
|
417e871b06 | |
|
|
23cfeabfe1 | |
|
|
74fef31bf2 | |
|
|
18bcd0b499 | |
|
|
d37b02af03 | |
|
|
ebfe5b2c06 | |
|
|
5b22e64d19 | |
|
|
290fb0556d | |
|
|
66306a8ca3 | |
|
|
cc915b4c76 | |
|
|
b44188110b | |
|
|
7b2ab9b245 | |
|
|
69219e6be0 | |
|
|
12b443e71c | |
|
|
0e7f7c826d | |
|
|
5fd39ff3e1 | |
|
|
dc77140275 | |
|
|
ee0461eb00 | |
|
|
d6ab610622 | |
|
|
2a8024ea4a | |
|
|
f560cba952 | |
|
|
27210627e5 | |
|
|
8d1d5a25e5 | |
|
|
05de1c4ae2 | |
|
|
4f4672d17b | |
|
|
7aaa0621d3 | |
|
|
9746bd3897 | |
|
|
ad7a776d73 | |
|
|
27737c6e2e | |
|
|
ea11453cef | |
|
|
23ce4b8560 | |
|
|
a141bd941c | |
|
|
4a6bd6a2fe | |
|
|
f9d930ba5a | |
|
|
c4cc53a72e | |
|
|
bccfdef05d | |
|
|
e05ed6b850 | |
|
|
18a7c54ebd | |
|
|
0b3f103745 | |
|
|
93c762c7c1 | |
|
|
926814f1e4 | |
|
|
0ea739b7d9 | |
|
|
150860c1c3 | |
|
|
e78690fc47 | |
|
|
c8f715fed8 | |
|
|
06264cdb2e | |
|
|
1111a401f7 | |
|
|
4251cd69ed | |
|
|
49ecb1ac11 | |
|
|
4716f4410f | |
|
|
53939bd3ba | |
|
|
18d94fe9a4 | |
|
|
5c74446e57 | |
|
|
4d725ee84d | |
|
|
c5c104f560 | |
|
|
498cb79abe | |
|
|
43ef4d2901 | |
|
|
de99d67bbd | |
|
|
fea0d18c0a | |
|
|
314d01b35f | |
|
|
47c2257f82 | |
|
|
c23ba3f917 | |
|
|
5048dac854 | |
|
|
9e666c727f | |
|
|
2f1cdc2df9 | |
|
|
85013f9ed3 | |
|
|
167c6c4585 | |
|
|
050483a6b2 | |
|
|
602f3fd1a5 | |
|
|
52533b0d1c | |
|
|
9c51ba1b09 | |
|
|
8d8c05b338 | |
|
|
32f5044eaf | |
|
|
70cc2d67fd | |
|
|
1260fda83a | |
|
|
cdfc586f18 | |
|
|
1e96328ede | |
|
|
3910d569da | |
|
|
ac55935a68 | |
|
|
3603cd52a0 | |
|
|
7f3b11e56b | |
|
|
19a7c8fcf3 | |
|
|
8e044d1045 | |
|
|
a7437c636d | |
|
|
887c32cb54 | |
|
|
72a21fe01d | |
|
|
c2bb7d6a82 | |
|
|
b42bb05b63 | |
|
|
e2166c4684 | |
|
|
5ff7d344c9 | |
|
|
fe329a0e14 | |
|
|
e71da96314 | |
|
|
ab238c3145 | |
|
|
87521df534 | |
|
|
b079e5721c | |
|
|
898a288a99 | |
|
|
13d9fffdb9 | |
|
|
bd7f2d9ba4 | |
|
|
7af5dbae35 | |
|
|
6cd66aed47 | |
|
|
df283fa1c9 | |
|
|
4e54853e35 | |
|
|
d9737acc31 | |
|
|
9288889e20 | |
|
|
95d738edc0 | |
|
|
629bf3dffd | |
|
|
23eb38fe3f | |
|
|
da83c93673 | |
|
|
f3efa51b3e | |
|
|
e2e8245be9 | |
|
|
c747466a7a | |
|
|
91740645a9 | |
|
|
709746b184 | |
|
|
cd60dd4912 | |
|
|
241db706e1 | |
|
|
3592d42d3b | |
|
|
5d3ed5a418 | |
|
|
f06018306d | |
|
|
95ef0cd788 | |
|
|
8a09cc5463 | |
|
|
dea8c275ff | |
|
|
39cb61615f | |
|
|
891b89f60d | |
|
|
4954fc980f | |
|
|
2c3876671b | |
|
|
0a2b6a4f21 | |
|
|
6ee0bfa913 | |
|
|
9dcffc3dbf | |
|
|
99e26d80b0 | |
|
|
9be3cfb3f9 | |
|
|
376f746bc9 | |
|
|
30a03886a5 | |
|
|
ae5325fe53 | |
|
|
c4bec4e8b8 | |
|
|
85eb07d14d | |
|
|
c9f6d7b2d4 | |
|
|
f659cbd159 | |
|
|
6f205b41f5 | |
|
|
4f2f064262 | |
|
|
d5ea7f7016 | |
|
|
4caffa7ebd | |
|
|
6ac8c8cb05 | |
|
|
26dc01102e | |
|
|
94c789e9c8 | |
|
|
39343f5f33 | |
|
|
0d7a875675 | |
|
|
6485a13809 | |
|
|
3bc26ff4d0 | |
|
|
16b1a914f1 | |
|
|
04822c6660 | |
|
|
b8ee0803ab | |
|
|
66bd4716cf | |
|
|
cae54a4c7b | |
|
|
6d4736269b | |
|
|
0284595e9c | |
|
|
793a3513c6 | |
|
|
ae10e9e955 | |
|
|
661fcb24cb | |
|
|
f594014bef | |
|
|
12412d1fa5 | |
|
|
ecb8b20f62 | |
|
|
5216d32d1b | |
|
|
7a5c303ccd | |
|
|
c3ed884bc4 | |
|
|
665b6eeb4a | |
|
|
4ab22cbb97 | |
|
|
d91e1c8607 | |
|
|
31b86ebc2e | |
|
|
8e17fb0266 | |
|
|
a0f87dc2d1 | |
|
|
a9463d1aee | |
|
|
e3f9911e33 | |
|
|
07ec8708e4 | |
|
|
3212dfaf1f | |
|
|
2d7d6ca10b | |
|
|
7e9e88c2ec | |
|
|
9e59f05c25 | |
|
|
35ccaa60d7 | |
|
|
6adc08b0e5 | |
|
|
3671d577a0 | |
|
|
a61455645d | |
|
|
cf4d4ff23d | |
|
|
05d1d56b9d | |
|
|
d3e297fcd4 | |
|
|
228052bfb3 | |
|
|
70a11c6bf0 | |
|
|
b7d013e6bf | |
|
|
750d536bba | |
|
|
126492742b | |
|
|
04113eb95d | |
|
|
5b4603c54f | |
|
|
22916aaab1 | |
|
|
024408004a | |
|
|
6f74c54c02 | |
|
|
857bc02710 | |
|
|
2dddc53ccf | |
|
|
c13a623dbc | |
|
|
ffb76a3486 | |
|
|
a53104379d | |
|
|
1d3f9b7905 | |
|
|
e9442194f2 | |
|
|
687a36af38 | |
|
|
7f1f247c56 | |
|
|
2dd71c3ba2 | |
|
|
b3caec1a93 | |
|
|
5970be33fb | |
|
|
2c52546e2a | |
|
|
5f8489d36d | |
|
|
fd1ac58767 | |
|
|
31f7d0d92d | |
|
|
53d8eb43ff | |
|
|
b51110a50b | |
|
|
fd311c5501 | |
|
|
2386923b8f | |
|
|
fb653c4181 | |
|
|
68e47ebcfe | |
|
|
0ed7c5ad53 | |
|
|
094481739f | |
|
|
13795203a1 | |
|
|
74f7b0cf92 | |
|
|
53509a9b2a | |
|
|
679156d323 | |
|
|
abc7563a35 | |
|
|
c75d80905a | |
|
|
29a270c4b6 | |
|
|
5bb31485b7 | |
|
|
62f19cb3a9 | |
|
|
33a2de9635 | |
|
|
01e89a8f9e | |
|
|
2b4f481850 | |
|
|
77f64de997 | |
|
|
81ea922512 | |
|
|
63068f9b8f | |
|
|
e6e57b33e3 | |
|
|
ac96f318ef | |
|
|
0090aa96b6 | |
|
|
adf8b6b0d8 | |
|
|
c7d88ded94 | |
|
|
1e852cef16 | |
|
|
e2f0c4d9a0 | |
|
|
bb7aa7d208 | |
|
|
e4b32d6aae | |
|
|
e5b3e9fc1f | |
|
|
c6e48f4bea | |
|
|
cc79c6a761 | |
|
|
b055ea05fd | |
|
|
5b94a97fb3 | |
|
|
542b29fa6a | |
|
|
5ea073d45e | |
|
|
9b9e7b5ae3 | |
|
|
ce5321da8c | |
|
|
1319112913 | |
|
|
7a0774c3bb | |
|
|
b890b1b43f | |
|
|
a13b5c4211 | |
|
|
be9c857e72 | |
|
|
b0021e5b10 | |
|
|
1ede98797f | |
|
|
9ad7aed4a5 | |
|
|
12ace45b89 | |
|
|
e3db8fee6f | |
|
|
8ab105ac28 | |
|
|
2e03ee1434 | |
|
|
fba29ea8f1 | |
|
|
43a15113ff | |
|
|
3f1fbfdaee | |
|
|
915912cc76 | |
|
|
c4094e457b | |
|
|
fe613f29b9 | |
|
|
5a46106a46 | |
|
|
a6a07fb39c | |
|
|
98c3f03497 | |
|
|
dfbef2fe24 | |
|
|
9f30f0e7d6 | |
|
|
030e495c8b | |
|
|
a6e33d9916 | |
|
|
d2f7d3cf63 | |
|
|
ff9cd0eed7 | |
|
|
b04948a8cd | |
|
|
6f6fa49d3c | |
|
|
b8ee50d77f | |
|
|
1502e23371 | |
|
|
b2f9ac4fb5 | |
|
|
2bb352a861 | |
|
|
f062a0c8d6 | |
|
|
34f8582725 | |
|
|
1717fa0180 | |
|
|
0640a5904b | |
|
|
8bbde80e02 | |
|
|
2aa0e1d009 | |
|
|
992e64342c | |
|
|
776b4d06a6 | |
|
|
ddfa34d743 | |
|
|
7326bb7d66 | |
|
|
3f01d7a33a | |
|
|
91b226b4d4 | |
|
|
ed53ff2f49 | |
|
|
c768e55983 | |
|
|
2efd0247a1 | |
|
|
d199195785 | |
|
|
8d1c1faf82 | |
|
|
8e73e2a306 | |
|
|
000be270ca | |
|
|
44afd4bbdd | |
|
|
fc11754557 | |
|
|
3bfeaee8ca | |
|
|
6dbe03f0f5 | |
|
|
153ddc0c84 | |
|
|
224549fb88 | |
|
|
414b1b6019 | |
|
|
59653da599 | |
|
|
f5c8368f7a | |
|
|
b88d6588bc | |
|
|
ac427a79b0 | |
|
|
382b28acbe | |
|
|
9c56c93632 | |
|
|
6af1b5b19c | |
|
|
106f289e31 | |
|
|
5a4ad6a6d0 | |
|
|
a68fee1115 | |
|
|
61b1c3c75a | |
|
|
7439d2489e | |
|
|
b70f527c67 | |
|
|
6ba8f3dc19 | |
|
|
43db5c9488 | |
|
|
6007b68e9c | |
|
|
8d504ecb48 | |
|
|
b6c148f84a | |
|
|
1f6a13dac7 | |
|
|
139c38ecfa | |
|
|
8f6c4d40e4 | |
|
|
5a64fe2d91 | |
|
|
8c2ef89732 | |
|
|
74c601db0f | |
|
|
6a6e5f0f54 | |
|
|
188082551a | |
|
|
fc2b7c317f | |
|
|
75008b70e5 | |
|
|
97366933b3 | |
|
|
fdff3dac2b | |
|
|
8ed7ac04d8 | |
|
|
4031310ebb | |
|
|
aaebce7adc | |
|
|
c3ffb48a6b | |
|
|
33e4b1d97f | |
|
|
09ceadfde7 | |
|
|
5b10c7f3c6 | |
|
|
ef3b2b0380 | |
|
|
a3c9716f18 | |
|
|
9367090763 | |
|
|
5803461c24 | |
|
|
29a9e42b64 | |
|
|
8576055dea | |
|
|
673c8d1ae7 | |
|
|
a75e0b2e92 | |
|
|
808ec8c04b | |
|
|
f3c87610f5 | |
|
|
32e96605d4 | |
|
|
7d53d64a47 | |
|
|
2468b391bf | |
|
|
f5ea73eb97 | |
|
|
0e4282d442 | |
|
|
4f53612725 | |
|
|
dcd7742d52 | |
|
|
e87bb65956 | |
|
|
125609105d | |
|
|
98f848e503 | |
|
|
a6fc695522 | |
|
|
317a4d77c7 | |
|
|
5e36503676 | |
|
|
f6eba53d1f | |
|
|
2c12545cf3 | |
|
|
2157f9b3fb | |
|
|
2c0448a81b | |
|
|
57ac113b7f | |
|
|
9ed56ac72c | |
|
|
bd9dbea4ea | |
|
|
0f6ef77775 | |
|
|
979b673f20 | |
|
|
d2b6bd00b1 | |
|
|
6565bf3ebf | |
|
|
12315c0d17 | |
|
|
9315f02c17 | |
|
|
bfd1401b32 | |
|
|
5a9d73369a | |
|
|
d0fa4781c6 | |
|
|
491276983e | |
|
|
90673cb0a2 | |
|
|
f67d4bcfa4 | |
|
|
49e5950791 | |
|
|
0f478a5952 | |
|
|
cc3038f468 | |
|
|
2bde91b6ef | |
|
|
67d10a41e8 | |
|
|
691983be14 | |
|
|
7880f31acb | |
|
|
c3f36afe7f | |
|
|
befadf6d4d | |
|
|
9355fa5037 | |
|
|
28c199fbbd | |
|
|
8da8d681d0 | |
|
|
b43c96b03d | |
|
|
cf511628b0 | |
|
|
d095d2c405 | |
|
|
ed64df737b | |
|
|
d5e1647d11 | |
|
|
fb864e91ee | |
|
|
967b47d984 | |
|
|
305b6c81d7 | |
|
|
60ac3670cb | |
|
|
ddf3c6c8b7 | |
|
|
e0077b188d | |
|
|
763001885f | |
|
|
210b733555 | |
|
|
4c1a18f01d | |
|
|
6aef8ea8ab | |
|
|
8a596f330a | |
|
|
40f9e235de | |
|
|
6a93a94d9f | |
|
|
c305c426eb | |
|
|
8b6925c5b0 | |
|
|
71feb2a2a1 | |
|
|
83c1364eeb | |
|
|
8da113b7f0 | |
|
|
d9956b20f8 | |
|
|
ff3c24fcdc | |
|
|
5ba0e9cae3 | |
|
|
8e2038c419 | |
|
|
21e6833010 | |
|
|
8f00c1824f | |
|
|
0e6973037d | |
|
|
b332279baf | |
|
|
77005b69a2 | |
|
|
b08e044994 | |
|
|
5ae48ee25f | |
|
|
51b210c93c | |
|
|
78cbc21b94 | |
|
|
b8497217bc | |
|
|
cc25ccfcd7 | |
|
|
b3b71df07c | |
|
|
72690062a1 | |
|
|
f193dd0a28 | |
|
|
2b12b74121 | |
|
|
37347aacb2 | |
|
|
991e704899 | |
|
|
cc3d569ade | |
|
|
c7b839ef5a | |
|
|
41a098172d | |
|
|
8da919587d | |
|
|
f1fc704c84 | |
|
|
35321cd292 | |
|
|
9a09758f56 | |
|
|
4d237bdd92 | |
|
|
9f77465170 | |
|
|
c0e29ef57c | |
|
|
fcb8695261 | |
|
|
0ab967b036 | |
|
|
5c630a366d | |
|
|
042ec1cf60 | |
|
|
2e1a2cfacb | |
|
|
11b0e7ad92 | |
|
|
1567526954 | |
|
|
1ccbd21ed8 | |
|
|
6e5a516051 | |
|
|
eae00c19a8 | |
|
|
8a78f2f7c5 | |
|
|
ab4381fba4 | |
|
|
ea90f54783 | |
|
|
8101c87fab | |
|
|
a6d696ba2b | |
|
|
582969b236 | |
|
|
55af32024d | |
|
|
96549e5514 | |
|
|
d523c88c3c | |
|
|
99d7ab9c42 | |
|
|
17ca71e1ab | |
|
|
aa9991d3ee | |
|
|
4bc4e4eb41 | |
|
|
721b504479 | |
|
|
09f9e0e8d1 | |
|
|
31f355c599 | |
|
|
0e61f57458 | |
|
|
9ee51c8f27 | |
|
|
d5b38af4a7 | |
|
|
650c18a2a2 | |
|
|
580b57c772 | |
|
|
13030e43d4 | |
|
|
48cdb499f2 | |
|
|
46cb05c471 | |
|
|
ddd6a16ee0 | |
|
|
914e14946d | |
|
|
856d455065 | |
|
|
772d821fb0 | |
|
|
64a933d77b | |
|
|
45d654e2d7 | |
|
|
49feaa1146 | |
|
|
d861a26e49 | |
|
|
e289e4c893 | |
|
|
cf8be2bae7 | |
|
|
2ded4bd893 | |
|
|
07c9d575fd | |
|
|
b201bf2cf3 | |
|
|
4d61ce63d3 | |
|
|
bd514df0df | |
|
|
18a7d4c262 | |
|
|
5b317ee03c | |
|
|
c69be9d767 | |
|
|
24f4902156 | |
|
|
9d3d8bf502 | |
|
|
52dc8c5eff | |
|
|
2833a44503 | |
|
|
f003eca615 | |
|
|
4da0c552dd | |
|
|
c1ec625f47 | |
|
|
9814f9dc4f | |
|
|
54b278d574 | |
|
|
5594b817cd | |
|
|
e08e9119ee | |
|
|
8703e3b4dd | |
|
|
99e873efc9 | |
|
|
d932ce7f47 | |
|
|
882001cb01 | |
|
|
7f3ea41103 | |
|
|
77f846e992 | |
|
|
2e9db8b850 | |
|
|
1cceaa2a80 | |
|
|
cf9ab4c899 | |
|
|
1af4f243af | |
|
|
6acb79afa2 | |
|
|
23e1b0656c | |
|
|
16a420afee | |
|
|
d274ff8627 | |
|
|
0e31e389f2 | |
|
|
685515865c | |
|
|
518610bbc4 | |
|
|
46fbed6e6f | |
|
|
638e904f91 | |
|
|
2ca28d964b | |
|
|
a871415abf | |
|
|
fc951a28d3 | |
|
|
7219ac94b3 | |
|
|
52b1245547 | |
|
|
2843ea3008 | |
|
|
e2dffbf991 | |
|
|
9c9f4f347e | |
|
|
6778151207 | |
|
|
436a247d60 | |
|
|
58c7dc7cc2 | |
|
|
5bafeb77dc | |
|
|
07a690570e | |
|
|
dd65dd610d | |
|
|
36f0e0392f | |
|
|
b2e527c67e | |
|
|
6842003e76 | |
|
|
e2e7922756 | |
|
|
9ec361beab | |
|
|
9871e9b17e | |
|
|
b2270ae1c8 | |
|
|
cebb80250c | |
|
|
38ee4fc730 | |
|
|
62e666c2ed | |
|
|
fb8a1ad3bc | |
|
|
0f8e1e3bf7 | |
|
|
5f84b8b339 | |
|
|
e223087578 | |
|
|
ade6379345 | |
|
|
ddcd93024f | |
|
|
5d5a7ab443 | |
|
|
473edd19ed | |
|
|
403740428c | |
|
|
ded7c9cb03 | |
|
|
9909049d2a | |
|
|
7e75200b2a | |
|
|
d603b7bb58 | |
|
|
6fe35fa46c | |
|
|
34fa8a4ff7 | |
|
|
9525f79d61 | |
|
|
214d09a8c6 | |
|
|
e4044e1b4a | |
|
|
c43246bba5 | |
|
|
c1e40e113c | |
|
|
7cb3a0f830 | |
|
|
752d24c0a8 | |
|
|
b23dc345ae | |
|
|
948001f39f | |
|
|
8f0ecce53f | |
|
|
4c8b537d71 | |
|
|
7f9de6e48f | |
|
|
10fd97821e | |
|
|
cae020a581 | |
|
|
5d3599a78c | |
|
|
d4e0437cfd | |
|
|
a8e8746fc0 | |
|
|
ba31a02578 | |
|
|
38a1e66145 | |
|
|
510f9ef63d | |
|
|
e8cbc92462 | |
|
|
faa1e8fac4 | |
|
|
0d954f2f4c | |
|
|
d550757b4e | |
|
|
53614a37a1 | |
|
|
33a49452d9 | |
|
|
f098352ae6 | |
|
|
615e338acd | |
|
|
542723d121 | |
|
|
bf70581efa | |
|
|
44ab884b06 | |
|
|
e33ca17388 | |
|
|
4d1b688717 | |
|
|
bfc957ee2d | |
|
|
b3112bf025 | |
|
|
d5c1cd8fc0 | |
|
|
302643330c | |
|
|
8ea51e1479 | |
|
|
25ba41f424 | |
|
|
6eb9e823e0 | |
|
|
b5625f9189 | |
|
|
e83d721cb0 | |
|
|
58e831486d | |
|
|
2eff366e8c | |
|
|
2cc0770305 | |
|
|
1edc32dcd0 | |
|
|
920f4793fb | |
|
|
229123eb87 | |
|
|
033a2d5a67 | |
|
|
f56e121ddb | |
|
|
650392d4ec | |
|
|
07de7509bf | |
|
|
224ed524fa | |
|
|
94dd248dfb | |
|
|
8a54e51300 | |
|
|
d4228efae8 | |
|
|
075237f73b | |
|
|
48ff9d4950 | |
|
|
ae1235210d | |
|
|
c6491629d8 | |
|
|
24a6412ea8 | |
|
|
21c68e0022 | |
|
|
420a083d9b | |
|
|
834125a076 | |
|
|
dc48ceadd9 | |
|
|
9a3c7f70ad | |
|
|
c26aa3186d | |
|
|
c1c6ec1266 | |
|
|
5a798b64ef | |
|
|
c281bac461 | |
|
|
85d2702ef6 | |
|
|
411fc149df | |
|
|
a5b6c3cc19 | |
|
|
9a5465bc83 | |
|
|
6846168db3 | |
|
|
5acb77cab1 | |
|
|
cee3d0b598 | |
|
|
9f07e21e35 | |
|
|
7bc88d5c40 | |
|
|
793594bd59 | |
|
|
7bed6ec658 | |
|
|
0c4105d72c | |
|
|
bbf1e4bca2 | |
|
|
e4e32d7966 | |
|
|
c2c9506f4f | |
|
|
9e81db4373 | |
|
|
b3ead7e47d | |
|
|
9aa2dde7ef | |
|
|
b8012086a3 | |
|
|
cfa9c8bfc8 | |
|
|
58d4e2c38e | |
|
|
725a1c3a4b | |
|
|
b870693393 | |
|
|
261a0ae9e1 | |
|
|
677bf21947 | |
|
|
84adc82fad | |
|
|
f47540b950 | |
|
|
c497b3b24c | |
|
|
65d7d70507 | |
|
|
ba99c05902 | |
|
|
4bfdc62f65 | |
|
|
b08195a9cf | |
|
|
a75b999f13 | |
|
|
abc78f0424 | |
|
|
b91dbc7324 | |
|
|
40bbb84766 | |
|
|
10b49f3a91 | |
|
|
5e0bc3fd9f | |
|
|
1929956fd7 | |
|
|
f2263642a4 | |
|
|
a915143768 | |
|
|
c48bc56f4a | |
|
|
1dd5b150e5 | |
|
|
bc3fc21248 | |
|
|
04135ba3e4 | |
|
|
ead0f922e1 | |
|
|
8c76f93fce | |
|
|
1ee4fc9d27 | |
|
|
50bfb5c5c9 | |
|
|
d93039a194 | |
|
|
ae281720cf | |
|
|
578d658871 | |
|
|
8c2984dc5f | |
|
|
c4c389fdd7 | |
|
|
325b27f43a | |
|
|
df8444c5e7 | |
|
|
e95ed7bbab | |
|
|
8895757364 | |
|
|
9577a028c8 | |
|
|
b3f3f42577 | |
|
|
b0e2d75dbe | |
|
|
54bde15329 | |
|
|
5133b4bdea | |
|
|
d28f97e9da | |
|
|
0fe79ce01b | |
|
|
e84bc3c6c5 | |
|
|
20639906e3 | |
|
|
32641bbf93 | |
|
|
2319d82efb | |
|
|
5f76729cbb | |
|
|
529886f7fb | |
|
|
7302bf9a66 | |
|
|
e4c5900acd | |
|
|
a5cc905184 | |
|
|
7d10a72490 | |
|
|
dcf72ff8e2 | |
|
|
108a4ed496 | |
|
|
3c54d8aef7 | |
|
|
a1d68fe3bc | |
|
|
8a9d724873 | |
|
|
51560b0bf6 | |
|
|
9faa61dfc6 | |
|
|
d8b27d41c0 | |
|
|
8ec9de00ec | |
|
|
af51097af7 | |
|
|
a55dc80175 | |
|
|
c1111f125c | |
|
|
1fdfba2a1a | |
|
|
10b8fdddb4 | |
|
|
7b4c9c5dcd | |
|
|
fd5918c811 |
|
|
@ -6,6 +6,8 @@ body:
|
|||
attributes:
|
||||
value: >
|
||||
|
||||
Learn more in our [Reporting bugs](https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/contributing.html#reporting-bugs) docs section. We fix well-reported bugs the fastest.
|
||||
|
||||
If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/).
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ runs:
|
|||
if: runner.os == 'Linux' && inputs.get-build-deps == 'true'
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
|
||||
with:
|
||||
packages: bison clang flex libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev
|
||||
packages: bison clang flex libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev libgtest-dev libgmock-dev
|
||||
version: ${{ inputs.runs-on }}-buildys
|
||||
|
||||
- name: Linux docs dependencies
|
||||
|
|
@ -52,15 +52,6 @@ runs:
|
|||
packages: graphviz xdot
|
||||
version: ${{ inputs.runs-on }}-docsys
|
||||
|
||||
# if updating test dependencies, make sure to update
|
||||
# docs/source/yosys_internals/extending_yosys/test_suites.rst to match.
|
||||
- name: Linux test dependencies
|
||||
if: runner.os == 'Linux' && inputs.get-test-deps == 'true'
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
|
||||
with:
|
||||
packages: libgtest-dev
|
||||
version: ${{ inputs.runs-on }}-testys
|
||||
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
get-build-deps: true
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: cpp
|
||||
queries: security-extended,security-and-quality
|
||||
|
|
@ -32,4 +32,4 @@ jobs:
|
|||
run: make yosys -j6
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
name: Test extra build flows
|
||||
|
||||
on:
|
||||
# always test main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# test PRs
|
||||
pull_request:
|
||||
# allow triggering tests, ignores skip check
|
||||
merge_group:
|
||||
#push:
|
||||
# branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre_job:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
if: ${{ github.event_name != 'merge_group' }}
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
# don't run on documentation changes
|
||||
|
|
@ -25,20 +23,28 @@ jobs:
|
|||
# but never cancel main
|
||||
cancel_others: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
vs-prep:
|
||||
name: Prepare Visual Studio build
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pre_job]
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
- run: sudo apt-get install libfl-dev
|
||||
- name: Build
|
||||
run: make vcxsrc YOSYS_VER=latest
|
||||
- uses: actions/upload-artifact@v4
|
||||
run: make vcxsrc YOSYS_COMPILER="Visual Studio" VCX_DIR_NAME=yosys-win32-vcxsrc-latest
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: vcxsrc
|
||||
path: yosys-win32-vcxsrc-latest.zip
|
||||
|
|
@ -47,9 +53,9 @@ jobs:
|
|||
name: Visual Studio build
|
||||
runs-on: windows-latest
|
||||
needs: [vs-prep, pre_job]
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: vcxsrc
|
||||
path: .
|
||||
|
|
@ -64,17 +70,17 @@ jobs:
|
|||
wasi-build:
|
||||
name: WASI build
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
- name: Build
|
||||
run: |
|
||||
WASI_SDK=wasi-sdk-27.0-x86_64-linux
|
||||
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz
|
||||
WASI_SDK=wasi-sdk-33.0-x86_64-linux
|
||||
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-33/wasi-sdk-33.0-x86_64-linux.tar.gz
|
||||
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
|
||||
|
||||
FLEX_VER=2.6.4
|
||||
|
|
@ -102,6 +108,7 @@ jobs:
|
|||
ENABLE_ZLIB := 0
|
||||
|
||||
CXXFLAGS += -I$(pwd)/flex-prefix/include
|
||||
LINKFLAGS += -Wl,-z,stack-size=8388608 -Wl,--stack-first -Wl,--strip-all
|
||||
END
|
||||
|
||||
make -C build -f ../Makefile CXX=clang -j$(nproc)
|
||||
|
|
@ -109,14 +116,14 @@ jobs:
|
|||
nix-build:
|
||||
name: "Build nix flake"
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true'
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
|
|
@ -124,3 +131,21 @@ jobs:
|
|||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.30.0/install
|
||||
- run: nix build .?submodules=1 -L
|
||||
|
||||
extra-builds-result:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- vs-build
|
||||
- wasi-build
|
||||
- nix-build
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
run: |
|
||||
echo "Needs results: ${{ join(needs.*.result, ',') }}"
|
||||
if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \
|
||||
[[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then
|
||||
echo "Some jobs failed or were cancelled"
|
||||
exit 1
|
||||
fi
|
||||
- run: echo "All good"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
name: Build docs artifact with Verific
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
merge_group:
|
||||
push:
|
||||
branches: [ main, "docs-preview/**", "docs-preview*" ]
|
||||
tags: [ "*" ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check_docs_rebuild:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
skip_check: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
docs_export: ${{ steps.docs_var.outputs.docs_export }}
|
||||
env:
|
||||
docs_export: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/docs-preview') || startsWith(github.ref, 'refs/tags/') }}
|
||||
|
|
@ -17,16 +23,26 @@ jobs:
|
|||
paths_ignore: '["**/README.md"]'
|
||||
# don't cancel in case we're updating docs
|
||||
cancel_others: 'false'
|
||||
# only run on push *or* pull_request, not both
|
||||
concurrent_skipping: ${{ env.docs_export && 'never' || 'same_content_newer'}}
|
||||
# push filtering means we only want to skip duplicates for PRs
|
||||
do_not_skip: '["workflow_dispatch", "merge_group", "push"]'
|
||||
concurrent_skipping: 'same_content_newer'
|
||||
|
||||
- id: docs_var
|
||||
run: echo "docs_export=${docs_export}" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
prepare-docs:
|
||||
# docs builds are needed for anything on main, any tagged versions, and any tag
|
||||
# or branch starting with docs-preview
|
||||
needs: check_docs_rebuild
|
||||
if: ${{ needs.check_docs_rebuild.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
|
||||
if: ${{ needs.check_docs_rebuild.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }}
|
||||
runs-on: [self-hosted, linux, x64, fast]
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
|
|
@ -75,7 +91,7 @@ jobs:
|
|||
make -C docs html -j$procs TARGETS= EXTRA_TARGETS=
|
||||
|
||||
- name: Trigger RTDs build
|
||||
if: ${{ needs.check_docs_rebuild.outputs.docs_export == 'true' }}
|
||||
if: ${{ needs.check_docs_rebuild.outputs.docs_export == 'true' && github.repository == 'YosysHQ/yosys' }}
|
||||
uses: dfm/rtds-action@v1.1.0
|
||||
with:
|
||||
webhook_url: ${{ secrets.RTDS_WEBHOOK_URL }}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
name: Create source archive with vendored dependencies
|
||||
|
||||
on: [push, workflow_dispatch]
|
||||
on:
|
||||
pull_request:
|
||||
merge_group:
|
||||
push:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
vendor-sources:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository with submodules
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
persist-credentials: false
|
||||
|
|
@ -27,7 +32,7 @@ jobs:
|
|||
gzip yosys-src-vendored.tar
|
||||
|
||||
- name: Store tarball artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: vendored-sources
|
||||
path: yosys-src-vendored.tar.gz
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
name: Build and run tests
|
||||
|
||||
on:
|
||||
# always test main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# test PRs
|
||||
pull_request:
|
||||
# allow triggering tests, ignores skip check
|
||||
merge_group:
|
||||
#push:
|
||||
# branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre_job:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
if: ${{ github.event_name != 'merge_group' }}
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
# don't run on documentation changes
|
||||
|
|
@ -25,12 +23,21 @@ jobs:
|
|||
# but never cancel main
|
||||
cancel_others: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
pre_docs_job:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
if: ${{ github.event_name != 'merge_group' }}
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
# don't run on readme changes
|
||||
|
|
@ -39,6 +46,14 @@ jobs:
|
|||
# but never cancel main
|
||||
cancel_others: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
build-yosys:
|
||||
name: Reusable build
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
@ -53,7 +68,7 @@ jobs:
|
|||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
|
|
@ -71,6 +86,7 @@ jobs:
|
|||
cd build
|
||||
make -f ../Makefile config-$CC
|
||||
make -f ../Makefile -j$procs
|
||||
make -f ../Makefile unit-test -j$procs
|
||||
|
||||
- name: Log yosys-config output
|
||||
run: |
|
||||
|
|
@ -80,10 +96,10 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
tar -cvf ../build.tar share/ yosys yosys-*
|
||||
tar -cvf ../build.tar share/ yosys yosys-* libyosys.so
|
||||
|
||||
- name: Store build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: build-${{ matrix.os }}
|
||||
path: build.tar
|
||||
|
|
@ -102,7 +118,7 @@ jobs:
|
|||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
@ -114,7 +130,7 @@ jobs:
|
|||
get-iverilog: true
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: build-${{ matrix.os }}
|
||||
|
||||
|
|
@ -130,7 +146,7 @@ jobs:
|
|||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC
|
||||
make -j$procs vanilla-test TARGETS= EXTRA_TARGETS= CONFIG=$CC
|
||||
|
||||
- name: Report errors
|
||||
if: ${{ failure() }}
|
||||
|
|
@ -150,7 +166,7 @@ jobs:
|
|||
os: [ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
@ -160,7 +176,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: build-${{ matrix.os }}
|
||||
|
||||
|
|
@ -190,7 +206,7 @@ jobs:
|
|||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
@ -202,7 +218,7 @@ jobs:
|
|||
get-docs-deps: true
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: build-${{ matrix.os }}
|
||||
|
||||
|
|
@ -224,7 +240,7 @@ jobs:
|
|||
name: Try build docs
|
||||
runs-on: [self-hosted, linux, x64, fast]
|
||||
needs: [pre_docs_job]
|
||||
if: ${{ needs.pre_docs_job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
|
||||
if: ${{ needs.pre_docs_job.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }}
|
||||
strategy:
|
||||
matrix:
|
||||
docs-target: [html, latexpdf]
|
||||
|
|
@ -263,3 +279,22 @@ jobs:
|
|||
name: docs-build-${{ matrix.docs-target }}
|
||||
path: docs/build/
|
||||
retention-days: 7
|
||||
|
||||
test-build-result:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- test-yosys
|
||||
- test-cells
|
||||
- test-docs
|
||||
- test-docs-build
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
run: |
|
||||
echo "Needs results: ${{ join(needs.*.result, ',') }}"
|
||||
if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \
|
||||
[[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then
|
||||
echo "Some jobs failed or were cancelled"
|
||||
exit 1
|
||||
fi
|
||||
- run: echo "All good"
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
name: Compiler testing
|
||||
|
||||
on:
|
||||
# always test main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# test PRs
|
||||
pull_request:
|
||||
# allow triggering tests, ignores skip check
|
||||
merge_group:
|
||||
#push:
|
||||
# branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre_job:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
if: ${{ github.event_name != 'merge_group' }}
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
# don't run on documentation changes
|
||||
|
|
@ -25,10 +23,18 @@ jobs:
|
|||
# but never cancel main
|
||||
cancel_others: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
test-compile:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true'
|
||||
env:
|
||||
CXXFLAGS: ${{ startsWith(matrix.compiler, 'gcc') && '-Wp,-D_GLIBCXX_ASSERTIONS' || ''}}
|
||||
CC_SHORT: ${{ startsWith(matrix.compiler, 'gcc') && 'gcc' || 'clang' }}
|
||||
|
|
@ -38,22 +44,22 @@ jobs:
|
|||
- ubuntu-latest
|
||||
compiler:
|
||||
# oldest supported
|
||||
- 'clang-10'
|
||||
- 'gcc-10'
|
||||
- 'clang-14'
|
||||
- 'gcc-11'
|
||||
# newest, make sure to update maximum standard step to match
|
||||
- 'clang-19'
|
||||
- 'gcc-14'
|
||||
- 'clang-22'
|
||||
- 'gcc-15'
|
||||
include:
|
||||
# macOS x86
|
||||
- os: macos-15-intel
|
||||
compiler: 'clang-19'
|
||||
compiler: 'clang-22'
|
||||
# macOS arm
|
||||
- os: macos-latest
|
||||
compiler: 'clang-19'
|
||||
compiler: 'clang-22'
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
|
|
@ -68,6 +74,7 @@ jobs:
|
|||
uses: aminya/setup-cpp@v1
|
||||
with:
|
||||
compiler: ${{ matrix.compiler }}
|
||||
gcc: ${{ (matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang-14') && '12' || '' }}
|
||||
|
||||
- name: Tool versions
|
||||
shell: bash
|
||||
|
|
@ -75,17 +82,38 @@ jobs:
|
|||
$CC --version
|
||||
$CXX --version
|
||||
|
||||
# minimum standard
|
||||
- name: Build C++17
|
||||
shell: bash
|
||||
- name: Fix clang-14 toolchain
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang-14'
|
||||
run: |
|
||||
make config-$CC_SHORT
|
||||
make -j$procs CXXSTD=c++17 compile-only
|
||||
echo 'CXXFLAGS=--gcc-toolchain=/usr -isystem /usr/include/c++/12 -isystem /usr/include/x86_64-linux-gnu/c++/12' >> $GITHUB_ENV
|
||||
|
||||
# maximum standard, only on newest compilers
|
||||
# minimum standard
|
||||
- name: Build C++20
|
||||
if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-14' }}
|
||||
shell: bash
|
||||
run: |
|
||||
make config-$CC_SHORT
|
||||
make -j$procs CXXSTD=c++20 compile-only
|
||||
|
||||
# maximum standard, only on newest compilers
|
||||
- name: Build C++26
|
||||
if: ${{ matrix.compiler == 'clang-22' || matrix.compiler == 'gcc-15' }}
|
||||
shell: bash
|
||||
run: |
|
||||
make config-$CC_SHORT
|
||||
make -j$procs CXXSTD=c++26 compile-only
|
||||
|
||||
test-compile-result:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- test-compile
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
run: |
|
||||
echo "Needs results: ${{ join(needs.*.result, ',') }}"
|
||||
if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \
|
||||
[[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then
|
||||
echo "Some jobs failed or were cancelled"
|
||||
exit 1
|
||||
fi
|
||||
- run: echo "All good"
|
||||
|
|
|
|||
|
|
@ -1,31 +1,41 @@
|
|||
name: Check clang sanitizers
|
||||
|
||||
on:
|
||||
# always test main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# ignore PRs due to time needed
|
||||
# allow triggering tests, ignores skip check
|
||||
pull_request:
|
||||
merge_group:
|
||||
#push:
|
||||
# branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre_job:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
if: ${{ github.event_name != 'merge_group' }}
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
# don't run on documentation changes
|
||||
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
|
||||
# cancel previous builds if a new commit is pushed
|
||||
# but never cancel main
|
||||
cancel_others: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
run_san:
|
||||
name: Build and run tests
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true'
|
||||
env:
|
||||
CC: clang
|
||||
ASAN_OPTIONS: halt_on_error=1
|
||||
|
|
@ -37,7 +47,7 @@ jobs:
|
|||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
|
|
@ -64,7 +74,7 @@ jobs:
|
|||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
make -j$procs test TARGETS= EXTRA_TARGETS=
|
||||
make -j$procs vanilla-test TARGETS= EXTRA_TARGETS=
|
||||
|
||||
- name: Report errors
|
||||
if: ${{ failure() }}
|
||||
|
|
@ -72,7 +82,18 @@ jobs:
|
|||
run: |
|
||||
find tests/**/*.err -print -exec cat {} \;
|
||||
|
||||
- name: Run unit tests
|
||||
shell: bash
|
||||
test-sanitizers-result:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- run_san
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
run: |
|
||||
make -j$procs unit-test ENABLE_LIBYOSYS=1
|
||||
echo "Needs results: ${{ join(needs.*.result, ',') }}"
|
||||
if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \
|
||||
[[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then
|
||||
echo "Some jobs failed or were cancelled"
|
||||
exit 1
|
||||
fi
|
||||
- run: echo "All good"
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
name: Build various Verific configurations
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test-verific-cfg:
|
||||
if: github.repository_owner == 'YosysHQ'
|
||||
runs-on: [self-hosted, linux, x64, fast]
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: true
|
||||
- name: Runtime environment
|
||||
run: |
|
||||
echo "procs=$(nproc)" >> $GITHUB_ENV
|
||||
|
||||
- name: verific [SV]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: verific [VHDL]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: verific [SV + VHDL]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: verific [SV + HIER]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: verific [VHDL + HIER]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: verific [SV + VHDL + HIER]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 0" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: verific [SV + VHDL + HIER + EDIF + LIBERTY]
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_SYSTEMVERILOG := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_VHDL := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_HIER_TREE := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
|
@ -1,22 +1,20 @@
|
|||
name: Build and run tests with Verific (Linux)
|
||||
|
||||
on:
|
||||
# always test main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# test PRs
|
||||
pull_request:
|
||||
# allow triggering tests, ignores skip check
|
||||
merge_group:
|
||||
#push:
|
||||
# branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre-job:
|
||||
pre_job:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
should_skip: ${{ steps.set_output.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
if: ${{ github.event_name != 'merge_group' }}
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
# don't run on documentation changes
|
||||
|
|
@ -25,9 +23,17 @@ jobs:
|
|||
# but never cancel main
|
||||
cancel_others: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- id: set_output
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
||||
echo "should_skip=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
test-verific:
|
||||
needs: pre-job
|
||||
if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
|
||||
needs: pre_job
|
||||
if: ${{ needs.pre_job.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }}
|
||||
runs-on: [self-hosted, linux, x64, fast]
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
|
|
@ -38,10 +44,18 @@ jobs:
|
|||
- name: Runtime environment
|
||||
run: |
|
||||
echo "procs=$(nproc)" >> $GITHUB_ENV
|
||||
mkdir -p "${GITHUB_WORKSPACE}/coverage"
|
||||
echo "LLVM_PROFILE_FILE=${GITHUB_WORKSPACE}/coverage/coverage_%p.profraw" >> $GITHUB_ENV
|
||||
echo "LLVM_PROFILE_FILE_BUFFER_SIZE=0" >> $GITHUB_ENV
|
||||
|
||||
- name: Skip generating files
|
||||
if: ${{ github.event_name != 'merge_group' && github.event_name != 'workflow_dispatch' }}
|
||||
run: |
|
||||
echo "LLVM_PROFILE_FILE=/dev/null" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Yosys
|
||||
run: |
|
||||
make config-clang
|
||||
make config-gcov
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
|
||||
|
|
@ -67,19 +81,95 @@ jobs:
|
|||
|
||||
- name: Run Yosys tests
|
||||
run: |
|
||||
make -j$procs test
|
||||
make -j$procs vanilla-test
|
||||
|
||||
- name: Run Verific specific Yosys tests
|
||||
run: |
|
||||
make -C tests/sva
|
||||
cd tests/svtypes && bash run-test.sh
|
||||
make -C tests/svtypes
|
||||
|
||||
- name: Run SBY tests
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }}
|
||||
run: |
|
||||
make -C sby run_ci
|
||||
|
||||
- name: Run unit tests
|
||||
shell: bash
|
||||
- name: Run coverage
|
||||
if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }}
|
||||
run: |
|
||||
make -j$procs unit-test ENABLE_LTO=1 ENABLE_LIBYOSYS=1
|
||||
make coverage
|
||||
make clean_coverage
|
||||
|
||||
- name: Push coverage
|
||||
if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }}
|
||||
run: |
|
||||
git clone https://x-access-token:${{ secrets.REPORTS_TOKEN }}@github.com/YosysHQ/reports.git out
|
||||
rm -rf out/coverage/main
|
||||
mkdir -p out/coverage/main
|
||||
cp -r coverage_html/* out/coverage/main/
|
||||
cd out
|
||||
# find . -name "*.html" -type f -print0 | xargs -0 sed -i -z 's#\(<td class="headerItem">Date:</td>[[:space:]]*<td class="headerValue">\)[^<]*\(</td>\)#\1\2#g'
|
||||
git config user.name "yosyshq-ci"
|
||||
git config user.email "105224853+yosyshq-ci@users.noreply.github.com"
|
||||
git add .
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "Update coverage"
|
||||
git push
|
||||
else
|
||||
echo "No changes to commit"
|
||||
fi
|
||||
|
||||
test-pyosys:
|
||||
needs: pre_job
|
||||
if: ${{ needs.pre_job.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }}
|
||||
runs-on: [self-hosted, linux, x64, fast]
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: true
|
||||
- name: Install UV
|
||||
run: |
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
- name: Runtime environment
|
||||
run: |
|
||||
echo "procs=$(nproc)" >> $GITHUB_ENV
|
||||
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Build pyosys
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
echo "ENABLE_PYOSYS := 1" >> Makefile.conf
|
||||
echo "PYTHON_DESTDIR := /usr/lib/python3/site-packages" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: Install pyosys
|
||||
run: |
|
||||
make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX=
|
||||
|
||||
- name: Run pyosys tests
|
||||
run: |
|
||||
export PYTHONPATH=${GITHUB_WORKSPACE}/.local/usr/lib/python3/site-packages:$PYTHONPATH
|
||||
python3 tests/pyosys/run_tests.py
|
||||
|
||||
test-verific-result:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- test-verific
|
||||
- test-pyosys
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
run: |
|
||||
echo "Needs results: ${{ join(needs.*.result, ',') }}"
|
||||
if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \
|
||||
[[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then
|
||||
echo "Some jobs failed or were cancelled"
|
||||
exit 1
|
||||
fi
|
||||
- run: echo "All good"
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
name: update-flake-lock
|
||||
on:
|
||||
workflow_dispatch: # allows manual triggering
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
|
||||
|
||||
jobs:
|
||||
lockfile:
|
||||
if: github.repository == 'YosysHQ/Yosys'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
- name: Update flake.lock
|
||||
uses: DeterminateSystems/update-flake-lock@main
|
||||
with:
|
||||
token: ${{CI_CREATE_PR_TOKEN}}
|
||||
pr-title: "Update flake.lock" # Title of PR to be created
|
||||
pr-labels: | # Labels to be set on the PR
|
||||
dependencies
|
||||
automated
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
name: Bump version
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
bump-version:
|
||||
if: github.repository == 'YosysHQ/Yosys'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
- name: Take last commit
|
||||
id: log
|
||||
run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT
|
||||
- name: Bump version
|
||||
if: ${{ !contains(steps.log.outputs.message, 'Bump version') }}
|
||||
run: |
|
||||
make bumpversion
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add Makefile
|
||||
git commit -m "Bump version"
|
||||
- name: Push changes # push the output folder to your repo
|
||||
if: ${{ !contains(steps.log.outputs.message, 'Bump version') }}
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -49,7 +49,7 @@ jobs:
|
|||
name: Build Wheels | ${{ matrix.os.name }} | ${{ matrix.os.archs }}
|
||||
runs-on: ${{ matrix.os.runner }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
|
@ -108,13 +108,13 @@ jobs:
|
|||
PATH="$PWD/bison/src:$PATH"
|
||||
CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh
|
||||
CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: python-wheels-${{ matrix.os.runner }}
|
||||
path: ./wheelhouse/*.whl
|
||||
upload_wheels:
|
||||
name: Upload Wheels
|
||||
if: (github.repository == 'YosysHQ/Yosys') && (github.event_name == 'workflow_dispatch')
|
||||
if: (github.repository == 'YosysHQ/yosys') && (github.event_name == 'workflow_dispatch')
|
||||
runs-on: ubuntu-latest
|
||||
# Specifying a GitHub environment is optional, but strongly encouraged
|
||||
environment: pypi
|
||||
|
|
@ -123,7 +123,7 @@ jobs:
|
|||
id-token: write
|
||||
needs: build_wheels
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: "."
|
||||
pattern: python-wheels-*
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -e -x
|
||||
|
||||
# Build-time dependencies
|
||||
|
|
|
|||
|
|
@ -65,10 +65,10 @@
|
|||
/viz.js
|
||||
|
||||
# other
|
||||
/coverage.info
|
||||
/yosys.profdata
|
||||
/coverage
|
||||
/coverage_html
|
||||
|
||||
|
||||
# these really belong in global gitignore since they're not specific to this project but rather to user tool choice
|
||||
# but too many people don't have a global gitignore configured:
|
||||
# https://docs.github.com/en/get-started/git-basics/ignoring-files#configuring-ignored-files-for-all-repositories-on-your-computer
|
||||
|
|
|
|||
2
Brewfile
2
Brewfile
|
|
@ -9,6 +9,6 @@ brew "python3"
|
|||
brew "uv"
|
||||
brew "xdot"
|
||||
brew "bash"
|
||||
brew "llvm@20"
|
||||
brew "llvm"
|
||||
brew "lld"
|
||||
brew "googletest"
|
||||
|
|
|
|||
90
CHANGELOG
90
CHANGELOG
|
|
@ -2,9 +2,97 @@
|
|||
List of major changes and improvements between releases
|
||||
=======================================================
|
||||
|
||||
Yosys 0.59 .. Yosys 0.60-dev
|
||||
Yosys 0.65 .. Yosys 0.66-dev
|
||||
--------------------------
|
||||
|
||||
Yosys 0.64 .. Yosys 0.65
|
||||
--------------------------
|
||||
* New commands and options
|
||||
- Added "arith_tree" pass to convert add/sub/macc chains
|
||||
to carry-save adder trees.
|
||||
- Removed "-force" option from "share" pass.
|
||||
|
||||
* Various
|
||||
- read_verilog: support positional assignment patterns
|
||||
for unpacked arrays.
|
||||
|
||||
Yosys 0.63 .. Yosys 0.64
|
||||
--------------------------
|
||||
* New commands and options
|
||||
- Added "synth_analogdevices" pass to support synthesis
|
||||
for Analog Devices FPGAs.
|
||||
|
||||
* Various
|
||||
- Removed rarely-used options from ABC/ABC9.
|
||||
- Removed "-S" option from "abc" pass.
|
||||
- Removed "-fast" option from "abc9" and "abc9_exe".
|
||||
- Calls to "abc -g AND -fast" to map logic to
|
||||
AND-Inverter Graph form should be replaced with
|
||||
"aigmap".
|
||||
- The above change was made to SBY, so we recommend
|
||||
updating it.
|
||||
- Added hardware latch support for Gowin FPGAs.
|
||||
|
||||
Yosys 0.62 .. Yosys 0.63
|
||||
--------------------------
|
||||
* Various
|
||||
- Added DSP inference for Gowin GW1N and GW2A.
|
||||
- Added support for subtract in preadder for Xilinx arch.
|
||||
- Added infrastructure to run a sat solver as a command.
|
||||
|
||||
* New commands and options
|
||||
- Added "-ignore-unknown-cells" option to "equiv_induct"
|
||||
and "equiv_simple" pass.
|
||||
- Added "-force-params" option to "memory_libmap" pass.
|
||||
- Added "-select-solver" option to "sat" pass.
|
||||
- Added "-default_params" option to "write_verilog" pass.
|
||||
- Added "-nodsp" option to "synth_gowin" pass.
|
||||
|
||||
Yosys 0.61 .. Yosys 0.62
|
||||
--------------------------
|
||||
* Various
|
||||
- verific: Added "-sv2017" flag option to support System
|
||||
Verilog 2017.
|
||||
- verific: Added VHDL related flags to "-f" and "-F" and
|
||||
support reading VHDL file from file lists.
|
||||
- Updated cell libs with proper module declaration where
|
||||
non standard (...) style was used.
|
||||
|
||||
* New commands and options
|
||||
- Added "-word" option to "lut2mux" pass to enable emitting
|
||||
word level cells.
|
||||
- Added experimental "opt_balance_tree" pass to convert
|
||||
cascaded cells into tree of cells to improve timing.
|
||||
- Added "-gatesi" option to "write_blif" pass to init gates
|
||||
under gates_mode in BLIF format.
|
||||
- Added "-on" and "-off" options to "debug" pass for
|
||||
persistent debug logging.
|
||||
- Added "linux_perf" pass to control performance recording.
|
||||
|
||||
Yosys 0.60 .. Yosys 0.61
|
||||
--------------------------
|
||||
* Various
|
||||
- Removed "cover" pass for coverage tracking.
|
||||
- Avoid merging formal properties with "opt_merge" pass.
|
||||
- Parallelize "opt_merge" pass.
|
||||
|
||||
* New commands and options
|
||||
- Added "design_equal" pass to support fuzz-test comparison.
|
||||
- Added "lut2bmux" pass to convert $lut to $bmux.
|
||||
- Added "-legalize" option to "read_rtlil" pass to prevent
|
||||
semantic errors.
|
||||
|
||||
Yosys 0.59 .. Yosys 0.60
|
||||
--------------------------
|
||||
* Various
|
||||
- read_verilog: suport unsized parameters.
|
||||
- Added static library compile option.
|
||||
|
||||
* New commands and options
|
||||
- Added "sdc" pass for reading SDC files.
|
||||
- Added experimental "sdc_expand" and "opensta" for OpenSTA integration.
|
||||
- Added "icell_liberty" pass for used internal cells.
|
||||
|
||||
Yosys 0.58 .. Yosys 0.59
|
||||
--------------------------
|
||||
* Various
|
||||
|
|
|
|||
|
|
@ -1,70 +1,15 @@
|
|||
# Introduction
|
||||
# Contributing to Yosys
|
||||
|
||||
Thanks for thinking about contributing to the Yosys project. If this is your
|
||||
Thanks for considering helping out. If this is your
|
||||
first time contributing to an open source project, please take a look at the
|
||||
following guide:
|
||||
following guide about the basics:
|
||||
https://opensource.guide/how-to-contribute/#orienting-yourself-to-a-new-project.
|
||||
|
||||
Information about the Yosys coding style is available on our Read the Docs:
|
||||
https://yosys.readthedocs.io/en/latest/yosys_internals/extending_yosys/contributing.html.
|
||||
Check out our [Contributing guidelines](https://yosys.readthedocs.io/en/latest/yosys_internals/extending_yosys/contributing.html) to learn the best ways to
|
||||
|
||||
# Using the issue tracker
|
||||
+ get help
|
||||
+ report bugs
|
||||
+ contribute code
|
||||
+ review code
|
||||
|
||||
The [issue tracker](https://github.com/YosysHQ/yosys/issues) is used for
|
||||
tracking bugs or other problems with Yosys or its documentation. It is also the
|
||||
place to go for requesting new features.
|
||||
When [creating a new issue](https://github.com/YosysHQ/yosys/issues/new/choose),
|
||||
we have a few templates available. Please make use of these! It will make it
|
||||
much easier for someone to respond and help.
|
||||
|
||||
### Bug reports
|
||||
|
||||
Before you submit an issue, please check out the [how-to guide for
|
||||
`bugpoint`](https://yosys.readthedocs.io/en/latest/using_yosys/bugpoint.html).
|
||||
This guide will take you through the process of using the [`bugpoint`
|
||||
command](https://yosys.readthedocs.io/en/latest/cmd/bugpoint.html) in Yosys to
|
||||
produce a [minimal, complete and verifiable
|
||||
example](https://stackoverflow.com/help/minimal-reproducible-example) (MVCE).
|
||||
Providing an MVCE with your bug report drastically increases the likelihood that
|
||||
someone will be able to help resolve your issue.
|
||||
|
||||
|
||||
# Using pull requests
|
||||
|
||||
If you are working on something to add to Yosys, or fix something that isn't
|
||||
working quite right, make a [PR](https://github.com/YosysHQ/yosys/pulls)! An
|
||||
open PR, even as a draft, tells everyone that you're working on it and they
|
||||
don't have to. It can also be a useful way to solicit feedback on in-progress
|
||||
changes. See below to find the best way to [ask us
|
||||
questions](#asking-questions).
|
||||
|
||||
In general, all changes to the code are done as a PR, with [Continuous
|
||||
Integration (CI)](https://github.com/YosysHQ/yosys/actions) tools that
|
||||
automatically run the full suite of tests compiling and running Yosys. Please
|
||||
make use of this! If you're adding a feature: add a test! Not only does it
|
||||
verify that your feature is working as expected, but it can also be a handy way
|
||||
for people to see how the feature is used. If you're fixing a bug: add a test!
|
||||
If you can, do this first; it's okay if the test starts off failing - you
|
||||
already know there is a bug. CI also helps to make sure that your changes still
|
||||
work under a range of compilers, settings, and targets.
|
||||
|
||||
|
||||
### Labels
|
||||
|
||||
We use [labels](https://github.com/YosysHQ/yosys/labels) to help categorise
|
||||
issues and PRs. If a label seems relevant to your work, please do add it; this
|
||||
also includes the labels beggining with 'status-'. The 'merge-' labels are used
|
||||
by maintainers for tracking and communicating which PRs are ready and pending
|
||||
merge; please do not use these labels if you are not a maintainer.
|
||||
|
||||
|
||||
# Asking questions
|
||||
|
||||
If you have a question about how to use Yosys, please ask on our [Discourse forum](https://yosyshq.discourse.group/) or in our [discussions
|
||||
page](https://github.com/YosysHQ/yosys/discussions).
|
||||
The Discourse is also a great place to ask questions about developing or
|
||||
contributing to Yosys.
|
||||
|
||||
We have open [dev 'jour fixe' (JF) meetings](https://docs.google.com/document/d/1SapA6QAsJcsgwsdKJDgnGR2mr97pJjV4eeXg_TVJhRU/edit?usp=sharing) where developers from YosysHQ and the
|
||||
community come together to discuss open issues and PRs. This is also a good
|
||||
place to talk to us about how to implement larger PRs.
|
||||
If you're reading this file offline and don't have internet access, you can [read the contributing.rst file locally](docs/source/yosys_internals/extending_yosys/contributing.rst).
|
||||
|
|
|
|||
2
COPYING
2
COPYING
|
|
@ -1,6 +1,6 @@
|
|||
ISC License
|
||||
|
||||
Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
Copyright (C) 2012 - 2026 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
|||
58
Dockerfile
58
Dockerfile
|
|
@ -1,58 +0,0 @@
|
|||
ARG IMAGE="python:3-slim-buster"
|
||||
|
||||
#---
|
||||
|
||||
FROM $IMAGE AS base
|
||||
|
||||
RUN apt-get update -qq \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
|
||||
ca-certificates \
|
||||
clang \
|
||||
lld \
|
||||
curl \
|
||||
libffi-dev \
|
||||
libreadline-dev \
|
||||
tcl-dev \
|
||||
graphviz \
|
||||
xdot \
|
||||
&& apt-get autoclean && apt-get clean && apt-get -y autoremove \
|
||||
&& update-ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists
|
||||
|
||||
#---
|
||||
|
||||
FROM base AS build
|
||||
|
||||
RUN apt-get update -qq \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
|
||||
bison \
|
||||
flex \
|
||||
gawk \
|
||||
gcc \
|
||||
git \
|
||||
iverilog \
|
||||
pkg-config \
|
||||
&& apt-get autoclean && apt-get clean && apt-get -y autoremove \
|
||||
&& rm -rf /var/lib/apt/lists
|
||||
|
||||
COPY . /yosys
|
||||
|
||||
ENV PREFIX /opt/yosys
|
||||
|
||||
RUN cd /yosys \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& make test
|
||||
|
||||
#---
|
||||
|
||||
FROM base
|
||||
|
||||
COPY --from=build /opt/yosys /opt/yosys
|
||||
|
||||
ENV PATH /opt/yosys/bin:$PATH
|
||||
|
||||
RUN useradd -m yosys
|
||||
USER yosys
|
||||
|
||||
CMD ["yosys"]
|
||||
263
Makefile
263
Makefile
|
|
@ -21,8 +21,8 @@ ENABLE_VERIFIC_HIER_TREE := 1
|
|||
ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0
|
||||
ENABLE_VERIFIC_EDIF := 0
|
||||
ENABLE_VERIFIC_LIBERTY := 0
|
||||
ENABLE_COVER := 1
|
||||
ENABLE_LIBYOSYS := 0
|
||||
ENABLE_LIBYOSYS_STATIC := 0
|
||||
ENABLE_ZLIB := 1
|
||||
ENABLE_HELP_SOURCE := 0
|
||||
|
||||
|
|
@ -103,8 +103,8 @@ VPATH := $(YOSYS_SRC)
|
|||
# Unit test
|
||||
UNITESTPATH := $(YOSYS_SRC)/tests/unit
|
||||
|
||||
export CXXSTD ?= c++17
|
||||
CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include
|
||||
export CXXSTD ?= c++20
|
||||
CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -Werror=unused -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include
|
||||
LIBS := $(LIBS) -lstdc++ -lm
|
||||
PLUGIN_LINKFLAGS :=
|
||||
PLUGIN_LIBS :=
|
||||
|
|
@ -161,7 +161,19 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.59+0
|
||||
YOSYS_VER := 0.65
|
||||
|
||||
ifneq (, $(shell command -v git 2>/dev/null))
|
||||
ifneq (, $(shell git rev-parse --git-dir 2>/dev/null))
|
||||
GIT_COMMIT_COUNT := $(or $(shell git rev-list --count v$(YOSYS_VER)..HEAD 2>/dev/null),0)
|
||||
ifneq ($(GIT_COMMIT_COUNT),0)
|
||||
YOSYS_VER := $(YOSYS_VER)+$(GIT_COMMIT_COUNT)
|
||||
endif
|
||||
else
|
||||
YOSYS_VER := $(YOSYS_VER)+post
|
||||
endif
|
||||
endif
|
||||
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
||||
|
|
@ -177,15 +189,14 @@ CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \
|
|||
TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit)
|
||||
ifneq ($(findstring Format:,$(TARBALL_GIT_REV)),)
|
||||
GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN)
|
||||
GIT_DIRTY := $(shell GIT_DIR=$(YOSYS_SRC)/.git git diff --exit-code --quiet 2>/dev/null; if [ $$? -ne 0 ]; then echo "-dirty"; fi)
|
||||
else
|
||||
GIT_REV := $(TARBALL_GIT_REV)
|
||||
GIT_DIRTY := ""
|
||||
endif
|
||||
|
||||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
bumpversion:
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 03eb220.. | wc -l`/;" Makefile
|
||||
|
||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
||||
|
||||
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
|
||||
|
|
@ -248,9 +259,6 @@ ifneq ($(SANITIZER),)
|
|||
$(info [Clang Sanitizer] $(SANITIZER))
|
||||
CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER)
|
||||
LINKFLAGS += -g -fsanitize=$(SANITIZER)
|
||||
ifneq ($(findstring address,$(SANITIZER)),)
|
||||
ENABLE_COVER := 0
|
||||
endif
|
||||
ifneq ($(findstring memory,$(SANITIZER)),)
|
||||
CXXFLAGS += -fPIE -fsanitize-memory-track-origins
|
||||
LINKFLAGS += -fPIE -fsanitize-memory-track-origins
|
||||
|
|
@ -283,18 +291,19 @@ ifeq ($(WASI_SDK),)
|
|||
CXX = clang++
|
||||
AR = llvm-ar
|
||||
RANLIB = llvm-ranlib
|
||||
WASIFLAGS := -target wasm32-wasi $(WASIFLAGS)
|
||||
WASIFLAGS := -target wasm32-wasip1 $(WASIFLAGS)
|
||||
else
|
||||
CXX = $(WASI_SDK)/bin/clang++
|
||||
AR = $(WASI_SDK)/bin/ar
|
||||
RANLIB = $(WASI_SDK)/bin/ranlib
|
||||
endif
|
||||
CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS))
|
||||
CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS)) -fwasm-exceptions -lunwind
|
||||
LIBS := -lwasi-emulated-process-clocks $(filter-out -lrt,$(LIBS))
|
||||
ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)"
|
||||
ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -D_WASI_EMULATED_PROCESS_CLOCKS -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT"
|
||||
ABCMKARGS += OPTFLAGS="-Os"
|
||||
LTOFLAGS =
|
||||
EXE = .wasm
|
||||
|
||||
DISABLE_SPAWN := 1
|
||||
|
|
@ -342,6 +351,9 @@ endif
|
|||
|
||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||
TARGETS += libyosys.so
|
||||
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
|
||||
TARGETS += libyosys.a
|
||||
endif
|
||||
endif
|
||||
|
||||
PY_WRAPPER_FILE = pyosys/wrappers
|
||||
|
|
@ -444,8 +456,11 @@ endif
|
|||
endif
|
||||
|
||||
ifeq ($(ENABLE_GCOV),1)
|
||||
CXXFLAGS += --coverage
|
||||
LINKFLAGS += --coverage
|
||||
LLVM_PROFILE_FILE ?= $(realpath $(YOSYS_SRC))/coverage/coverage_%p.profraw
|
||||
export LLVM_PROFILE_FILE
|
||||
export LLVM_PROFILE_FILE_BUFFER_SIZE=0
|
||||
CXXFLAGS += -fprofile-instr-generate -fcoverage-mapping
|
||||
LINKFLAGS+= -fprofile-instr-generate
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_GPROF),1)
|
||||
|
|
@ -474,6 +489,9 @@ else
|
|||
ifeq ($(ABCEXTERNAL),)
|
||||
TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS)
|
||||
endif
|
||||
ifeq ($(DISABLE_SPAWN),1)
|
||||
$(error ENABLE_ABC=1 requires either LINK_ABC=1 or DISABLE_SPAWN=0)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
@ -541,10 +559,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_COVER),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_COVER
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_CCACHE),1)
|
||||
CXX := ccache $(CXX)
|
||||
else
|
||||
|
|
@ -603,6 +617,7 @@ $(eval $(call add_include_file,kernel/bitpattern.h))
|
|||
$(eval $(call add_include_file,kernel/cellaigs.h))
|
||||
$(eval $(call add_include_file,kernel/celledges.h))
|
||||
$(eval $(call add_include_file,kernel/celltypes.h))
|
||||
$(eval $(call add_include_file,kernel/newcelltypes.h))
|
||||
$(eval $(call add_include_file,kernel/consteval.h))
|
||||
$(eval $(call add_include_file,kernel/constids.inc))
|
||||
$(eval $(call add_include_file,kernel/cost.h))
|
||||
|
|
@ -637,6 +652,7 @@ $(eval $(call add_include_file,kernel/yosys_common.h))
|
|||
$(eval $(call add_include_file,kernel/yw.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezcmdline.h))
|
||||
ifeq ($(ENABLE_ZLIB),1)
|
||||
$(eval $(call add_include_file,libs/fst/fstapi.h))
|
||||
endif
|
||||
|
|
@ -644,8 +660,6 @@ $(eval $(call add_include_file,libs/sha1/sha1.h))
|
|||
$(eval $(call add_include_file,libs/json11/json11.hpp))
|
||||
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
|
||||
$(eval $(call add_include_file,passes/techmap/libparse.h))
|
||||
$(eval $(call add_include_file,frontends/ast/ast.h))
|
||||
$(eval $(call add_include_file,frontends/ast/ast_binding.h))
|
||||
$(eval $(call add_include_file,frontends/blif/blifparse.h))
|
||||
$(eval $(call add_include_file,backends/rtlil/rtlil_backend.h))
|
||||
|
||||
|
|
@ -684,6 +698,7 @@ OBJS += libs/json11/json11.o
|
|||
|
||||
OBJS += libs/ezsat/ezsat.o
|
||||
OBJS += libs/ezsat/ezminisat.o
|
||||
OBJS += libs/ezsat/ezcmdline.o
|
||||
|
||||
OBJS += libs/minisat/Options.o
|
||||
OBJS += libs/minisat/SimpSolver.o
|
||||
|
|
@ -722,7 +737,6 @@ OBJS += passes/hierarchy/hierarchy.o
|
|||
OBJS += passes/cmds/select.o
|
||||
OBJS += passes/cmds/show.o
|
||||
OBJS += passes/cmds/stat.o
|
||||
OBJS += passes/cmds/cover.o
|
||||
OBJS += passes/cmds/design.o
|
||||
OBJS += passes/cmds/plugin.o
|
||||
|
||||
|
|
@ -772,6 +786,9 @@ else
|
|||
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
|
||||
endif
|
||||
|
||||
libyosys.a: $(filter-out kernel/driver.o,$(OBJS))
|
||||
$(P) $(AR) rcs $@ $^
|
||||
|
||||
%.o: %.cc
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
|
||||
|
|
@ -790,12 +807,34 @@ endif
|
|||
$(Q) mkdir -p $(dir $@)
|
||||
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
|
||||
|
||||
YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) $(shell \
|
||||
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))
|
||||
YOSYS_REPO :=
|
||||
ifneq (, $(shell command -v git 2>/dev/null))
|
||||
ifneq (, $(shell git rev-parse --git-dir 2>/dev/null))
|
||||
GIT_REMOTE := $(strip $(shell git config --get remote.origin.url 2>/dev/null | $(AWK) '{print tolower($$0)}'))
|
||||
ifneq ($(strip $(GIT_REMOTE)),)
|
||||
YOSYS_REPO := $(strip $(shell echo $(GIT_REMOTE) | $(AWK) -F '[:/]' '{gsub(/\.git$$/, "", $$NF); printf "%s/%s", $$(NF-1), $$NF}'))
|
||||
endif
|
||||
ifeq ($(strip $(YOSYS_REPO)),yosyshq/yosys)
|
||||
YOSYS_REPO :=
|
||||
endif
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
ifeq ($(filter main HEAD release/v%,$(GIT_BRANCH)),)
|
||||
YOSYS_REPO := $(YOSYS_REPO) at $(GIT_BRANCH)
|
||||
endif
|
||||
YOSYS_REPO := $(strip $(YOSYS_REPO))
|
||||
endif
|
||||
endif
|
||||
|
||||
YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY)
|
||||
YOSYS_COMPILER := $(notdir $(CXX)) $(shell $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS))
|
||||
YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(YOSYS_COMPILER))
|
||||
ifneq ($(strip $(YOSYS_REPO)),)
|
||||
YOSYS_VER_STR := $(YOSYS_VER_STR) [$(YOSYS_REPO)]
|
||||
endif
|
||||
|
||||
kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile
|
||||
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
|
||||
$(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc
|
||||
$(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; const char *yosys_git_hash_str=\"$(YOSYS_GIT_STR)\"; }" > kernel/version_$(GIT_REV).cc
|
||||
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v)))
|
||||
|
|
@ -883,106 +922,15 @@ else
|
|||
ABCOPT=""
|
||||
endif
|
||||
|
||||
# Tests that generate .mk with tests/gen-tests-makefile.sh
|
||||
MK_TEST_DIRS =
|
||||
MK_TEST_DIRS += tests/arch/anlogic
|
||||
MK_TEST_DIRS += tests/arch/ecp5
|
||||
MK_TEST_DIRS += tests/arch/efinix
|
||||
MK_TEST_DIRS += tests/arch/gatemate
|
||||
MK_TEST_DIRS += tests/arch/gowin
|
||||
MK_TEST_DIRS += tests/arch/ice40
|
||||
MK_TEST_DIRS += tests/arch/intel_alm
|
||||
MK_TEST_DIRS += tests/arch/machxo2
|
||||
MK_TEST_DIRS += tests/arch/microchip
|
||||
MK_TEST_DIRS += tests/arch/nanoxplore
|
||||
MK_TEST_DIRS += tests/arch/nexus
|
||||
MK_TEST_DIRS += tests/arch/quicklogic/pp3
|
||||
MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f
|
||||
MK_TEST_DIRS += tests/arch/xilinx
|
||||
MK_TEST_DIRS += tests/bugpoint
|
||||
MK_TEST_DIRS += tests/opt
|
||||
MK_TEST_DIRS += tests/sat
|
||||
MK_TEST_DIRS += tests/sim
|
||||
MK_TEST_DIRS += tests/svtypes
|
||||
MK_TEST_DIRS += tests/techmap
|
||||
MK_TEST_DIRS += tests/various
|
||||
MK_TEST_DIRS += tests/rtlil
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifneq ($(YOSYS_NOVERIFIC),1)
|
||||
MK_TEST_DIRS += tests/verific
|
||||
endif
|
||||
endif
|
||||
MK_TEST_DIRS += tests/verilog
|
||||
test: vanilla-test unit-test
|
||||
|
||||
# Tests that don't generate .mk
|
||||
SH_TEST_DIRS =
|
||||
SH_TEST_DIRS += tests/simple
|
||||
SH_TEST_DIRS += tests/simple_abc9
|
||||
SH_TEST_DIRS += tests/hana
|
||||
SH_TEST_DIRS += tests/asicworld
|
||||
# SH_TEST_DIRS += tests/realmath
|
||||
SH_TEST_DIRS += tests/share
|
||||
SH_TEST_DIRS += tests/opt_share
|
||||
SH_TEST_DIRS += tests/fsm
|
||||
SH_TEST_DIRS += tests/memlib
|
||||
SH_TEST_DIRS += tests/bram
|
||||
SH_TEST_DIRS += tests/svinterfaces
|
||||
SH_TEST_DIRS += tests/xprop
|
||||
SH_TEST_DIRS += tests/select
|
||||
SH_TEST_DIRS += tests/peepopt
|
||||
SH_TEST_DIRS += tests/proc
|
||||
SH_TEST_DIRS += tests/blif
|
||||
SH_TEST_DIRS += tests/arch
|
||||
SH_TEST_DIRS += tests/rpc
|
||||
SH_TEST_DIRS += tests/memfile
|
||||
SH_TEST_DIRS += tests/fmt
|
||||
SH_TEST_DIRS += tests/cxxrtl
|
||||
SH_TEST_DIRS += tests/liberty
|
||||
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
|
||||
SH_TEST_DIRS += tests/functional
|
||||
endif
|
||||
.PHONY: vanilla-test
|
||||
|
||||
# Tests that don't generate .mk and need special args
|
||||
SH_ABC_TEST_DIRS =
|
||||
SH_ABC_TEST_DIRS += tests/memories
|
||||
SH_ABC_TEST_DIRS += tests/aiger
|
||||
SH_ABC_TEST_DIRS += tests/alumacc
|
||||
|
||||
# seed-tests/ is a dummy string, not a directory
|
||||
.PHONY: seed-tests
|
||||
seed-tests: $(SH_TEST_DIRS:%=seed-tests/%)
|
||||
.PHONY: seed-tests/%
|
||||
seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd $* && bash run-test.sh $(SEEDOPT)
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
# abcopt-tests/ is a dummy string, not a directory
|
||||
.PHONY: abcopt-tests
|
||||
abcopt-tests: $(SH_ABC_TEST_DIRS:%=abcopt-tests/%)
|
||||
abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT)
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
# makefile-tests/ is a dummy string, not a directory
|
||||
.PHONY: makefile-tests
|
||||
makefile-tests: $(MK_TEST_DIRS:%=makefile-tests/%)
|
||||
# this target actually emits .mk files
|
||||
%.mk:
|
||||
+cd $(dir $*) && bash run-test.sh
|
||||
# this one spawns submake on each
|
||||
makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(MAKE) -C $* -f run-test.mk
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
test: makefile-tests abcopt-tests seed-tests
|
||||
@echo ""
|
||||
@echo " Passed \"make test\"."
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
@echo " Ran tests without verific support due to YOSYS_NOVERIFIC=1."
|
||||
endif
|
||||
endif
|
||||
@echo ""
|
||||
vanilla-test: $(TARGETS) $(EXTRA_TARGETS)
|
||||
@$(MAKE) -C tests vanilla-test \
|
||||
$(if $(ENABLE_VERIFIC),ENABLE_VERIFIC=$(ENABLE_VERIFIC)) \
|
||||
$(if $(YOSYS_NOVERIFIC),YOSYS_NOVERIFIC=$(YOSYS_NOVERIFIC)) \
|
||||
SEEDOPT=$(SEEDOPT) ABCOPT=$(ABCOPT)
|
||||
|
||||
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
|
||||
|
||||
|
|
@ -1008,11 +956,11 @@ ystests: $(TARGETS) $(EXTRA_TARGETS)
|
|||
|
||||
# Unit test
|
||||
unit-test: libyosys.so
|
||||
@$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" \
|
||||
@$(MAKE) -f $(UNITESTPATH)/Makefile CXX="$(CXX)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" \
|
||||
CXXFLAGS="$(CXXFLAGS)" LINKFLAGS="$(LINKFLAGS)" LIBS="$(LIBS)" ROOTPATH="$(CURDIR)"
|
||||
|
||||
clean-unit-test:
|
||||
@$(MAKE) -C $(UNITESTPATH) clean
|
||||
@$(MAKE) -f $(UNITESTPATH)/Makefile clean
|
||||
|
||||
install-dev: $(PROGRAM_PREFIX)yosys-config share
|
||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
||||
|
|
@ -1022,15 +970,15 @@ install-dev: $(PROGRAM_PREFIX)yosys-config share
|
|||
|
||||
install: $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
|
||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys; fi
|
||||
$(INSTALL_SUDO) cp $(filter-out libyosys.so libyosys.a,$(TARGETS)) $(DESTDIR)$(BINDIR)
|
||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys$(EXE),$(TARGETS)),)
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys$(EXE); fi
|
||||
endif
|
||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),)
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc; fi
|
||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc$(EXE),$(TARGETS)),)
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc$(EXE); fi
|
||||
endif
|
||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),)
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib; fi
|
||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib$(EXE),$(TARGETS)),)
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib$(EXE); fi
|
||||
endif
|
||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
|
||||
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
|
||||
|
|
@ -1038,13 +986,18 @@ ifeq ($(ENABLE_LIBYOSYS),1)
|
|||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
|
||||
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi
|
||||
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
|
||||
$(INSTALL_SUDO) cp libyosys.a $(DESTDIR)$(LIBDIR)/
|
||||
endif
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
|
||||
$(INSTALL_SUDO) cp pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
|
||||
$(INSTALL_SUDO) cp $(YOSYS_SRC)/pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
|
||||
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
|
||||
$(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
$(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc
|
||||
ifeq ($(ABCEXTERNAL),)
|
||||
$(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-abc$(EXE) $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc$(EXE)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
@ -1060,6 +1013,9 @@ uninstall:
|
|||
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
|
||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
|
||||
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
|
||||
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.a
|
||||
endif
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
|
||||
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
|
||||
|
|
@ -1140,16 +1096,8 @@ clean: clean-py clean-unit-test
|
|||
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
|
||||
rm -f kernel/version_*.o kernel/version_*.cc
|
||||
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
|
||||
rm -rf tests/asicworld/*.out tests/asicworld/*.log
|
||||
rm -rf tests/hana/*.out tests/hana/*.log
|
||||
rm -rf tests/simple/*.out tests/simple/*.log
|
||||
rm -rf tests/memories/*.out tests/memories/*.log tests/memories/*.dmp
|
||||
rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log
|
||||
rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp tests/various/temp
|
||||
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
|
||||
rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
|
||||
rm -f tests/tools/cmp_tbdata
|
||||
rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS))
|
||||
-$(MAKE) -C $(YOSYS_SRC)/tests clean
|
||||
-$(MAKE) -C $(YOSYS_SRC)/docs clean
|
||||
rm -rf docs/util/__pycache__
|
||||
rm -f libyosys.so
|
||||
|
|
@ -1158,7 +1106,7 @@ clean-py:
|
|||
rm -f $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc
|
||||
rm -f $(PYTHON_OBJECTS)
|
||||
rm -f *.whl
|
||||
rm -f libyosys.so
|
||||
rm -f libyosys.so libyosys.a
|
||||
rm -rf kernel/*.pyh
|
||||
|
||||
clean-abc:
|
||||
|
|
@ -1170,12 +1118,13 @@ mrproper: clean
|
|||
|
||||
coverage:
|
||||
./$(PROGRAM_PREFIX)yosys -qp 'help; help -all'
|
||||
rm -rf coverage.info coverage_html
|
||||
lcov --capture -d . --no-external -o coverage.info
|
||||
genhtml coverage.info --output-directory coverage_html
|
||||
rm -rf coverage_html
|
||||
llvm-profdata merge -sparse coverage/coverage_*.profraw -o yosys.profdata
|
||||
llvm-cov show ./$(PROGRAM_PREFIX)yosys -instr-profile=yosys.profdata -format=html -output-dir=coverage_html --compilation-dir=. -ignore-filename-regex='(^|.*/)libs/.*|/usr/include/.*|$(subst /,\/,$(VERIFIC_DIR))/.*'
|
||||
|
||||
clean_coverage:
|
||||
find . -name "*.gcda" -type f -delete
|
||||
rm -rf coverage
|
||||
rm -f yosys.profdata
|
||||
|
||||
FUNC_KERNEL := functional.cc functional.h sexpr.cc sexpr.h compute_graph.h
|
||||
FUNC_INCLUDES := $(addprefix --include *,functional/* $(FUNC_KERNEL))
|
||||
|
|
@ -1192,15 +1141,17 @@ qtcreator:
|
|||
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
|
||||
touch qtcreator.creator
|
||||
|
||||
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
|
||||
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
|
||||
VCX_DIR_NAME := yosys-win32-vcxsrc-$(YOSYS_VER)
|
||||
vcxsrc: $(GENFILES) $(EXTRA_TARGETS) kernel/version_$(GIT_REV).cc
|
||||
rm -rf $(VCX_DIR_NAME){,.zip}
|
||||
cp -f kernel/version_$(GIT_REV).cc kernel/version.cc
|
||||
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
|
||||
echo "Analyse: $$f" >&2; cpp -std=c++17 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
|
||||
echo "Analyse: $$f" >&2; cpp -std=c++20 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
|
||||
echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt
|
||||
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
|
||||
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
|
||||
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
|
||||
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
|
||||
echo "kernel/version.cc" >> srcfiles.txt
|
||||
bash misc/create_vcxsrc.sh $(VCX_DIR_NAME) $(YOSYS_VER)
|
||||
zip $(VCX_DIR_NAME)/genfiles.zip $(GENFILES) kernel/version.cc
|
||||
zip -r $(VCX_DIR_NAME).zip $(VCX_DIR_NAME)/
|
||||
rm -f srcfiles.txt kernel/version.cc
|
||||
|
||||
config-clean: clean
|
||||
|
|
@ -1235,7 +1186,7 @@ config-msys2-64: clean
|
|||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||
|
||||
config-gcov: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
echo 'CONFIG := clang' > Makefile.conf
|
||||
echo 'ENABLE_GCOV := 1' >> Makefile.conf
|
||||
echo 'ENABLE_DEBUG := 1' >> Makefile.conf
|
||||
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ To build Yosys simply type 'make' in this directory.
|
|||
$ sudo make install
|
||||
|
||||
Tests are located in the tests subdirectory and can be executed using the test
|
||||
target. Note that you need gawk as well as a recent version of iverilog (i.e.
|
||||
build from git). Then, execute tests via:
|
||||
target. Note that you need gawk, a recent version of iverilog, and gtest.
|
||||
Execute tests via:
|
||||
|
||||
$ make test
|
||||
|
||||
|
|
@ -246,6 +246,8 @@ Building the documentation
|
|||
|
||||
Note that there is no need to build the manual if you just want to read it.
|
||||
Simply visit https://yosys.readthedocs.io/en/latest/ instead.
|
||||
If you're offline, you can read the sources, replacing `.../en/latest`
|
||||
with `docs/source`.
|
||||
|
||||
In addition to those packages listed above for building Yosys from source, the
|
||||
following are used for building the website:
|
||||
|
|
|
|||
2
abc
2
abc
|
|
@ -1 +1 @@
|
|||
Subproject commit 1c5ed1ce378cc04beac30bb31abc4c37c8467042
|
||||
Subproject commit 5d51a5e420f5de493d07bf61109a977248c86ffb
|
||||
|
|
@ -340,7 +340,7 @@ struct AigerWriter
|
|||
if (cell->type == ID($scopeinfo))
|
||||
continue;
|
||||
|
||||
log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
|
||||
log_error("Unsupported cell type: %s (%s)\n", cell->type.unescape(), cell);
|
||||
}
|
||||
|
||||
for (auto bit : unused_bits)
|
||||
|
|
@ -349,10 +349,10 @@ struct AigerWriter
|
|||
if (!undriven_bits.empty()) {
|
||||
undriven_bits.sort();
|
||||
for (auto bit : undriven_bits) {
|
||||
log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
|
||||
log_warning("Treating undriven bit %s.%s like $anyseq.\n", module, log_signal(bit));
|
||||
input_bits.insert(bit);
|
||||
}
|
||||
log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
|
||||
log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), module);
|
||||
}
|
||||
|
||||
init_map.sort();
|
||||
|
|
@ -635,35 +635,35 @@ struct AigerWriter
|
|||
int a = aig_map.at(sig[i]);
|
||||
log_assert((a & 1) == 0);
|
||||
if (GetSize(wire) != 1)
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", log_id(wire), i));
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", wire, i));
|
||||
else
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", log_id(wire)));
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", wire));
|
||||
}
|
||||
|
||||
if (wire->port_output) {
|
||||
int o = ordered_outputs.at(SigSpec(wire, i));
|
||||
if (GetSize(wire) != 1)
|
||||
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i));
|
||||
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", wire, i));
|
||||
else
|
||||
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire)));
|
||||
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", wire));
|
||||
}
|
||||
|
||||
if (init_inputs.count(sig[i])) {
|
||||
int a = init_inputs.at(sig[i]);
|
||||
log_assert((a & 1) == 0);
|
||||
if (GetSize(wire) != 1)
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i));
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", wire, i));
|
||||
else
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire)));
|
||||
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", wire));
|
||||
}
|
||||
|
||||
if (ordered_latches.count(sig[i])) {
|
||||
int l = ordered_latches.at(sig[i]);
|
||||
const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : "";
|
||||
if (GetSize(wire) != 1)
|
||||
symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, log_id(wire), i));
|
||||
symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, wire, i));
|
||||
else
|
||||
symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, log_id(wire)));
|
||||
symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, wire));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -705,30 +705,30 @@ struct AigerWriter
|
|||
int index = no_startoffset ? i : (wire->start_offset+i);
|
||||
|
||||
if (verbose_map)
|
||||
wire_lines[a] += stringf("wire %d %d %s\n", a, index, log_id(wire));
|
||||
wire_lines[a] += stringf("wire %d %d %s\n", a, index, wire);
|
||||
|
||||
if (wire->port_input) {
|
||||
log_assert((a & 1) == 0);
|
||||
input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, index, log_id(wire));
|
||||
input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, index, wire);
|
||||
}
|
||||
|
||||
if (wire->port_output) {
|
||||
int o = ordered_outputs.at(SigSpec(wire, i));
|
||||
output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire));
|
||||
output_lines[o] += stringf("output %d %d %s\n", o, index, wire);
|
||||
}
|
||||
|
||||
if (init_inputs.count(sig[i])) {
|
||||
int a = init_inputs.at(sig[i]);
|
||||
log_assert((a & 1) == 0);
|
||||
init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, index, log_id(wire));
|
||||
init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, index, wire);
|
||||
}
|
||||
|
||||
if (ordered_latches.count(sig[i])) {
|
||||
int l = ordered_latches.at(sig[i]);
|
||||
if (zinit_mode && (aig_latchinit.at(l) == 1))
|
||||
latch_lines[l] += stringf("invlatch %d %d %s\n", l, index, log_id(wire));
|
||||
latch_lines[l] += stringf("invlatch %d %d %s\n", l, index, wire);
|
||||
else
|
||||
latch_lines[l] += stringf("latch %d %d %s\n", l, index, log_id(wire));
|
||||
latch_lines[l] += stringf("latch %d %d %s\n", l, index, wire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -930,7 +930,9 @@ struct AigerBackend : public Backend {
|
|||
log(" make indexes zero based, enable using map files with smt solvers.\n");
|
||||
log("\n");
|
||||
log(" -ywmap <filename>\n");
|
||||
log(" write a map file for conversion to and from yosys witness traces.\n");
|
||||
log(" write a map file for conversion to and from yosys witness traces,\n");
|
||||
log(" also allows for mapping AIGER bad-state properties and invariant\n");
|
||||
log(" constraints back to individual formal properties by name.\n");
|
||||
log("\n");
|
||||
log(" -I, -O, -B, -L\n");
|
||||
log(" If the design contains no input/output/assert/flip-flop then create one\n");
|
||||
|
|
@ -1025,12 +1027,12 @@ struct AigerBackend : public Backend {
|
|||
log_error("Can't find top module in current design!\n");
|
||||
|
||||
if (!design->selected_whole_module(top_module))
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", log_id(top_module));
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", top_module);
|
||||
|
||||
if (!top_module->processes.empty())
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in AIGER backend!\n", log_id(top_module));
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in AIGER backend!\n", top_module);
|
||||
if (!top_module->memories.empty())
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module));
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", top_module);
|
||||
|
||||
AigerWriter writer(top_module, no_sort, zinit_mode, imode, omode, bmode, lmode);
|
||||
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ struct XAigerWriter
|
|||
if (ys_debug(1)) {
|
||||
static pool<std::pair<IdString,TimingInfo::NameBit>> seen;
|
||||
if (seen.emplace(inst_module->name, i.first).second) log("%s.%s[%d] abc9_arrival = %d\n",
|
||||
log_id(cell->type), log_id(i.first.name), offset, d);
|
||||
cell->type.unescape(), i.first.name.unescape(), offset, d);
|
||||
}
|
||||
#endif
|
||||
arrival_times[rhs[offset]] = d;
|
||||
|
|
@ -285,7 +285,7 @@ struct XAigerWriter
|
|||
auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
|
||||
auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
|
||||
if (!is_input && !is_output)
|
||||
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
|
||||
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", c.first.unescape(), cell, cell->type.unescape());
|
||||
|
||||
if (is_input)
|
||||
for (auto b : c.second) {
|
||||
|
|
@ -303,7 +303,7 @@ struct XAigerWriter
|
|||
}
|
||||
}
|
||||
|
||||
//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
|
||||
//log_warning("Unsupported cell type: %s (%s)\n", cell->type.unescape(), cell);
|
||||
}
|
||||
|
||||
dict<IdString, std::vector<IdString>> box_ports;
|
||||
|
|
@ -325,12 +325,12 @@ struct XAigerWriter
|
|||
if (w->get_bool_attribute(ID::abc9_carry)) {
|
||||
if (w->port_input) {
|
||||
if (carry_in != IdString())
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module));
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", box_module);
|
||||
carry_in = port_name;
|
||||
}
|
||||
if (w->port_output) {
|
||||
if (carry_out != IdString())
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module));
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", box_module);
|
||||
carry_out = port_name;
|
||||
}
|
||||
}
|
||||
|
|
@ -339,9 +339,9 @@ struct XAigerWriter
|
|||
}
|
||||
|
||||
if (carry_in != IdString() && carry_out == IdString())
|
||||
log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module));
|
||||
log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", box_module);
|
||||
if (carry_in == IdString() && carry_out != IdString())
|
||||
log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module));
|
||||
log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", box_module);
|
||||
if (carry_in != IdString()) {
|
||||
r.first->second.push_back(carry_in);
|
||||
r.first->second.push_back(carry_out);
|
||||
|
|
@ -612,7 +612,7 @@ struct XAigerWriter
|
|||
write_r_buffer(mergeability);
|
||||
|
||||
State init = init_map.at(q, State::Sx);
|
||||
log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", log_id(cell), log_id(cell->type), log_signal(init));
|
||||
log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", cell, cell->type.unescape(), log_signal(init));
|
||||
if (init == State::S1)
|
||||
write_s_buffer(1);
|
||||
else if (init == State::S0)
|
||||
|
|
@ -692,12 +692,12 @@ struct XAigerWriter
|
|||
if (input_bits.count(b)) {
|
||||
int a = aig_map.at(b);
|
||||
log_assert((a & 1) == 0);
|
||||
input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire));
|
||||
input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, wire);
|
||||
}
|
||||
|
||||
if (output_bits.count(b)) {
|
||||
int o = ordered_outputs.at(b);
|
||||
output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), wire->start_offset+i, log_id(wire));
|
||||
output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), wire->start_offset+i, wire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -709,7 +709,7 @@ struct XAigerWriter
|
|||
|
||||
int box_count = 0;
|
||||
for (auto cell : box_list)
|
||||
f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
|
||||
f << stringf("box %d %d %s\n", box_count++, 0, cell->name.unescape());
|
||||
|
||||
output_lines.sort();
|
||||
for (auto &it : output_lines)
|
||||
|
|
@ -774,12 +774,12 @@ struct XAigerBackend : public Backend {
|
|||
log_error("Can't find top module in current design!\n");
|
||||
|
||||
if (!design->selected_whole_module(top_module))
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", log_id(top_module));
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", top_module);
|
||||
|
||||
if (!top_module->processes.empty())
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in XAIGER backend!\n", log_id(top_module));
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in XAIGER backend!\n", top_module);
|
||||
if (!top_module->memories.empty())
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module));
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", top_module);
|
||||
|
||||
XAigerWriter writer(top_module, dff_mode);
|
||||
writer.write_aiger(*f, ascii_mode);
|
||||
|
|
|
|||
|
|
@ -21,9 +21,13 @@
|
|||
// - gracefully handling inout ports (an error message probably)
|
||||
// - undriven wires
|
||||
// - zero-width operands
|
||||
// - decide how to unify this with cellaigs
|
||||
// - break up Index into something smaller
|
||||
// - (C++20) remove snprintf-into-std::ostream weirdness
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
@ -44,8 +48,22 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
// TODO
|
||||
//#define ARITH_OPS ID($add), ID($sub), ID($neg)
|
||||
|
||||
#define KNOWN_OPS BITWISE_OPS, REDUCE_OPS, LOGIC_OPS, GATE_OPS, ID($pos), CMP_OPS, \
|
||||
ID($pmux), ID($bmux) /*, ARITH_OPS*/
|
||||
static constexpr auto known_ops = []() constexpr {
|
||||
StaticCellTypes::Categories::Category c{};
|
||||
for (auto id : {BITWISE_OPS})
|
||||
c.set_id(id);
|
||||
for (auto id : {REDUCE_OPS})
|
||||
c.set_id(id);
|
||||
for (auto id : {LOGIC_OPS})
|
||||
c.set_id(id);
|
||||
for (auto id : {GATE_OPS})
|
||||
c.set_id(id);
|
||||
for (auto id : {CMP_OPS})
|
||||
c.set_id(id);
|
||||
for (auto id : {ID($pos), ID($pmux), ID($bmux)})
|
||||
c.set_id(id);
|
||||
return c;
|
||||
}();
|
||||
|
||||
template<typename Writer, typename Lit, Lit CFALSE, Lit CTRUE>
|
||||
struct Index {
|
||||
|
|
@ -91,7 +109,7 @@ struct Index {
|
|||
int pos = index_wires(info, m);
|
||||
|
||||
for (auto cell : m->cells()) {
|
||||
if (cell->type.in(KNOWN_OPS) || cell->type.in(ID($scopeinfo), ID($specify2), ID($specify3), ID($input_port)))
|
||||
if (known_ops(cell->type) || cell->type.in(ID($scopeinfo), ID($specify2), ID($specify3), ID($input_port)))
|
||||
continue;
|
||||
|
||||
Module *submodule = m->design->module(cell->type);
|
||||
|
|
@ -114,7 +132,7 @@ struct Index {
|
|||
continue;
|
||||
if (!submodule || submodule->get_blackbox_attribute())
|
||||
log_error("Unsupported cell type: %s (%s in %s)\n",
|
||||
log_id(cell->type), log_id(cell), log_id(m));
|
||||
cell->type.unescape(), cell, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -162,6 +180,11 @@ struct Index {
|
|||
if (!strashing) {
|
||||
return (static_cast<Writer*>(this))->emit_gate(a, b);
|
||||
} else {
|
||||
// AigMaker::node2index
|
||||
|
||||
// In XAIGER, the ordering of inputs is used to distinguish between AND
|
||||
// and XOR gates. AND gates have their first input literal be larger
|
||||
// than their second, and vice-versa for XORs.
|
||||
if (a < b) std::swap(a, b);
|
||||
auto pair = std::make_pair(a, b);
|
||||
|
||||
|
|
@ -182,7 +205,9 @@ struct Index {
|
|||
|
||||
Lit OR(Lit a, Lit b)
|
||||
{
|
||||
return NOT(AND(NOT(a), NOT(b)));
|
||||
Lit not_a = NOT(a);
|
||||
Lit not_b = NOT(b);
|
||||
return NOT(AND(not_a, not_b));
|
||||
}
|
||||
|
||||
Lit MUX(Lit a, Lit b, Lit s)
|
||||
|
|
@ -196,17 +221,24 @@ struct Index {
|
|||
return b;
|
||||
}
|
||||
|
||||
return OR(AND(a, NOT(s)), AND(b, s));
|
||||
Lit not_s = NOT(s);
|
||||
Lit a_active = AND(a, not_s);
|
||||
Lit b_active = AND(b, s);
|
||||
return OR(a_active, b_active);
|
||||
}
|
||||
|
||||
Lit XOR(Lit a, Lit b)
|
||||
{
|
||||
return OR(AND(a, NOT(b)), AND(NOT(a), b));
|
||||
Lit not_a = NOT(a);
|
||||
Lit not_b = NOT(b);
|
||||
Lit a_and_not_b = AND(a, not_b);
|
||||
Lit not_a_and_b = AND(not_a, b);
|
||||
return OR(a_and_not_b, not_a_and_b);
|
||||
}
|
||||
|
||||
Lit XNOR(Lit a, Lit b)
|
||||
{
|
||||
return NOT(OR(AND(a, NOT(b)), AND(NOT(a), b)));
|
||||
return NOT(XOR(a, b));
|
||||
}
|
||||
|
||||
Lit CARRY(Lit a, Lit b, Lit c)
|
||||
|
|
@ -218,7 +250,10 @@ struct Index {
|
|||
return AND(a, b);
|
||||
}
|
||||
}
|
||||
return OR(AND(a, b), AND(c, OR(a, b)));
|
||||
Lit a_or_b = OR(a, b);
|
||||
Lit a_or_b_and_c = AND(c, a_or_b);
|
||||
Lit a_and_b = AND(a, b);
|
||||
return OR(a_and_b, a_or_b_and_c);
|
||||
}
|
||||
|
||||
Lit REDUCE(std::vector<Lit> lits, bool op_xor=false)
|
||||
|
|
@ -366,7 +401,7 @@ struct Index {
|
|||
} else if (cell->type.in(ID($xor), ID($_XOR_))) {
|
||||
return XOR(a, b);
|
||||
} else if (cell->type.in(ID($xnor), ID($_XNOR_))) {
|
||||
return NOT(XOR(a, b));
|
||||
return XNOR(a, b);
|
||||
} else if (cell->type.in(ID($_ANDNOT_))) {
|
||||
return AND(a, NOT(b));
|
||||
} else if (cell->type.in(ID($_ORNOT_))) {
|
||||
|
|
@ -386,7 +421,9 @@ struct Index {
|
|||
if (oport == ID::Y) {
|
||||
return XOR(ab, c);
|
||||
} else /* oport == ID::X */ {
|
||||
return OR(AND(a, b), AND(c, ab));
|
||||
Lit a_and_b = AND(a, b);
|
||||
Lit c_and_ab = AND(c, ab);
|
||||
return OR(a_and_b, c_and_ab);
|
||||
}
|
||||
} else if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) {
|
||||
Lit c, d;
|
||||
|
|
@ -397,10 +434,15 @@ struct Index {
|
|||
else
|
||||
d = cell->type == ID($_AOI3_) ? CTRUE : CFALSE;
|
||||
|
||||
if (/* aoi */ cell->type.in(ID($_AOI3_), ID($_AOI4_)))
|
||||
return NOT(OR(AND(a, b), AND(c, d)));
|
||||
else
|
||||
return NOT(AND(OR(a, b), OR(c, d)));
|
||||
if (/* aoi */ cell->type.in(ID($_AOI3_), ID($_AOI4_))) {
|
||||
Lit a_and_b = AND(a, b);
|
||||
Lit c_and_d = AND(c, d);
|
||||
return NOT(OR(a_and_b, c_and_d));
|
||||
} else {
|
||||
Lit a_or_b = OR(a, b);
|
||||
Lit c_or_d = OR(c, d);
|
||||
return NOT(AND(a_or_b, c_or_d));
|
||||
}
|
||||
} else {
|
||||
log_abort();
|
||||
}
|
||||
|
|
@ -421,7 +463,11 @@ struct Index {
|
|||
sels.push_back(NOT(s));
|
||||
}
|
||||
|
||||
return OR(AND(REDUCE(sels), a), NOT(REDUCE(bar)));
|
||||
Lit reduce_sels = REDUCE(sels);
|
||||
Lit reduce_sels_and_a = AND(reduce_sels, a);
|
||||
Lit reduce_bar = NOT(REDUCE(bar));
|
||||
|
||||
return OR(reduce_sels_and_a, reduce_bar);
|
||||
} else if (cell->type == ID($bmux)) {
|
||||
SigSpec aport = cell->getPort(ID::A);
|
||||
SigSpec sport = cell->getPort(ID::S);
|
||||
|
|
@ -491,7 +537,7 @@ struct Index {
|
|||
Design *design = index.design;
|
||||
auto &minfo = leaf_minfo(index);
|
||||
if (!minfo.suboffsets.count(cell))
|
||||
log_error("Reached unsupport cell %s (%s in %s)\n", log_id(cell->type), log_id(cell), log_id(cell->module));
|
||||
log_error("Reached unsupported cell %s (%s in %s)\n", cell->type.unescape(), cell, cell->module);
|
||||
Module *def = design->module(cell->type);
|
||||
log_assert(def);
|
||||
levels.push_back(Level(index.modules.at(def), cell));
|
||||
|
|
@ -510,13 +556,13 @@ struct Index {
|
|||
{
|
||||
std::string ret;
|
||||
bool first = true;
|
||||
for (auto pair : levels) {
|
||||
for (auto [minfo, cell] : levels) {
|
||||
if (!first)
|
||||
ret += ".";
|
||||
if (!pair.second)
|
||||
ret += RTLIL::unescape_id(pair.first.module->name);
|
||||
if (!cell)
|
||||
ret += minfo.module->name.unescape();
|
||||
else
|
||||
ret += RTLIL::unescape_id(pair.second->name);
|
||||
ret += cell->name.unescape();
|
||||
first = false;
|
||||
}
|
||||
return ret;
|
||||
|
|
@ -525,8 +571,8 @@ struct Index {
|
|||
int hash() const
|
||||
{
|
||||
int hash = 0;
|
||||
for (auto pair : levels)
|
||||
hash += (uintptr_t) pair.second;
|
||||
for (auto [_, cell] : levels)
|
||||
hash += (uintptr_t) cell;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -535,9 +581,12 @@ struct Index {
|
|||
if (levels.size() != other.levels.size())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < levels.size(); i++)
|
||||
if (levels[i].second != other.levels[i].second)
|
||||
for (int i = 0; i < levels.size(); i++) {
|
||||
auto* cell = levels[i].second;
|
||||
auto* other_cell = other.levels[i].second;
|
||||
if (cell != other_cell)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -578,7 +627,7 @@ struct Index {
|
|||
// an output of a cell
|
||||
Cell *driver = bit.wire->driverCell();
|
||||
|
||||
if (driver->type.in(KNOWN_OPS)) {
|
||||
if (known_ops(driver->type)) {
|
||||
ret = impl_op(cursor, driver, bit.wire->driverPort(), bit.offset);
|
||||
} else {
|
||||
Module *def = cursor.enter(*this, driver);
|
||||
|
|
@ -587,10 +636,10 @@ struct Index {
|
|||
Wire *w = def->wire(portname);
|
||||
if (!w)
|
||||
log_error("Output port %s on instance %s of %s doesn't exist\n",
|
||||
log_id(portname), log_id(driver), log_id(def));
|
||||
portname.unescape(), driver, def);
|
||||
if (bit.offset >= w->width)
|
||||
log_error("Bit position %d of output port %s on instance %s of %s is out of range (port has width %d)\n",
|
||||
bit.offset, log_id(portname), log_id(driver), log_id(def), w->width);
|
||||
bit.offset, portname.unescape(), driver, def, w->width);
|
||||
ret = visit(cursor, SigBit(w, bit.offset));
|
||||
}
|
||||
cursor.exit(*this);
|
||||
|
|
@ -606,11 +655,11 @@ struct Index {
|
|||
IdString portname = bit.wire->name;
|
||||
if (!instance->hasPort(portname))
|
||||
log_error("Input port %s on instance %s of %s unconnected\n",
|
||||
log_id(portname), log_id(instance), log_id(instance->type));
|
||||
portname.unescape(), instance, instance->type);
|
||||
auto &port = instance->getPort(portname);
|
||||
if (bit.offset >= port.size())
|
||||
log_error("Bit %d of input port %s on instance %s of %s unconnected\n",
|
||||
bit.offset, log_id(portname), log_id(instance), log_id(instance->type));
|
||||
bit.offset, portname.unescape(), instance, instance->type.unescape());
|
||||
ret = visit(cursor, port[bit.offset]);
|
||||
}
|
||||
cursor.enter(*this, instance);
|
||||
|
|
@ -700,6 +749,9 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
nands++;
|
||||
lit_counter += 2;
|
||||
|
||||
// In XAIGER, the ordering of inputs is used to distinguish between AND
|
||||
// and XOR gates. AND gates have their first input literal be larger
|
||||
// than their second, and vice-versa for XORs.
|
||||
if (a < b) std::swap(a, b);
|
||||
encode(out - a);
|
||||
encode(a - b);
|
||||
|
|
@ -716,7 +768,7 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
log_assert(lit_counter == (Lit) (ninputs + nlatches + nands) * 2 + 2);
|
||||
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf) - 1, "aig %08d %08d %08d %08d %08d\n",
|
||||
snprintf(buf, sizeof(buf), "aig %08d %08d %08d %08d %08d\n",
|
||||
ninputs + nlatches + nands, ninputs, nlatches, noutputs, nands);
|
||||
f->write(buf, strlen(buf));
|
||||
}
|
||||
|
|
@ -729,15 +781,16 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
// populate inputs
|
||||
std::vector<SigBit> inputs;
|
||||
for (auto id : top->ports) {
|
||||
Wire *w = top->wire(id);
|
||||
log_assert(w);
|
||||
if (w->port_input && !w->port_output)
|
||||
for (int i = 0; i < w->width; i++) {
|
||||
pi_literal(SigBit(w, i)) = lit_counter;
|
||||
inputs.push_back(SigBit(w, i));
|
||||
lit_counter += 2;
|
||||
ninputs++;
|
||||
}
|
||||
Wire *w = top->wire(id);
|
||||
log_assert(w);
|
||||
if (w->port_input && !w->port_output)
|
||||
for (int i = 0; i < w->width; i++) {
|
||||
auto bit = SigBit(w, i);
|
||||
pi_literal(bit) = lit_counter;
|
||||
inputs.push_back(bit);
|
||||
lit_counter += 2;
|
||||
ninputs++;
|
||||
}
|
||||
}
|
||||
|
||||
this->f = f;
|
||||
|
|
@ -745,35 +798,38 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
write_header();
|
||||
// insert padding where output literals will go (once known)
|
||||
for (auto id : top->ports) {
|
||||
Wire *w = top->wire(id);
|
||||
log_assert(w);
|
||||
if (w->port_output) {
|
||||
for (auto bit : SigSpec(w)) {
|
||||
(void) bit;
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf) - 1, "%08d\n", 0);
|
||||
f->write(buf, strlen(buf));
|
||||
noutputs++;
|
||||
Wire *w = top->wire(id);
|
||||
log_assert(w);
|
||||
if (w->port_output) {
|
||||
for (auto bit : SigSpec(w)) {
|
||||
(void) bit;
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%08d\n", 0);
|
||||
f->write(buf, strlen(buf));
|
||||
noutputs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto data_start = f->tellp();
|
||||
|
||||
// now the guts
|
||||
std::vector<std::pair<SigBit, int>> outputs;
|
||||
for (auto w : top->wires())
|
||||
if (w->port_output) {
|
||||
for (auto bit : SigSpec(w))
|
||||
outputs.push_back({bit, eval_po(bit)});
|
||||
}
|
||||
if (w->port_output) {
|
||||
for (auto bit : SigSpec(w))
|
||||
// Each call to eval_po eventually reaches emit_gate and
|
||||
// encode which writes to f.
|
||||
outputs.push_back({bit, eval_po(bit)});
|
||||
}
|
||||
|
||||
auto data_end = f->tellp();
|
||||
|
||||
// revisit header and the list of outputs
|
||||
f->seekp(file_start);
|
||||
write_header();
|
||||
for (auto pair : outputs) {
|
||||
for (auto [_, po] : outputs) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf) - 1, "%08d\n", pair.second);
|
||||
snprintf(buf, sizeof(buf), "%08d\n", po);
|
||||
f->write(buf, strlen(buf));
|
||||
}
|
||||
// double check we arrived at the same offset for the
|
||||
|
|
@ -782,12 +838,13 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
|
||||
f->seekp(data_end);
|
||||
int i = 0;
|
||||
for (auto pair : outputs) {
|
||||
if (SigSpec(pair.first).is_wire()) {
|
||||
for (auto [bit, _] : outputs) {
|
||||
if (SigSpec(bit).is_wire()) {
|
||||
// primary output symbol
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf) - 1, "o%d ", i);
|
||||
snprintf(buf, sizeof(buf), "o%d ", i);
|
||||
f->write(buf, strlen(buf));
|
||||
std::string name = RTLIL::unescape_id(pair.first.wire->name);
|
||||
std::string name = bit.wire->name.unescape();
|
||||
f->write(name.data(), name.size());
|
||||
f->put('\n');
|
||||
}
|
||||
|
|
@ -796,10 +853,11 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
i = 0;
|
||||
for (auto bit : inputs) {
|
||||
if (SigSpec(bit).is_wire()) {
|
||||
// primary input symbol
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf) - 1, "i%d ", i);
|
||||
snprintf(buf, sizeof(buf), "i%d ", i);
|
||||
f->write(buf, strlen(buf));
|
||||
std::string name = RTLIL::unescape_id(bit.wire->name);
|
||||
std::string name = bit.wire->name.unescape();
|
||||
f->write(name.data(), name.size());
|
||||
f->put('\n');
|
||||
}
|
||||
|
|
@ -845,11 +903,14 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
|||
return false;
|
||||
|
||||
int max = 1;
|
||||
for (auto wire : mod->wires())
|
||||
if (wire->port_input && !wire->port_output)
|
||||
for (int i = 0; i < wire->width; i++) {
|
||||
int ilevel = visit(cursor, driver->getPort(wire->name)[i]);
|
||||
max = std::max(max, ilevel + 1);
|
||||
for (auto wire : mod->wires()) {
|
||||
if (wire->port_input && !wire->port_output) {
|
||||
SigSpec port = driver->getPort(wire->name);
|
||||
for (int i = 0; i < std::min(wire->width, port.size()); i++) {
|
||||
int ilevel = visit(cursor, port[i]);
|
||||
max = std::max(max, ilevel + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
lits[idx] = max;
|
||||
|
||||
|
|
@ -867,33 +928,34 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
|||
Wire *w = top->wire(id);
|
||||
log_assert(w);
|
||||
if (w->port_input && !w->port_output)
|
||||
for (int i = 0; i < w->width; i++)
|
||||
pi_literal(SigBit(w, i)) = 0;
|
||||
for (int i = 0; i < w->width; i++)
|
||||
pi_literal(SigBit(w, i)) = 0;
|
||||
}
|
||||
|
||||
HierCursor cursor;
|
||||
for (auto box : top_minfo->found_blackboxes) {
|
||||
Module *def = design->module(box->type);
|
||||
if (!(def && def->has_attribute(ID::abc9_box_id)))
|
||||
for (auto &conn : box->connections_)
|
||||
if (box->port_dir(conn.first) != RTLIL::PD_INPUT)
|
||||
for (auto bit : conn.second)
|
||||
pi_literal(bit, &cursor) = 0;
|
||||
for (auto &conn : box->connections_)
|
||||
if (box->port_dir(conn.first) != RTLIL::PD_INPUT)
|
||||
for (auto bit : conn.second)
|
||||
pi_literal(bit, &cursor) = 0;
|
||||
}
|
||||
|
||||
for (auto w : top->wires())
|
||||
if (w->port_output) {
|
||||
for (auto bit : SigSpec(w))
|
||||
(void) eval_po(bit);
|
||||
for (auto w : top->wires()) {
|
||||
if (w->port_output) {
|
||||
for (auto bit : SigSpec(w))
|
||||
(void) eval_po(bit);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto box : top_minfo->found_blackboxes) {
|
||||
Module *def = design->module(box->type);
|
||||
if (!(def && def->has_attribute(ID::abc9_box_id)))
|
||||
for (auto &conn : box->connections_)
|
||||
if (box->port_dir(conn.first) == RTLIL::PD_INPUT)
|
||||
for (auto bit : conn.second)
|
||||
(void) eval_po(bit);
|
||||
for (auto &conn : box->connections_)
|
||||
if (box->port_dir(conn.first) == RTLIL::PD_INPUT)
|
||||
for (auto bit : conn.second)
|
||||
(void) eval_po(bit);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -912,15 +974,15 @@ struct XAigerWriter : AigerWriter {
|
|||
std::vector<HierBit> pos;
|
||||
std::vector<HierBit> pis;
|
||||
|
||||
// * The aiger output port sequence is COs (inputs to modeled boxes),
|
||||
// inputs to opaque boxes, then module outputs. COs going first is
|
||||
// required by abc.
|
||||
// * proper_pos_counter counts ports which follow after COs
|
||||
// * The mapping file `pseudopo` and `po` statements use indexing relative
|
||||
// to the first port following COs.
|
||||
// * If a module output is directly driven by an opaque box, the emission
|
||||
// of the po statement in the mapping file is skipped. This is done to
|
||||
// aid re-integration of the mapped result.
|
||||
// * The aiger output port sequence is COs (inputs to modeled boxes),
|
||||
// inputs to opaque boxes, then module outputs. COs going first is
|
||||
// required by abc.
|
||||
// * proper_pos_counter counts ports which follow after COs
|
||||
// * The mapping file `pseudopo` and `po` statements use indexing relative
|
||||
// to the first port following COs.
|
||||
// * If a module output is directly driven by an opaque box, the emission
|
||||
// of the po statement in the mapping file is skipped. This is done to
|
||||
// aid re-integration of the mapped result.
|
||||
int proper_pos_counter = 0;
|
||||
|
||||
pool<SigBit> driven_by_opaque_box;
|
||||
|
|
@ -986,7 +1048,7 @@ struct XAigerWriter : AigerWriter {
|
|||
} else if (!is_input && !inputs) {
|
||||
for (auto &bit : conn.second) {
|
||||
if (!bit.wire || (bit.wire->port_input && !bit.wire->port_output))
|
||||
log_error("Bad connection %s/%s ~ %s\n", log_id(box), log_id(conn.first), log_signal(conn.second));
|
||||
log_error("Bad connection %s/%s ~ %s\n", box, conn.first.unescape(), log_signal(conn.second));
|
||||
|
||||
|
||||
ensure_pi(bit, cursor);
|
||||
|
|
@ -1011,9 +1073,9 @@ struct XAigerWriter : AigerWriter {
|
|||
void prep_boxes(int pending_pos_num)
|
||||
{
|
||||
XAigerAnalysis analysis;
|
||||
log_debug("preforming analysis on '%s'\n", log_id(top));
|
||||
log_debug("preforming analysis on '%s'\n", top);
|
||||
analysis.analyze(top);
|
||||
log_debug("analysis on '%s' done\n", log_id(top));
|
||||
log_debug("analysis on '%s' done\n", top);
|
||||
|
||||
// boxes which have timing data, maybe a whitebox model
|
||||
std::vector<std::tuple<HierCursor, Cell *, Module *>> nonopaque_boxes;
|
||||
|
|
@ -1026,8 +1088,8 @@ struct XAigerWriter : AigerWriter {
|
|||
|
||||
for (auto box : minfo.found_blackboxes) {
|
||||
log_debug(" - %s.%s (type %s): ", cursor.path(),
|
||||
RTLIL::unescape_id(box->name),
|
||||
log_id(box->type));
|
||||
box,
|
||||
box->type.unescape());
|
||||
|
||||
Module *box_module = design->module(box->type), *box_derived;
|
||||
|
||||
|
|
@ -1096,7 +1158,7 @@ struct XAigerWriter : AigerWriter {
|
|||
} else {
|
||||
// FIXME: hierarchical path
|
||||
log_warning("connection on port %s[%d] of instance %s (type %s) missing, using 1'bx\n",
|
||||
log_id(port_id), i, log_id(box), log_id(box->type));
|
||||
port_id.unescape(), i, box, box->type.unescape());
|
||||
bit = RTLIL::Sx;
|
||||
}
|
||||
|
||||
|
|
@ -1131,7 +1193,7 @@ struct XAigerWriter : AigerWriter {
|
|||
} else {
|
||||
// FIXME: hierarchical path
|
||||
log_warning("connection on port %s[%d] of instance %s (type %s) missing\n",
|
||||
log_id(port_id), i, log_id(box), log_id(box->type));
|
||||
port_id.unescape(), i, box, box->type.unescape());
|
||||
pad_pi();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1148,7 +1210,7 @@ struct XAigerWriter : AigerWriter {
|
|||
holes_wb->setPort(port_id, w);
|
||||
} else {
|
||||
log_error("Ambiguous port direction on %s/%s\n",
|
||||
log_id(box->type), log_id(port_id));
|
||||
box->type.unescape(), port_id.unescape());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1198,29 +1260,29 @@ struct XAigerWriter : AigerWriter {
|
|||
reset_counters();
|
||||
|
||||
for (auto w : top->wires())
|
||||
if (w->port_input && !w->port_output)
|
||||
for (int i = 0; i < w->width; i++)
|
||||
ensure_pi(SigBit(w, i));
|
||||
if (w->port_input && !w->port_output)
|
||||
for (int i = 0; i < w->width; i++)
|
||||
ensure_pi(SigBit(w, i));
|
||||
|
||||
int proper_po_num = 0;
|
||||
for (auto w : top->wires())
|
||||
if (w->port_output)
|
||||
proper_po_num += w->width;
|
||||
if (w->port_output)
|
||||
proper_po_num += w->width;
|
||||
|
||||
prep_boxes(proper_po_num);
|
||||
for (auto w : top->wires())
|
||||
if (w->port_output)
|
||||
for (int i = 0; i < w->width; i++) {
|
||||
// When a module output is directly driven by an opaque box, we
|
||||
// don't emit it to the mapping file to aid re-integration, but we
|
||||
// do emit a proper PO.
|
||||
if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) {
|
||||
map_file << "po " << proper_pos_counter << " " << i
|
||||
<< " " << w->name.c_str() << "\n";
|
||||
}
|
||||
proper_pos_counter++;
|
||||
pos.push_back(std::make_pair(SigBit(w, i), HierCursor{}));
|
||||
}
|
||||
if (w->port_output)
|
||||
for (int i = 0; i < w->width; i++) {
|
||||
// When a module output is directly driven by an opaque box, we
|
||||
// don't emit it to the mapping file to aid re-integration, but we
|
||||
// do emit a proper PO.
|
||||
if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) {
|
||||
map_file << "po " << proper_pos_counter << " " << i
|
||||
<< " " << w->name.c_str() << "\n";
|
||||
}
|
||||
proper_pos_counter++;
|
||||
pos.push_back(std::make_pair(SigBit(w, i), HierCursor{}));
|
||||
}
|
||||
|
||||
this->f = f;
|
||||
// start with the header
|
||||
|
|
@ -1230,7 +1292,7 @@ struct XAigerWriter : AigerWriter {
|
|||
// insert padding where output literals will go (once known)
|
||||
for (auto _ : pos) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf) - 1, "%08d\n", 0);
|
||||
snprintf(buf, sizeof(buf), "%08d\n", 0);
|
||||
f->write(buf, strlen(buf));
|
||||
}
|
||||
auto data_start = f->tellp();
|
||||
|
|
@ -1247,35 +1309,36 @@ struct XAigerWriter : AigerWriter {
|
|||
write_header();
|
||||
for (auto lit : outlits) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf) - 1, "%08d\n", lit);
|
||||
snprintf(buf, sizeof(buf), "%08d\n", lit);
|
||||
f->write(buf, strlen(buf));
|
||||
}
|
||||
// double check we arrived at the same offset for the
|
||||
// main data section
|
||||
log_assert(data_start == f->tellp());
|
||||
|
||||
// extensions
|
||||
// XAIGER extensions
|
||||
f->seekp(0, std::ios::end);
|
||||
|
||||
f->put('c');
|
||||
f->put('c'); // 'c': comment (marks beginning of extensions)
|
||||
|
||||
// insert empty 'r' and 's' sections (abc crashes if we provide 'a' without those)
|
||||
f->put('r');
|
||||
write_be32(*f, 4);
|
||||
write_be32(*f, 0);
|
||||
f->put('s');
|
||||
write_be32(*f, 4);
|
||||
write_be32(*f, 0);
|
||||
f->put('r'); // 'r': register classes
|
||||
write_be32(*f, 4); // length in bytes
|
||||
write_be32(*f, 0); // no register classes
|
||||
|
||||
f->put('h');
|
||||
f->put('s'); // 's': register initial values
|
||||
write_be32(*f, 4); // length in bytes
|
||||
write_be32(*f, 0); // no register initial values
|
||||
|
||||
f->put('h'); // 'h': hierarchy information
|
||||
// TODO: get rid of std::string copy
|
||||
std::string h_buffer_str = h_buffer.str();
|
||||
write_be32(*f, h_buffer_str.size());
|
||||
f->write(h_buffer_str.data(), h_buffer_str.size());
|
||||
write_be32(*f, h_buffer_str.size()); // length in bytes
|
||||
f->write(h_buffer_str.data(), h_buffer_str.size()); // data
|
||||
|
||||
#if 1
|
||||
f->put('a');
|
||||
write_be32(*f, 0); // size to be filled later
|
||||
f->put('a'); // 'a': additional AIG (used for holes)
|
||||
write_be32(*f, 0); // length in bytes (to be filled later)
|
||||
auto holes_aiger_start = f->tellp();
|
||||
{
|
||||
AigerWriter holes_writer;
|
||||
|
|
@ -1287,7 +1350,7 @@ struct XAigerWriter : AigerWriter {
|
|||
auto holes_aiger_size = f->tellp() - holes_aiger_start;
|
||||
f->seekp(holes_aiger_start, std::ios::beg);
|
||||
f->seekp(-4, std::ios::cur);
|
||||
write_be32(*f, holes_aiger_size);
|
||||
write_be32(*f, holes_aiger_size); // length in bytes
|
||||
#endif
|
||||
f->seekp(0, std::ios::end);
|
||||
|
||||
|
|
@ -1327,41 +1390,50 @@ struct Aiger2Backend : Backend {
|
|||
log(" perform structural hashing while writing\n");
|
||||
log("\n");
|
||||
log(" -flatten\n");
|
||||
log(" allow descending into submodules and write a flattened view of the design\n");
|
||||
log(" hierarchy starting at the selected top\n");
|
||||
log("\n");
|
||||
log(" allow descending into submodules and write a flattened view of the design\n");
|
||||
log(" hierarchy starting at the selected top\n");
|
||||
log("\n");
|
||||
log("This command is able to ingest all combinational cells except for:\n");
|
||||
log("\n");
|
||||
pool<IdString> supported = {KNOWN_OPS};
|
||||
CellTypes ct;
|
||||
ct.setup_internals_eval();
|
||||
log(" ");
|
||||
int col = 0;
|
||||
for (auto pair : ct.cell_types)
|
||||
if (!supported.count(pair.first)) {
|
||||
if (col + pair.first.size() + 2 > 72) {
|
||||
for (size_t i = 0; i < StaticCellTypes::builder.count; i++) {
|
||||
auto &cell = StaticCellTypes::builder.cells[i];
|
||||
if (!cell.features.is_evaluable)
|
||||
continue;
|
||||
if (cell.features.is_stdcell)
|
||||
continue;
|
||||
if (known_ops(cell.type))
|
||||
continue;
|
||||
std::string name = cell.type.unescape();
|
||||
if (col + name.size() + 2 > 72) {
|
||||
log("\n ");
|
||||
col = 0;
|
||||
}
|
||||
col += pair.first.size() + 2;
|
||||
log("%s, ", log_id(pair.first));
|
||||
col += name.size() + 2;
|
||||
log("%s, ", name.c_str());
|
||||
}
|
||||
log("\n");
|
||||
log("\n");
|
||||
log("And all combinational gates except for:\n");
|
||||
log("\n");
|
||||
CellTypes ct2;
|
||||
ct2.setup_stdcells();
|
||||
log(" ");
|
||||
col = 0;
|
||||
for (auto pair : ct2.cell_types)
|
||||
if (!supported.count(pair.first)) {
|
||||
if (col + pair.first.size() + 2 > 72) {
|
||||
for (size_t i = 0; i < StaticCellTypes::builder.count; i++) {
|
||||
auto &cell = StaticCellTypes::builder.cells[i];
|
||||
if (!cell.features.is_evaluable)
|
||||
continue;
|
||||
if (!cell.features.is_stdcell)
|
||||
continue;
|
||||
if (known_ops(cell.type))
|
||||
continue;
|
||||
std::string name = cell.type.unescape();
|
||||
if (col + name.size() + 2 > 72) {
|
||||
log("\n ");
|
||||
col = 0;
|
||||
}
|
||||
col += pair.first.size() + 2;
|
||||
log("%s, ", log_id(pair.first));
|
||||
col += name.size() + 2;
|
||||
log("%s, ", name.c_str());
|
||||
}
|
||||
log("\n");
|
||||
}
|
||||
|
|
@ -1419,20 +1491,20 @@ struct XAiger2Backend : Backend {
|
|||
log(" perform structural hashing while writing\n");
|
||||
log("\n");
|
||||
log(" -flatten\n");
|
||||
log(" allow descending into submodules and write a flattened view of the design\n");
|
||||
log(" hierarchy starting at the selected top\n");
|
||||
log("\n");
|
||||
log(" -mapping_prep\n");
|
||||
log(" after the file is written, prepare the module for reintegration of\n");
|
||||
log(" a mapping in a subsequent command. all cells which are not blackboxed nor\n");
|
||||
log(" whiteboxed are removed from the design as well as all wires which only\n");
|
||||
log(" connect to removed cells\n");
|
||||
log(" (conflicts with -flatten)\n");
|
||||
log("\n");
|
||||
log(" -map2 <file>\n");
|
||||
log(" write a map2 file which 'read_xaiger2 -sc_mapping' can read to\n");
|
||||
log(" reintegrate a mapping\n");
|
||||
log(" (conflicts with -flatten)\n");
|
||||
log(" allow descending into submodules and write a flattened view of the design\n");
|
||||
log(" hierarchy starting at the selected top\n");
|
||||
log("\n");
|
||||
log(" -mapping_prep\n");
|
||||
log(" after the file is written, prepare the module for reintegration of\n");
|
||||
log(" a mapping in a subsequent command. all cells which are not blackboxed nor\n");
|
||||
log(" whiteboxed are removed from the design as well as all wires which only\n");
|
||||
log(" connect to removed cells\n");
|
||||
log(" (conflicts with -flatten)\n");
|
||||
log("\n");
|
||||
log(" -map2 <file>\n");
|
||||
log(" write a map2 file which 'read_xaiger2 -sc_mapping' can read to\n");
|
||||
log(" reintegrate a mapping\n");
|
||||
log(" (conflicts with -flatten)\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
|
|
@ -44,6 +44,7 @@ struct BlifDumperConfig
|
|||
bool iattr_mode;
|
||||
bool blackbox_mode;
|
||||
bool noalias_mode;
|
||||
bool gatesi_mode;
|
||||
|
||||
std::string buf_type, buf_in, buf_out;
|
||||
std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
|
||||
|
|
@ -51,7 +52,7 @@ struct BlifDumperConfig
|
|||
|
||||
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false),
|
||||
cname_mode(false), iname_mode(false), param_mode(false), attr_mode(false), iattr_mode(false),
|
||||
blackbox_mode(false), noalias_mode(false) { }
|
||||
blackbox_mode(false), noalias_mode(false), gatesi_mode(false) { }
|
||||
};
|
||||
|
||||
struct BlifDumper
|
||||
|
|
@ -60,7 +61,7 @@ struct BlifDumper
|
|||
RTLIL::Module *module;
|
||||
RTLIL::Design *design;
|
||||
BlifDumperConfig *config;
|
||||
CellTypes ct;
|
||||
NewCellTypes ct;
|
||||
|
||||
SigMap sigmap;
|
||||
dict<SigBit, int> init_bits;
|
||||
|
|
@ -90,7 +91,7 @@ struct BlifDumper
|
|||
|
||||
const std::string str(RTLIL::IdString id)
|
||||
{
|
||||
std::string str = RTLIL::unescape_id(id);
|
||||
std::string str = id.unescape();
|
||||
for (size_t i = 0; i < str.size(); i++)
|
||||
if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>')
|
||||
str[i] = '?';
|
||||
|
|
@ -107,7 +108,7 @@ struct BlifDumper
|
|||
return config->undef_type == "-" || config->undef_type == "+" ? config->undef_out.c_str() : "$undef";
|
||||
}
|
||||
|
||||
std::string str = RTLIL::unescape_id(sig.wire->name);
|
||||
std::string str = sig.wire->name.unescape();
|
||||
for (size_t i = 0; i < str.size(); i++)
|
||||
if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>')
|
||||
str[i] = '?';
|
||||
|
|
@ -118,16 +119,21 @@ struct BlifDumper
|
|||
return str;
|
||||
}
|
||||
|
||||
const std::string str_init(RTLIL::SigBit sig)
|
||||
template <bool Space = true> const std::string str_init(RTLIL::SigBit sig)
|
||||
{
|
||||
sigmap.apply(sig);
|
||||
|
||||
if (init_bits.count(sig) == 0)
|
||||
return " 2";
|
||||
if (init_bits.count(sig) == 0) {
|
||||
if constexpr (Space)
|
||||
return " 2";
|
||||
else
|
||||
return "2";
|
||||
}
|
||||
|
||||
string str = stringf(" %d", init_bits.at(sig));
|
||||
|
||||
return str;
|
||||
if constexpr (Space)
|
||||
return stringf(" %d", init_bits.at(sig));
|
||||
else
|
||||
return stringf("%d", init_bits.at(sig));
|
||||
}
|
||||
|
||||
const char *subckt_or_gate(std::string cell_type)
|
||||
|
|
@ -144,7 +150,7 @@ struct BlifDumper
|
|||
void dump_params(const char *command, dict<IdString, Const> ¶ms)
|
||||
{
|
||||
for (auto ¶m : params) {
|
||||
f << stringf("%s %s ", command, log_id(param.first));
|
||||
f << stringf("%s %s ", command, param.first.unescape());
|
||||
if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
|
||||
std::string str = param.second.decode_string();
|
||||
f << stringf("\"");
|
||||
|
|
@ -469,6 +475,11 @@ struct BlifDumper
|
|||
f << stringf(".names %s %s\n1 1\n", str(rhs_bit), str(lhs_bit));
|
||||
}
|
||||
|
||||
if (config->gatesi_mode) {
|
||||
for (auto &&init_bit : init_bits)
|
||||
f << stringf(".gateinit %s=%s\n", str(init_bit.first), str_init<false>(init_bit.first));
|
||||
}
|
||||
|
||||
f << stringf(".end\n");
|
||||
}
|
||||
|
||||
|
|
@ -550,6 +561,9 @@ struct BlifBackend : public Backend {
|
|||
log(" -impltf\n");
|
||||
log(" do not write definitions for the $true, $false and $undef wires.\n");
|
||||
log("\n");
|
||||
log(" -gatesi\n");
|
||||
log(" write initial bit(s) with .gateinit for gates that needs to be initialized.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
|
|
@ -640,6 +654,10 @@ struct BlifBackend : public Backend {
|
|||
config.noalias_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-gatesi") {
|
||||
config.gatesi_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
|
@ -660,9 +678,9 @@ struct BlifBackend : public Backend {
|
|||
continue;
|
||||
|
||||
if (module->processes.size() != 0)
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", log_id(module->name));
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", module->name.unescape());
|
||||
if (module->memories.size() != 0)
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", log_id(module->name));
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", module->name.unescape());
|
||||
|
||||
if (module->name == RTLIL::escape_id(top_module_name)) {
|
||||
BlifDumper::dump(*f, module, design, config);
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ struct BtorWorker
|
|||
template<typename T>
|
||||
string getinfo(T *obj, bool srcsym = false)
|
||||
{
|
||||
string infostr = log_id(obj);
|
||||
string infostr = obj->name.unescape();
|
||||
if (!srcsym && !print_internal_names && infostr[0] == '$') return "";
|
||||
if (obj->attributes.count(ID::src)) {
|
||||
string src = obj->attributes.at(ID::src).decode_string().c_str();
|
||||
|
|
@ -243,12 +243,12 @@ struct BtorWorker
|
|||
if (cell_recursion_guard.count(cell)) {
|
||||
string cell_list;
|
||||
for (auto c : cell_recursion_guard)
|
||||
cell_list += stringf("\n %s", log_id(c));
|
||||
log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list);
|
||||
cell_list += stringf("\n %s", c);
|
||||
log_error("Found topological loop while processing cell %s. Active cells:%s\n", cell, cell_list);
|
||||
}
|
||||
|
||||
cell_recursion_guard.insert(cell);
|
||||
btorf_push(log_id(cell));
|
||||
btorf_push(cell->name.unescape());
|
||||
|
||||
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($sshl), ID($shr), ID($sshr), ID($shift), ID($shiftx),
|
||||
ID($concat), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_)))
|
||||
|
|
@ -726,7 +726,7 @@ struct BtorWorker
|
|||
if (symbol.empty() || (!print_internal_names && symbol[0] == '$'))
|
||||
btorf("%d state %d\n", nid, sid);
|
||||
else
|
||||
btorf("%d state %d %s\n", nid, sid, log_id(symbol));
|
||||
btorf("%d state %d %s\n", nid, sid, symbol.unescape());
|
||||
|
||||
if (cell->get_bool_attribute(ID(clk2fflogic)))
|
||||
ywmap_state(cell->getPort(ID::D)); // For a clk2fflogic FF the named signal is the D input not the Q output
|
||||
|
|
@ -804,12 +804,12 @@ struct BtorWorker
|
|||
|
||||
if (asyncwr && syncwr)
|
||||
log_error("Memory %s.%s has mixed async/sync write ports.\n",
|
||||
log_id(module), log_id(mem->memid));
|
||||
module, mem->memid.unescape());
|
||||
|
||||
for (auto &port : mem->rd_ports) {
|
||||
if (port.clk_enable)
|
||||
log_error("Memory %s.%s has sync read ports. Please use memory_nordff to convert them first.\n",
|
||||
log_id(module), log_id(mem->memid));
|
||||
module, mem->memid.unescape());
|
||||
}
|
||||
|
||||
int data_sid = get_bv_sid(mem->width);
|
||||
|
|
@ -871,7 +871,7 @@ struct BtorWorker
|
|||
if (mem->memid[0] == '$')
|
||||
btorf("%d state %d\n", nid, sid);
|
||||
else
|
||||
btorf("%d state %d %s\n", nid, sid, log_id(mem->memid));
|
||||
btorf("%d state %d %s\n", nid, sid, mem->memid.unescape());
|
||||
|
||||
ywmap_state(cell);
|
||||
|
||||
|
|
@ -948,21 +948,20 @@ struct BtorWorker
|
|||
|
||||
if (cell->type.in(ID($dffe), ID($sdff), ID($sdffe), ID($sdffce)) || cell->type.str().substr(0, 6) == "$_SDFF" || (cell->type.str().substr(0, 6) == "$_DFFE" && cell->type.str().size() == 10)) {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `dffunmap` before `write_btor`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
if (cell->type.in(ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($dffsr), ID($dffsre)) || cell->type.str().substr(0, 5) == "$_DFF" || cell->type.str().substr(0, 7) == "$_ALDFF") {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `async2sync; dffunmap` or `clk2fflogic` before `write_btor`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
if (cell->type.in(ID($sr), ID($dlatch), ID($adlatch), ID($dlatchsr)) || cell->type.str().substr(0, 8) == "$_DLATCH" || cell->type.str().substr(0, 5) == "$_SR_") {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `clk2fflogic` before `write_btor`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
log_error("Unsupported cell type %s for cell %s.%s.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
|
||||
cell->type.unescape(), module, cell);
|
||||
okay:
|
||||
btorf_pop(log_id(cell));
|
||||
btorf_pop(cell->name.unescape());
|
||||
cell_recursion_guard.erase(cell);
|
||||
}
|
||||
|
||||
|
|
@ -1167,7 +1166,7 @@ struct BtorWorker
|
|||
f(f), sigmap(module), module(module), verbose(verbose), single_bad(single_bad), cover_mode(cover_mode), print_internal_names(print_internal_names), info_filename(info_filename)
|
||||
{
|
||||
if (!info_filename.empty())
|
||||
infof("name %s\n", log_id(module));
|
||||
infof("name %s\n", module);
|
||||
|
||||
if (!ywmap_filename.empty())
|
||||
ywmap_json.write_to_file(ywmap_filename);
|
||||
|
|
@ -1257,19 +1256,19 @@ struct BtorWorker
|
|||
if (!wire->port_id || !wire->port_output)
|
||||
continue;
|
||||
|
||||
btorf_push(stringf("output %s", log_id(wire)));
|
||||
btorf_push(stringf("output %s", wire));
|
||||
|
||||
int nid = get_sig_nid(wire);
|
||||
btorf("%d output %d%s\n", next_nid++, nid, getinfo(wire));
|
||||
|
||||
btorf_pop(stringf("output %s", log_id(wire)));
|
||||
btorf_pop(stringf("output %s", wire));
|
||||
}
|
||||
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
if (cell->type == ID($assume))
|
||||
{
|
||||
btorf_push(log_id(cell));
|
||||
btorf_push(cell->name.unescape());
|
||||
|
||||
int sid = get_bv_sid(1);
|
||||
int nid_a = get_sig_nid(cell->getPort(ID::A));
|
||||
|
|
@ -1284,12 +1283,12 @@ struct BtorWorker
|
|||
|
||||
if (ywmap_json.active()) ywmap_assumes.emplace_back(cell);
|
||||
|
||||
btorf_pop(log_id(cell));
|
||||
btorf_pop(cell->name.unescape());
|
||||
}
|
||||
|
||||
if (cell->type == ID($assert))
|
||||
{
|
||||
btorf_push(log_id(cell));
|
||||
btorf_push(cell->name.unescape());
|
||||
|
||||
int sid = get_bv_sid(1);
|
||||
int nid_a = get_sig_nid(cell->getPort(ID::A));
|
||||
|
|
@ -1313,12 +1312,12 @@ struct BtorWorker
|
|||
}
|
||||
}
|
||||
|
||||
btorf_pop(log_id(cell));
|
||||
btorf_pop(cell->name.unescape());
|
||||
}
|
||||
|
||||
if (cell->type == ID($cover) && cover_mode)
|
||||
{
|
||||
btorf_push(log_id(cell));
|
||||
btorf_push(cell->name.unescape());
|
||||
|
||||
int sid = get_bv_sid(1);
|
||||
int nid_a = get_sig_nid(cell->getPort(ID::A));
|
||||
|
|
@ -1334,7 +1333,7 @@ struct BtorWorker
|
|||
btorf("%d bad %d%s\n", nid, nid_en_and_a, getinfo(cell, true));
|
||||
}
|
||||
|
||||
btorf_pop(log_id(cell));
|
||||
btorf_pop(cell->name.unescape());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1343,7 +1342,7 @@ struct BtorWorker
|
|||
if (wire->port_id || wire->name[0] == '$')
|
||||
continue;
|
||||
|
||||
btorf_push(stringf("wire %s", log_id(wire)));
|
||||
btorf_push(stringf("wire %s", wire));
|
||||
|
||||
int sid = get_bv_sid(GetSize(wire));
|
||||
int nid = get_sig_nid(sigmap(wire));
|
||||
|
|
@ -1356,7 +1355,7 @@ struct BtorWorker
|
|||
if (info_clocks.count(nid))
|
||||
info_clocks[this_nid] |= info_clocks[nid];
|
||||
|
||||
btorf_pop(stringf("wire %s", log_id(wire)));
|
||||
btorf_pop(stringf("wire %s", wire));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1370,14 +1369,14 @@ struct BtorWorker
|
|||
int nid = it.first;
|
||||
Cell *cell = it.second;
|
||||
|
||||
btorf_push(stringf("next %s", log_id(cell)));
|
||||
btorf_push(stringf("next %s", cell));
|
||||
|
||||
SigSpec sig = sigmap(cell->getPort(ID::D));
|
||||
int nid_q = get_sig_nid(sig);
|
||||
int sid = get_bv_sid(GetSize(sig));
|
||||
btorf("%d next %d %d %d%s\n", next_nid++, sid, nid, nid_q, getinfo(cell));
|
||||
|
||||
btorf_pop(stringf("next %s", log_id(cell)));
|
||||
btorf_pop(stringf("next %s", cell));
|
||||
}
|
||||
|
||||
vector<pair<int, Mem*>> mtodo;
|
||||
|
|
@ -1388,7 +1387,7 @@ struct BtorWorker
|
|||
int nid = it.first;
|
||||
Mem *mem = it.second;
|
||||
|
||||
btorf_push(stringf("next %s", log_id(mem->memid)));
|
||||
btorf_push(stringf("next %s", mem->memid.unescape()));
|
||||
|
||||
int abits = ceil_log2(mem->size);
|
||||
|
||||
|
|
@ -1436,7 +1435,7 @@ struct BtorWorker
|
|||
int nid2 = next_nid++;
|
||||
btorf("%d next %d %d %d%s\n", nid2, sid, nid, nid_head, (mem->cell ? getinfo(mem->cell) : getinfo(mem->mem)));
|
||||
|
||||
btorf_pop(stringf("next %s", log_id(mem->memid)));
|
||||
btorf_pop(stringf("next %s", mem->memid.unescape()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1630,7 +1629,7 @@ struct BtorBackend : public Backend {
|
|||
log_cmd_error("No top module found.\n");
|
||||
|
||||
*f << stringf("; BTOR description generated by %s for module %s.\n",
|
||||
yosys_maybe_version(), log_id(topmod));
|
||||
yosys_maybe_version(), topmod);
|
||||
|
||||
BtorWorker(*f, topmod, verbose, single_bad, cover_mode, print_internal_names, info_filename, ywmap_filename);
|
||||
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ CxxrtlPortType cxxrtl_port_type(RTLIL::Module *module, RTLIL::IdString port)
|
|||
bool is_sync = output_wire->get_bool_attribute(ID(cxxrtl_sync));
|
||||
if (is_comb && is_sync)
|
||||
log_cmd_error("Port `%s.%s' is marked as both `cxxrtl_comb` and `cxxrtl_sync`.\n",
|
||||
log_id(module), log_signal(output_wire));
|
||||
module, log_signal(output_wire));
|
||||
else if (is_comb)
|
||||
return CxxrtlPortType::COMB;
|
||||
else if (is_sync)
|
||||
|
|
@ -756,7 +756,7 @@ struct CxxrtlWorker {
|
|||
// 1b. Generated identifiers for internal names (beginning with `$`) start with `i_`.
|
||||
// 2. An underscore is escaped with another underscore, i.e. `__`.
|
||||
// 3. Any other non-alnum character is escaped with underscores around its lowercase hex code, e.g. `@` as `_40_`.
|
||||
std::string mangle_name(const RTLIL::IdString &name)
|
||||
std::string mangle_name(RTLIL::IdString name)
|
||||
{
|
||||
std::string mangled;
|
||||
bool first = true;
|
||||
|
|
@ -786,7 +786,7 @@ struct CxxrtlWorker {
|
|||
return mangled;
|
||||
}
|
||||
|
||||
std::string mangle_module_name(const RTLIL::IdString &name, bool is_blackbox = false)
|
||||
std::string mangle_module_name(RTLIL::IdString name, bool is_blackbox = false)
|
||||
{
|
||||
// Class namespace.
|
||||
if (is_blackbox)
|
||||
|
|
@ -794,19 +794,19 @@ struct CxxrtlWorker {
|
|||
return mangle_name(name);
|
||||
}
|
||||
|
||||
std::string mangle_memory_name(const RTLIL::IdString &name)
|
||||
std::string mangle_memory_name(RTLIL::IdString name)
|
||||
{
|
||||
// Class member namespace.
|
||||
return "memory_" + mangle_name(name);
|
||||
}
|
||||
|
||||
std::string mangle_cell_name(const RTLIL::IdString &name)
|
||||
std::string mangle_cell_name(RTLIL::IdString name)
|
||||
{
|
||||
// Class member namespace.
|
||||
return "cell_" + mangle_name(name);
|
||||
}
|
||||
|
||||
std::string mangle_wire_name(const RTLIL::IdString &name)
|
||||
std::string mangle_wire_name(RTLIL::IdString name)
|
||||
{
|
||||
// Class member namespace.
|
||||
return mangle_name(name);
|
||||
|
|
@ -851,7 +851,7 @@ struct CxxrtlWorker {
|
|||
return {};
|
||||
|
||||
if (!(module->attributes.at(ID(cxxrtl_template)).flags & RTLIL::CONST_FLAG_STRING))
|
||||
log_cmd_error("Attribute `cxxrtl_template' of module `%s' is not a string.\n", log_id(module));
|
||||
log_cmd_error("Attribute `cxxrtl_template' of module `%s' is not a string.\n", module);
|
||||
|
||||
std::vector<std::string> param_names = split_by(module->get_string_attribute(ID(cxxrtl_template)), " \t");
|
||||
for (const auto ¶m_name : param_names) {
|
||||
|
|
@ -861,7 +861,7 @@ struct CxxrtlWorker {
|
|||
if (!isupper(param_name[0]))
|
||||
log_cmd_error("Attribute `cxxrtl_template' of module `%s' includes a parameter `%s', "
|
||||
"which does not start with an uppercase letter.\n",
|
||||
log_id(module), param_name.c_str());
|
||||
module, param_name.c_str());
|
||||
}
|
||||
return param_names;
|
||||
}
|
||||
|
|
@ -907,12 +907,12 @@ struct CxxrtlWorker {
|
|||
RTLIL::IdString id_param_name = '\\' + param_name;
|
||||
if (!cell->hasParam(id_param_name))
|
||||
log_cmd_error("Cell `%s.%s' does not have a parameter `%s', which is required by the templated module `%s'.\n",
|
||||
log_id(cell->module), log_id(cell), param_name.c_str(), log_id(cell_module));
|
||||
cell->module, cell, param_name.c_str(), cell_module);
|
||||
RTLIL::Const param_value = cell->getParam(id_param_name);
|
||||
if (((param_value.flags & ~RTLIL::CONST_FLAG_SIGNED) != 0) || param_value.as_int() < 0)
|
||||
log_cmd_error("Parameter `%s' of cell `%s.%s', which is required by the templated module `%s', "
|
||||
"is not a positive integer.\n",
|
||||
param_name.c_str(), log_id(cell->module), log_id(cell), log_id(cell_module));
|
||||
param_name.c_str(), cell->module, cell, cell_module);
|
||||
params += std::to_string(cell->getParam(id_param_name).as_int());
|
||||
}
|
||||
params += ">";
|
||||
|
|
@ -2576,7 +2576,7 @@ struct CxxrtlWorker {
|
|||
}
|
||||
dec_indent();
|
||||
|
||||
log_debug("Debug information statistics for module `%s':\n", log_id(module));
|
||||
log_debug("Debug information statistics for module `%s':\n", module);
|
||||
log_debug(" Scopes: %zu", count_scopes);
|
||||
log_debug(" Public wires: %zu, of which:\n", count_public_wires);
|
||||
log_debug(" Member wires: %zu, of which:\n", count_member_wires);
|
||||
|
|
@ -2776,7 +2776,8 @@ struct CxxrtlWorker {
|
|||
{
|
||||
RTLIL::Module *top_module = nullptr;
|
||||
std::vector<RTLIL::Module*> modules;
|
||||
TopoSort<RTLIL::Module*> topo_design;
|
||||
using Order = IdString::compare_ptr_by_name<RTLIL::NamedObject>;
|
||||
TopoSort<RTLIL::Module*, Order> topo_design;
|
||||
for (auto module : design->modules()) {
|
||||
if (!design->selected_module(module))
|
||||
continue;
|
||||
|
|
@ -2939,7 +2940,7 @@ struct CxxrtlWorker {
|
|||
RTLIL::Const edge_attr = wire->attributes[ID(cxxrtl_edge)];
|
||||
if (!(edge_attr.flags & RTLIL::CONST_FLAG_STRING) || (int)edge_attr.decode_string().size() != GetSize(wire))
|
||||
log_cmd_error("Attribute `cxxrtl_edge' of port `%s.%s' is not a string with one character per bit.\n",
|
||||
log_id(module), log_signal(wire));
|
||||
module, log_signal(wire));
|
||||
|
||||
std::string edges = wire->get_string_attribute(ID(cxxrtl_edge));
|
||||
for (int i = 0; i < GetSize(wire); i++) {
|
||||
|
|
@ -2952,7 +2953,7 @@ struct CxxrtlWorker {
|
|||
default:
|
||||
log_cmd_error("Attribute `cxxrtl_edge' of port `%s.%s' contains specifiers "
|
||||
"other than '-', 'p', 'n', or 'a'.\n",
|
||||
log_id(module), log_signal(wire));
|
||||
module, log_signal(wire));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2977,7 +2978,7 @@ struct CxxrtlWorker {
|
|||
|
||||
for (auto cell : module->cells()) {
|
||||
if (!cell->known())
|
||||
log_cmd_error("Unknown cell `%s'.\n", log_id(cell->type));
|
||||
log_cmd_error("Unknown cell `%s'.\n", cell->type.unescape());
|
||||
|
||||
if (cell->is_mem_cell())
|
||||
continue;
|
||||
|
|
@ -2986,7 +2987,7 @@ struct CxxrtlWorker {
|
|||
if (cell_module &&
|
||||
cell_module->get_blackbox_attribute() &&
|
||||
!cell_module->get_bool_attribute(ID(cxxrtl_blackbox)))
|
||||
log_cmd_error("External blackbox cell `%s' is not marked as a CXXRTL blackbox.\n", log_id(cell->type));
|
||||
log_cmd_error("External blackbox cell `%s' is not marked as a CXXRTL blackbox.\n", cell->type.unescape());
|
||||
|
||||
if (cell_module &&
|
||||
cell_module->get_bool_attribute(ID(cxxrtl_blackbox)) &&
|
||||
|
|
@ -3115,9 +3116,9 @@ struct CxxrtlWorker {
|
|||
}
|
||||
if (!feedback_wires.empty()) {
|
||||
has_feedback_arcs = true;
|
||||
log("Module `%s' contains feedback arcs through wires:\n", log_id(module));
|
||||
log("Module `%s' contains feedback arcs through wires:\n", module);
|
||||
for (auto wire : feedback_wires)
|
||||
log(" %s\n", log_id(wire));
|
||||
log(" %s\n", wire);
|
||||
}
|
||||
|
||||
// Conservatively assign wire types. Assignment of types BUFFERED and MEMBER is final, but assignment
|
||||
|
|
@ -3188,7 +3189,7 @@ struct CxxrtlWorker {
|
|||
if (wire->name.isPublic() && !inline_public) continue;
|
||||
if (flow.is_inlinable(wire, live_wires[wire])) {
|
||||
if (flow.wire_comb_defs[wire].size() > 1)
|
||||
log_cmd_error("Wire %s.%s has multiple drivers!\n", log_id(module), log_id(wire));
|
||||
log_cmd_error("Wire %s.%s has multiple drivers!\n", module, wire);
|
||||
log_assert(flow.wire_comb_defs[wire].size() == 1);
|
||||
FlowGraph::Node *node = *flow.wire_comb_defs[wire].begin();
|
||||
switch (node->type) {
|
||||
|
|
@ -3236,9 +3237,9 @@ struct CxxrtlWorker {
|
|||
buffered_comb_wires.insert(wire);
|
||||
if (!buffered_comb_wires.empty()) {
|
||||
has_buffered_comb_wires = true;
|
||||
log("Module `%s' contains buffered combinatorial wires:\n", log_id(module));
|
||||
log("Module `%s' contains buffered combinatorial wires:\n", module);
|
||||
for (auto wire : buffered_comb_wires)
|
||||
log(" %s\n", log_id(wire));
|
||||
log(" %s\n", wire);
|
||||
}
|
||||
|
||||
// Record whether eval() requires only one delta cycle in this module.
|
||||
|
|
@ -3419,7 +3420,7 @@ struct CxxrtlWorker {
|
|||
|
||||
if (!design->selected_whole_module(module))
|
||||
if (design->selected_module(module))
|
||||
log_cmd_error("Can't handle partially selected module `%s'!\n", id2cstr(module->name));
|
||||
log_cmd_error("Can't handle partially selected module `%s'!\n", module);
|
||||
if (!design->selected_module(module))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -614,7 +614,7 @@ struct value : public expr_base<value<Bits>> {
|
|||
int64_t divisor_shift = divisor.ctlz() - dividend.ctlz();
|
||||
assert(divisor_shift >= 0);
|
||||
divisor = divisor.shl(value<Bits>{(chunk::type) divisor_shift});
|
||||
for (size_t step = 0; step <= divisor_shift; step++) {
|
||||
for (size_t step = 0; step <= (uint64_t) divisor_shift; step++) {
|
||||
quotient = quotient.shl(value<Bits>{1u});
|
||||
if (!dividend.ucmp(divisor)) {
|
||||
dividend = dividend.sub(divisor);
|
||||
|
|
@ -1119,7 +1119,7 @@ struct fmt_part {
|
|||
|
||||
case STRING: {
|
||||
buf.reserve(Bits/8);
|
||||
for (int i = 0; i < Bits; i += 8) {
|
||||
for (size_t i = 0; i < Bits; i += 8) {
|
||||
char ch = 0;
|
||||
for (int j = 0; j < 8 && i + j < int(Bits); j++)
|
||||
if (val.bit(i + j))
|
||||
|
|
|
|||
|
|
@ -23,16 +23,18 @@
|
|||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true)
|
||||
#define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(RTLIL::unescape_id(_id), true, _ren, _bl, _br)
|
||||
#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false)
|
||||
#define EDIF_DEF(_id) edif_names(_id.unescape(), true)
|
||||
#define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(_id.unescape(), true, _ren, _bl, _br)
|
||||
#define EDIF_REF(_id) edif_names(_id.unescape(), false)
|
||||
#define EDIF_DEF_STR(_id) edif_names(RTLIL::unescape_id(_id), true)
|
||||
#define EDIF_REF_STR(_id) edif_names(RTLIL::unescape_id(_id), false)
|
||||
|
||||
struct EdifNames
|
||||
{
|
||||
|
|
@ -138,7 +140,7 @@ struct EdifBackend : public Backend {
|
|||
bool lsbidx = false;
|
||||
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
|
||||
bool nogndvcc = false, gndvccy = false, keepmode = false;
|
||||
CellTypes ct(design);
|
||||
NewCellTypes ct(design);
|
||||
EdifNames edif_names;
|
||||
|
||||
size_t argidx;
|
||||
|
|
@ -207,9 +209,9 @@ struct EdifBackend : public Backend {
|
|||
top_module_name = module->name.str();
|
||||
|
||||
if (module->processes.size() != 0)
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", log_id(module->name));
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", module->name.unescape());
|
||||
if (module->memories.size() != 0)
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", log_id(module->name));
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", module->name.unescape());
|
||||
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
|
|
@ -227,7 +229,7 @@ struct EdifBackend : public Backend {
|
|||
if (top_module_name.empty())
|
||||
log_error("No module found in design!\n");
|
||||
|
||||
*f << stringf("(edif %s\n", EDIF_DEF(top_module_name));
|
||||
*f << stringf("(edif %s\n", EDIF_DEF_STR(top_module_name));
|
||||
*f << stringf(" (edifVersion 2 0 0)\n");
|
||||
*f << stringf(" (edifLevel 0)\n");
|
||||
*f << stringf(" (keywordMap (keywordLevel 0))\n");
|
||||
|
|
@ -317,12 +319,12 @@ struct EdifBackend : public Backend {
|
|||
for (auto &dep : it.second)
|
||||
if (module_deps.count(dep) > 0)
|
||||
goto not_ready_yet;
|
||||
// log("Next in topological sort: %s\n", log_id(it.first->name));
|
||||
// log("Next in topological sort: %s\n", it.first->name.unescape());
|
||||
sorted_modules.push_back(it.first);
|
||||
not_ready_yet:;
|
||||
}
|
||||
if (sorted_modules_idx == sorted_modules.size())
|
||||
log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", log_id(module_deps.begin()->first->name));
|
||||
log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", module_deps.begin()->first->name.unescape());
|
||||
while (sorted_modules_idx < sorted_modules.size())
|
||||
module_deps.erase(sorted_modules.at(sorted_modules_idx++));
|
||||
}
|
||||
|
|
@ -486,7 +488,7 @@ struct EdifBackend : public Backend {
|
|||
for (int i = 0; i < GetSize(sig); i++)
|
||||
if (sig[i].wire == NULL && sig[i] != RTLIL::State::S0 && sig[i] != RTLIL::State::S1)
|
||||
log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n",
|
||||
i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i]));
|
||||
i, module, cell, p.first.unescape(), log_signal(sig[i]));
|
||||
else {
|
||||
int member_idx = lsbidx ? i : GetSize(sig)-i-1;
|
||||
auto m = design->module(cell->type);
|
||||
|
|
@ -534,7 +536,7 @@ struct EdifBackend : public Backend {
|
|||
if (netname[i] == ' ' || netname[i] == '\\')
|
||||
netname.erase(netname.begin() + i--);
|
||||
}
|
||||
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
|
||||
*f << stringf(" (net %s (joined\n", EDIF_DEF_STR(netname));
|
||||
for (auto &ref : it.second)
|
||||
*f << stringf(" %s\n", ref.first);
|
||||
if (sig.wire == NULL) {
|
||||
|
|
@ -572,7 +574,7 @@ struct EdifBackend : public Backend {
|
|||
|
||||
if (keepmode)
|
||||
{
|
||||
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
|
||||
*f << stringf(" (net %s (joined\n", EDIF_DEF_STR(netname));
|
||||
|
||||
auto &refs = net_join_db.at(mapped_sig);
|
||||
for (auto &ref : refs)
|
||||
|
|
@ -588,7 +590,7 @@ struct EdifBackend : public Backend {
|
|||
}
|
||||
else
|
||||
{
|
||||
log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF(netname));
|
||||
log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF_STR(netname));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -599,8 +601,8 @@ struct EdifBackend : public Backend {
|
|||
}
|
||||
*f << stringf(" )\n");
|
||||
|
||||
*f << stringf(" (design %s\n", EDIF_DEF(top_module_name));
|
||||
*f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name));
|
||||
*f << stringf(" (design %s\n", EDIF_DEF_STR(top_module_name));
|
||||
*f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF_STR(top_module_name));
|
||||
*f << stringf(" )\n");
|
||||
|
||||
*f << stringf(")\n");
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ const char *make_id(IdString id)
|
|||
if (namecache.count(id) != 0)
|
||||
return namecache.at(id).c_str();
|
||||
|
||||
string new_id = log_id(id);
|
||||
string new_id = id.unescape();
|
||||
|
||||
for (int i = 0; i < GetSize(new_id); i++)
|
||||
{
|
||||
|
|
@ -263,7 +263,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
|
|||
|
||||
if (wire->port_input && wire->port_output)
|
||||
{
|
||||
log_error("Module port %s.%s is inout!\n", log_id(mod_instance), log_id(wire));
|
||||
log_error("Module port %s.%s is inout!\n", mod_instance, wire);
|
||||
}
|
||||
|
||||
const std::string portDecl = stringf("%s%s %s: UInt<%d> %s\n",
|
||||
|
|
@ -559,12 +559,12 @@ struct FirrtlWorker
|
|||
if (wire->attributes.count(ID::init)) {
|
||||
log_warning("Initial value (%s) for (%s.%s) not supported\n",
|
||||
wire->attributes.at(ID::init).as_string().c_str(),
|
||||
log_id(module), log_id(wire));
|
||||
module, wire);
|
||||
}
|
||||
if (wire->port_id)
|
||||
{
|
||||
if (wire->port_input && wire->port_output)
|
||||
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
|
||||
log_error("Module port %s.%s is inout!\n", module, wire);
|
||||
port_decls.push_back(stringf("%s%s %s: UInt<%d> %s\n", indent, wire->port_input ? "input" : "output",
|
||||
wireName, wire->width, wireFileinfo.c_str()));
|
||||
}
|
||||
|
|
@ -833,7 +833,7 @@ struct FirrtlWorker
|
|||
primop = "shl";
|
||||
int shiftAmount = b_sig.as_int();
|
||||
if (shiftAmount < 0) {
|
||||
log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell));
|
||||
log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, module, cell);
|
||||
}
|
||||
b_expr = std::to_string(shiftAmount);
|
||||
firrtl_width = a_width + shiftAmount;
|
||||
|
|
@ -844,7 +844,7 @@ struct FirrtlWorker
|
|||
firrtl_width = a_width + (1 << b_width) - 1;
|
||||
}
|
||||
} else {
|
||||
log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell));
|
||||
log_error("Non power 2: %s.%s\n", module, cell);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -905,7 +905,7 @@ struct FirrtlWorker
|
|||
{
|
||||
bool clkpol = cell->parameters.at(ID::CLK_POLARITY).as_bool();
|
||||
if (clkpol == false)
|
||||
log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell));
|
||||
log_error("Negative edge clock on FF %s.%s.\n", module, cell);
|
||||
|
||||
int width = cell->parameters.at(ID::WIDTH).as_int();
|
||||
string expr = make_expr(cell->getPort(ID::D));
|
||||
|
|
@ -983,7 +983,7 @@ struct FirrtlWorker
|
|||
|
||||
if (cell->type == ID($scopeinfo))
|
||||
continue;
|
||||
log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
|
||||
log_error("Cell type not supported: %s (%s.%s)\n", cell->type.unescape(), module, cell);
|
||||
}
|
||||
|
||||
for (auto &mem : memories) {
|
||||
|
|
@ -991,10 +991,10 @@ struct FirrtlWorker
|
|||
|
||||
Const init_data = mem.get_init_data();
|
||||
if (!init_data.is_fully_undef())
|
||||
log_error("Memory with initialization data: %s.%s\n", log_id(module), log_id(mem.memid));
|
||||
log_error("Memory with initialization data: %s.%s\n", module, mem.memid.unescape());
|
||||
|
||||
if (mem.start_offset != 0)
|
||||
log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(mem.memid));
|
||||
log_error("Memory with nonzero offset: %s.%s\n", module, mem.memid.unescape());
|
||||
|
||||
for (int i = 0; i < GetSize(mem.rd_ports); i++)
|
||||
{
|
||||
|
|
@ -1002,7 +1002,7 @@ struct FirrtlWorker
|
|||
string port_name(stringf("%s.r%d", mem_id, i));
|
||||
|
||||
if (port.clk_enable)
|
||||
log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid));
|
||||
log_error("Clocked read port %d on memory %s.%s.\n", i, module, mem.memid.unescape());
|
||||
|
||||
std::ostringstream rpe;
|
||||
|
||||
|
|
@ -1023,12 +1023,12 @@ struct FirrtlWorker
|
|||
string port_name(stringf("%s.w%d", mem_id, i));
|
||||
|
||||
if (!port.clk_enable)
|
||||
log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid));
|
||||
log_error("Unclocked write port %d on memory %s.%s.\n", i, module, mem.memid.unescape());
|
||||
if (!port.clk_polarity)
|
||||
log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid));
|
||||
log_error("Negedge write port %d on memory %s.%s.\n", i, module, mem.memid.unescape());
|
||||
for (int i = 1; i < GetSize(port.en); i++)
|
||||
if (port.en[0] != port.en[i])
|
||||
log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid));
|
||||
log_error("Complex write enable on port %d on memory %s.%s.\n", i, module, mem.memid.unescape());
|
||||
|
||||
std::ostringstream wpe;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ struct CxxStruct {
|
|||
}
|
||||
f.print("\n\t\ttemplate <typename T> void visit(T &&fn) {{\n");
|
||||
for (auto p : types) {
|
||||
f.print("\t\t\tfn(\"{}\", {});\n", RTLIL::unescape_id(p.first), scope(p.first, p.first));
|
||||
f.print("\t\t\tfn(\"{}\", {});\n", p.first.unescape(), scope(p.first, p.first));
|
||||
}
|
||||
f.print("\t\t}}\n");
|
||||
f.print("\t}};\n\n");
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public:
|
|||
SmtStruct(std::string name, SmtScope &scope) : scope(scope), name(name) {}
|
||||
void insert(IdString field_name, SmtSort sort) {
|
||||
field_names(field_name);
|
||||
auto accessor = scope.unique_name("\\" + name + "_" + RTLIL::unescape_id(field_name));
|
||||
auto accessor = scope.unique_name("\\" + name + "_" + field_name.unescape());
|
||||
fields.emplace_back(Field{sort, accessor});
|
||||
}
|
||||
void write_definition(SExprWriter &w) {
|
||||
|
|
@ -99,7 +99,7 @@ public:
|
|||
w.open(list(name));
|
||||
for(auto field_name : field_names) {
|
||||
w << fn(field_name);
|
||||
w.comment(RTLIL::unescape_id(field_name), true);
|
||||
w.comment(field_name.unescape(), true);
|
||||
}
|
||||
w.close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public:
|
|||
w.open(list(name));
|
||||
for(auto field_name : field_names) {
|
||||
w << fn(field_name);
|
||||
w.comment(RTLIL::unescape_id(field_name), true);
|
||||
w.comment(field_name.unescape(), true);
|
||||
}
|
||||
w.close();
|
||||
}
|
||||
|
|
@ -188,20 +188,27 @@ struct SmtrModule {
|
|||
Functional::IR ir;
|
||||
SmtrScope scope;
|
||||
std::string name;
|
||||
bool use_assoc_list_helpers;
|
||||
std::optional<std::string> input_helper_name;
|
||||
std::optional<std::string> output_helper_name;
|
||||
|
||||
SmtrStruct input_struct;
|
||||
SmtrStruct output_struct;
|
||||
SmtrStruct state_struct;
|
||||
|
||||
SmtrModule(Module *module)
|
||||
: ir(Functional::IR::from_module(module))
|
||||
, scope()
|
||||
, name(scope.unique_name(module->name))
|
||||
, input_struct(scope.unique_name(module->name.str() + "_Inputs"), scope)
|
||||
, output_struct(scope.unique_name(module->name.str() + "_Outputs"), scope)
|
||||
, state_struct(scope.unique_name(module->name.str() + "_State"), scope)
|
||||
SmtrModule(Module *module, bool assoc_list_helpers)
|
||||
: ir(Functional::IR::from_module(module)), scope(), name(scope.unique_name(module->name)), use_assoc_list_helpers(assoc_list_helpers),
|
||||
input_struct(scope.unique_name(module->name.str() + "_Inputs"), scope),
|
||||
output_struct(scope.unique_name(module->name.str() + "_Outputs"), scope),
|
||||
state_struct(scope.unique_name(module->name.str() + "_State"), scope)
|
||||
{
|
||||
scope.reserve(name + "_initial");
|
||||
if (assoc_list_helpers) {
|
||||
input_helper_name = scope.unique_name(module->name.str() + "_inputs_helper");
|
||||
scope.reserve(*input_helper_name);
|
||||
output_helper_name = scope.unique_name(module->name.str() + "_outputs_helper");
|
||||
scope.reserve(*output_helper_name);
|
||||
}
|
||||
for (auto input : ir.inputs())
|
||||
input_struct.insert(input->name, input->sort);
|
||||
for (auto output : ir.outputs())
|
||||
|
|
@ -257,6 +264,45 @@ struct SmtrModule {
|
|||
w.pop();
|
||||
}
|
||||
|
||||
void write_assoc_list_helpers(SExprWriter &w)
|
||||
{
|
||||
log_assert(output_helper_name && input_helper_name);
|
||||
|
||||
// Input struct keyword-based constructor.
|
||||
w.push();
|
||||
w.open(list("define"));
|
||||
const auto inputs_name = "inputs";
|
||||
w.open(list(*input_helper_name, inputs_name));
|
||||
w.close();
|
||||
w.open(list(input_struct.name));
|
||||
for (auto input : ir.inputs()) {
|
||||
w.push();
|
||||
w.open(list("let"));
|
||||
w.push();
|
||||
w.open(list());
|
||||
w.open(list("assoc-result"));
|
||||
w << list("assoc", "\"" + input->name.unescape() + "\"", inputs_name);
|
||||
w.pop();
|
||||
w.open(list("if", "assoc-result"));
|
||||
w << list("cdr", "assoc-result");
|
||||
w.open(list("begin"));
|
||||
w << list("fprintf", list("current-error-port"), "\"%s not found in inputs\"");
|
||||
w << "'not-found";
|
||||
w.pop();
|
||||
}
|
||||
w.pop();
|
||||
// Output struct keyword-based destructuring
|
||||
w.push();
|
||||
w.open(list("define"));
|
||||
const auto outputs_name = "outputs";
|
||||
w << list(*output_helper_name, outputs_name);
|
||||
w.open(list("list"));
|
||||
for (auto output : ir.outputs()) {
|
||||
w << list("cons", "\"" + output->name.unescape() + "\"", output_struct.access("outputs", output->name));
|
||||
}
|
||||
w.pop();
|
||||
}
|
||||
|
||||
void write(std::ostream &out)
|
||||
{
|
||||
SExprWriter w(out);
|
||||
|
|
@ -265,6 +311,10 @@ struct SmtrModule {
|
|||
output_struct.write_definition(w);
|
||||
state_struct.write_definition(w);
|
||||
|
||||
if (use_assoc_list_helpers) {
|
||||
write_assoc_list_helpers(w);
|
||||
}
|
||||
|
||||
write_eval(w);
|
||||
write_initial(w);
|
||||
}
|
||||
|
|
@ -282,12 +332,16 @@ struct FunctionalSmtrBackend : public Backend {
|
|||
log("\n");
|
||||
log(" -provides\n");
|
||||
log(" include 'provide' statement(s) for loading output as a module\n");
|
||||
log(" -assoc-list-helpers\n");
|
||||
log(" provide helper functions which convert inputs/outputs from/to association lists\n");
|
||||
log(" \n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
auto provides = false;
|
||||
auto assoc_list_helpers = false;
|
||||
|
||||
log_header(design, "Executing Functional Rosette Backend.\n");
|
||||
|
||||
|
|
@ -296,6 +350,8 @@ struct FunctionalSmtrBackend : public Backend {
|
|||
{
|
||||
if (args[argidx] == "-provides")
|
||||
provides = true;
|
||||
else if (args[argidx] == "-assoc-list-helpers")
|
||||
assoc_list_helpers = true;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
|
@ -307,8 +363,8 @@ struct FunctionalSmtrBackend : public Backend {
|
|||
}
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
log("Processing module `%s`.\n", module->name);
|
||||
SmtrModule smtr(module);
|
||||
log("Processing module `%s`.\n", module->name.c_str());
|
||||
SmtrModule smtr(module, assoc_list_helpers);
|
||||
smtr.write(*f);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,11 +146,11 @@ struct FunctionalTestGeneric : public Pass
|
|||
log("Dumping module `%s'.\n", module->name);
|
||||
auto fir = Functional::IR::from_module(module);
|
||||
for(auto node : fir)
|
||||
std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n";
|
||||
std::cout << node.name().unescape() << " = " << node.to_string([](auto n) { return n.name().unescape(); }) << "\n";
|
||||
for(auto output : fir.all_outputs())
|
||||
std::cout << RTLIL::unescape_id(output->kind) << " " << RTLIL::unescape_id(output->name) << " = " << RTLIL::unescape_id(output->value().name()) << "\n";
|
||||
std::cout << output->kind.unescape() << " " << output->name.unescape() << " = " << output->value().name().unescape() << "\n";
|
||||
for(auto state : fir.all_states())
|
||||
std::cout << RTLIL::unescape_id(state->kind) << " " << RTLIL::unescape_id(state->name) << " = " << RTLIL::unescape_id(state->next_value().name()) << "\n";
|
||||
std::cout << state->kind.unescape() << " " << state->name.unescape() << " = " << state->next_value().name().unescape() << "\n";
|
||||
}
|
||||
}
|
||||
} FunctionalCxxBackend;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ static std::string netname(std::set<std::string> &conntypes_code, std::set<std::
|
|||
return stringf("CONST_%d_0x%x", sig.size(), sig.as_int());
|
||||
}
|
||||
|
||||
return RTLIL::unescape_id(sig.as_wire()->name);
|
||||
return sig.as_wire()->name.unescape();
|
||||
}
|
||||
|
||||
struct IntersynthBackend : public Backend {
|
||||
|
|
@ -117,7 +117,7 @@ struct IntersynthBackend : public Backend {
|
|||
|
||||
std::set<std::string> conntypes_code, celltypes_code;
|
||||
std::string netlists_code;
|
||||
CellTypes ct(design);
|
||||
NewCellTypes ct(design);
|
||||
|
||||
for (auto lib : libs)
|
||||
ct.setup_design(lib);
|
||||
|
|
@ -133,26 +133,26 @@ struct IntersynthBackend : public Backend {
|
|||
|
||||
if (selected && !design->selected_whole_module(module->name)) {
|
||||
if (design->selected_module(module->name))
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", log_id(module->name));
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", module->name.unescape());
|
||||
continue;
|
||||
}
|
||||
|
||||
log("Generating netlist %s.\n", log_id(module->name));
|
||||
log("Generating netlist %s.\n", module->name.unescape());
|
||||
|
||||
if (module->memories.size() != 0 || module->processes.size() != 0)
|
||||
log_error("Can't generate a netlist for a module with unprocessed memories or processes!\n");
|
||||
|
||||
std::set<std::string> constcells_code;
|
||||
netlists_code += stringf("# Netlist of module %s\n", log_id(module->name));
|
||||
netlists_code += stringf("netlist %s\n", log_id(module->name));
|
||||
netlists_code += stringf("# Netlist of module %s\n", module->name.unescape());
|
||||
netlists_code += stringf("netlist %s\n", module->name.unescape());
|
||||
|
||||
// Module Ports: "std::set<string> celltypes_code" prevents duplicate top level ports
|
||||
for (auto wire : module->wires()) {
|
||||
if (wire->port_input || wire->port_output) {
|
||||
celltypes_code.insert(stringf("celltype !%s b%d %sPORT\n" "%s %s %d %s PORT\n",
|
||||
log_id(wire->name), wire->width, wire->port_input ? "*" : "",
|
||||
wire->port_input ? "input" : "output", log_id(wire->name), wire->width, log_id(wire->name)));
|
||||
netlists_code += stringf("node %s %s PORT %s\n", log_id(wire->name), log_id(wire->name),
|
||||
wire->name.unescape(), wire->width, wire->port_input ? "*" : "",
|
||||
wire->port_input ? "input" : "output", wire->name.unescape(), wire->width, wire->name.unescape()));
|
||||
netlists_code += stringf("node %s %s PORT %s\n", wire->name.unescape(), wire->name.unescape(),
|
||||
netname(conntypes_code, celltypes_code, constcells_code, sigmap(wire)).c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -163,26 +163,26 @@ struct IntersynthBackend : public Backend {
|
|||
std::string celltype_code, node_code;
|
||||
|
||||
if (!ct.cell_known(cell->type))
|
||||
log_error("Found unknown cell type %s in module!\n", log_id(cell->type));
|
||||
log_error("Found unknown cell type %s in module!\n", cell->type.unescape());
|
||||
|
||||
celltype_code = stringf("celltype %s", log_id(cell->type));
|
||||
node_code = stringf("node %s %s", log_id(cell->name), log_id(cell->type));
|
||||
celltype_code = stringf("celltype %s", cell->type.unescape());
|
||||
node_code = stringf("node %s %s", cell->name.unescape(), cell->type.unescape());
|
||||
for (auto &port : cell->connections()) {
|
||||
RTLIL::SigSpec sig = sigmap(port.second);
|
||||
if (sig.size() != 0) {
|
||||
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
|
||||
celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", log_id(port.first));
|
||||
node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig));
|
||||
celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", port.first.unescape());
|
||||
node_code += stringf(" %s %s", port.first.unescape(), netname(conntypes_code, celltypes_code, constcells_code, sig));
|
||||
}
|
||||
}
|
||||
for (auto ¶m : cell->parameters) {
|
||||
celltype_code += stringf(" cfg:%d %s", int(param.second.size()), log_id(param.first));
|
||||
celltype_code += stringf(" cfg:%d %s", int(param.second.size()), param.first.unescape());
|
||||
if (param.second.size() != 32) {
|
||||
node_code += stringf(" %s '", log_id(param.first));
|
||||
node_code += stringf(" %s '", param.first.unescape());
|
||||
for (int i = param.second.size()-1; i >= 0; i--)
|
||||
node_code += param.second[i] == State::S1 ? "1" : "0";
|
||||
} else
|
||||
node_code += stringf(" %s 0x%x", log_id(param.first), param.second.as_int());
|
||||
node_code += stringf(" %s 0x%x", param.first.unescape(), param.second.as_int());
|
||||
}
|
||||
|
||||
celltypes_code.insert(celltype_code + "\n");
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ struct JnyWriter
|
|||
{
|
||||
_cells.clear();
|
||||
for (auto cell : mod->cells()) {
|
||||
const auto cell_type = escape_string(RTLIL::unescape_id(cell->type));
|
||||
const auto cell_type = escape_string(cell->type.unescape());
|
||||
|
||||
if (_cells.find(cell_type) == _cells.end())
|
||||
_cells.emplace(cell_type, std::vector<Cell*>());
|
||||
|
|
@ -214,7 +214,7 @@ struct JnyWriter
|
|||
void write_cell_conn(const std::pair<RTLIL::IdString, RTLIL::SigSpec>& sig, uint16_t indent_level = 0) {
|
||||
const auto _indent = gen_indent(indent_level);
|
||||
f << _indent << " {\n";
|
||||
f << _indent << " \"name\": \"" << escape_string(RTLIL::unescape_id(sig.first)) << "\",\n";
|
||||
f << _indent << " \"name\": \"" << escape_string(sig.first.unescape()) << "\",\n";
|
||||
f << _indent << " \"signals\": [\n";
|
||||
|
||||
write_sigspec(sig.second, indent_level + 2);
|
||||
|
|
@ -232,7 +232,7 @@ struct JnyWriter
|
|||
const auto _indent = gen_indent(indent_level);
|
||||
|
||||
f << _indent << "{\n";
|
||||
f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(RTLIL::unescape_id(mod->name)));
|
||||
f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(mod->name.unescape()));
|
||||
f << _indent << " \"cell_sorts\": [\n";
|
||||
|
||||
bool first_sort{true};
|
||||
|
|
@ -280,7 +280,7 @@ struct JnyWriter
|
|||
f << ",\n";
|
||||
|
||||
f << _indent << " {\n";
|
||||
f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(RTLIL::unescape_id(con.first)));
|
||||
f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(con.first.unescape()));
|
||||
f << _indent << " \"direction\": \"";
|
||||
if (port_cell->input(con.first))
|
||||
f << "i";
|
||||
|
|
@ -351,10 +351,10 @@ struct JnyWriter
|
|||
f << stringf(",\n");
|
||||
const auto param_val = param.second;
|
||||
if (!param_val.empty()) {
|
||||
f << stringf(" %s\"%s\": ", _indent, escape_string(RTLIL::unescape_id(param.first)));
|
||||
f << stringf(" %s\"%s\": ", _indent, escape_string(param.first.unescape()));
|
||||
write_param_val(param_val);
|
||||
} else {
|
||||
f << stringf(" %s\"%s\": true", _indent, escape_string(RTLIL::unescape_id(param.first)));
|
||||
f << stringf(" %s\"%s\": true", _indent, escape_string(param.first.unescape()));
|
||||
}
|
||||
|
||||
first_param = false;
|
||||
|
|
@ -366,7 +366,7 @@ struct JnyWriter
|
|||
log_assert(cell != nullptr);
|
||||
|
||||
f << _indent << " {\n";
|
||||
f << stringf(" %s\"name\": \"%s\"", _indent, escape_string(RTLIL::unescape_id(cell->name)));
|
||||
f << stringf(" %s\"name\": \"%s\"", _indent, escape_string(cell->name.unescape()));
|
||||
|
||||
if (_include_connections) {
|
||||
f << ",\n" << _indent << " \"connections\": [\n";
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ struct JsonWriter
|
|||
|
||||
string get_name(IdString name)
|
||||
{
|
||||
return get_string(RTLIL::unescape_id(name));
|
||||
return get_string(name.unescape());
|
||||
}
|
||||
|
||||
string get_bits(SigSpec sig)
|
||||
|
|
@ -152,7 +152,7 @@ struct JsonWriter
|
|||
sigidcounter = 2;
|
||||
|
||||
if (module->has_processes()) {
|
||||
log_error("Module %s contains processes, which are not supported by JSON backend (run `proc` first).\n", log_id(module));
|
||||
log_error("Module %s contains processes, which are not supported by JSON backend (run `proc` first).\n", module);
|
||||
}
|
||||
|
||||
f << stringf(" %s: {\n", get_name(module->name));
|
||||
|
|
@ -316,13 +316,13 @@ struct JsonWriter
|
|||
f << stringf(" /* %3d */ [ ", node_idx);
|
||||
if (node.portbit >= 0)
|
||||
f << stringf("\"%sport\", \"%s\", %d", node.inverter ? "n" : "",
|
||||
log_id(node.portname), node.portbit);
|
||||
node.portname.unescape(), node.portbit);
|
||||
else if (node.left_parent < 0 && node.right_parent < 0)
|
||||
f << stringf("\"%s\"", node.inverter ? "true" : "false");
|
||||
else
|
||||
f << stringf("\"%s\", %d, %d", node.inverter ? "nand" : "and", node.left_parent, node.right_parent);
|
||||
for (auto &op : node.outports)
|
||||
f << stringf(", \"%s\", %d", log_id(op.first), op.second);
|
||||
f << stringf(", \"%s\", %d", op.first.unescape(), op.second);
|
||||
f << stringf(" ]");
|
||||
node_idx++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,9 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi
|
|||
return;
|
||||
}
|
||||
}
|
||||
f << stringf("%d'", width);
|
||||
if ((data.flags & RTLIL::CONST_FLAG_UNSIZED) == 0) {
|
||||
f << stringf("%d'", width);
|
||||
}
|
||||
if (data.flags & RTLIL::CONST_FLAG_SIGNED) {
|
||||
f << stringf("s");
|
||||
}
|
||||
|
|
@ -173,9 +175,10 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
|
|||
dump_attributes(f, indent, cell);
|
||||
f << stringf("%s" "cell %s %s\n", indent, cell->type, cell->name);
|
||||
for (const auto& [name, param] : reversed(cell->parameters)) {
|
||||
f << stringf("%s parameter%s%s %s ", indent,
|
||||
f << stringf("%s parameter%s%s%s %s ", indent,
|
||||
(param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
|
||||
(param.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
|
||||
(param.flags & RTLIL::CONST_FLAG_UNSIZED) != 0 ? " unsized" : "",
|
||||
name);
|
||||
dump_const(f, param);
|
||||
f << stringf("\n");
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ struct HierDirtyFlags
|
|||
for (Cell *cell : module->cells()) {
|
||||
Module *mod = module->design->module(cell->type);
|
||||
if (mod) children[cell->name] = new HierDirtyFlags(mod, cell->name, this,
|
||||
prefix + cid(cell->name) + ".", log_prefix + "." + prefix + log_id(cell->name));
|
||||
prefix + cid(cell->name) + ".", log_prefix + "." + prefix + cell->name.unescape());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,23 +354,23 @@ struct SimplecWorker
|
|||
struct_declarations.push_back(" // Input Ports");
|
||||
for (Wire *w : mod->wires())
|
||||
if (w->port_input)
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), w));
|
||||
|
||||
struct_declarations.push_back("");
|
||||
struct_declarations.push_back(" // Output Ports");
|
||||
for (Wire *w : mod->wires())
|
||||
if (!w->port_input && w->port_output)
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), w));
|
||||
|
||||
struct_declarations.push_back("");
|
||||
struct_declarations.push_back(" // Internal Wires");
|
||||
for (Wire *w : mod->wires())
|
||||
if (!w->port_input && !w->port_output)
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), w));
|
||||
|
||||
for (Cell *c : mod->cells())
|
||||
if (design->module(c->type))
|
||||
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), log_id(c)));
|
||||
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), c));
|
||||
|
||||
struct_declarations.push_back(stringf("};"));
|
||||
struct_declarations.push_back("#endif");
|
||||
|
|
@ -391,7 +391,7 @@ struct SimplecWorker
|
|||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
|
||||
stringf(" // %s (%s)", cell, cell->type.unescape()));
|
||||
|
||||
work->set_dirty(y);
|
||||
return;
|
||||
|
|
@ -418,7 +418,7 @@ struct SimplecWorker
|
|||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
|
||||
stringf(" // %s (%s)", cell, cell->type.unescape()));
|
||||
|
||||
work->set_dirty(y);
|
||||
return;
|
||||
|
|
@ -441,7 +441,7 @@ struct SimplecWorker
|
|||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
|
||||
stringf(" // %s (%s)", cell, cell->type.unescape()));
|
||||
|
||||
work->set_dirty(y);
|
||||
return;
|
||||
|
|
@ -466,7 +466,7 @@ struct SimplecWorker
|
|||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
|
||||
stringf(" // %s (%s)", cell, cell->type.unescape()));
|
||||
|
||||
work->set_dirty(y);
|
||||
return;
|
||||
|
|
@ -490,13 +490,13 @@ struct SimplecWorker
|
|||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
|
||||
stringf(" // %s (%s)", cell, cell->type.unescape()));
|
||||
|
||||
work->set_dirty(y);
|
||||
return;
|
||||
}
|
||||
|
||||
log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type));
|
||||
log_error("No C model for %s available at the moment (FIXME).\n", cell->type.unescape());
|
||||
}
|
||||
|
||||
void eval_dirty(HierDirtyFlags *work)
|
||||
|
|
@ -517,7 +517,7 @@ struct SimplecWorker
|
|||
if (chunk.wire == nullptr)
|
||||
continue;
|
||||
if (verbose)
|
||||
log(" Propagating %s.%s[%d:%d].\n", work->log_prefix, log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
|
||||
log(" Propagating %s.%s[%d:%d].\n", work->log_prefix, chunk.wire, chunk.offset+chunk.width-1, chunk.offset);
|
||||
funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk)));
|
||||
}
|
||||
|
||||
|
|
@ -539,8 +539,8 @@ struct SimplecWorker
|
|||
work->parent->set_dirty(parent_bit);
|
||||
|
||||
if (verbose)
|
||||
log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix, log_id(bit.wire), bit.offset,
|
||||
work->parent->log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset);
|
||||
log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix, bit.wire, bit.offset,
|
||||
work->parent->log_prefix.c_str(), parent_bit.wire, parent_bit.offset);
|
||||
}
|
||||
|
||||
for (auto &port : bit2cell[work->module][bit])
|
||||
|
|
@ -556,12 +556,12 @@ struct SimplecWorker
|
|||
child->set_dirty(child_bit);
|
||||
|
||||
if (verbose)
|
||||
log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix, log_id(bit.wire), bit.offset,
|
||||
work->log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset);
|
||||
log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix, bit.wire, bit.offset,
|
||||
work->log_prefix.c_str(), std::get<0>(port), child_bit.wire, child_bit.offset);
|
||||
} else {
|
||||
if (verbose)
|
||||
log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix, log_id(std::get<0>(port)),
|
||||
work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
|
||||
log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix, std::get<0>(port),
|
||||
work->log_prefix.c_str(), bit.wire, bit.offset);
|
||||
work->set_dirty(std::get<0>(port));
|
||||
}
|
||||
}
|
||||
|
|
@ -576,10 +576,10 @@ struct SimplecWorker
|
|||
if (cell == nullptr || topoidx.at(cell) < topoidx.at(c))
|
||||
cell = c;
|
||||
|
||||
string hiername = work->log_prefix + "." + log_id(cell);
|
||||
string hiername = work->log_prefix + "." + cell->name.unescape();
|
||||
|
||||
if (verbose)
|
||||
log(" Evaluating %s (%s, best of %d).\n", hiername, log_id(cell->type), GetSize(work->dirty_cells));
|
||||
log(" Evaluating %s (%s, best of %d).\n", hiername, cell->type.unescape(), GetSize(work->dirty_cells));
|
||||
|
||||
if (activated_cells.count(hiername))
|
||||
reactivated_cells.insert(hiername);
|
||||
|
|
@ -618,8 +618,8 @@ struct SimplecWorker
|
|||
|
||||
if (verbose)
|
||||
log(" Propagating alias %s.%s[%d] -> %s.%s[%d].\n",
|
||||
work->log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset,
|
||||
work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
|
||||
work->log_prefix.c_str(), canonical_bit.wire, canonical_bit.offset,
|
||||
work->log_prefix.c_str(), bit.wire, bit.offset);
|
||||
}
|
||||
|
||||
work->sticky_dirty_bits.clear();
|
||||
|
|
@ -716,7 +716,7 @@ struct SimplecWorker
|
|||
{
|
||||
create_module_struct(mod);
|
||||
|
||||
HierDirtyFlags work(mod, IdString(), nullptr, "state->", log_id(mod->name));
|
||||
HierDirtyFlags work(mod, IdString(), nullptr, "state->", mod->name.unescape());
|
||||
|
||||
make_init_func(&work);
|
||||
make_eval_func(&work);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/mem.h"
|
||||
#include "libs/json11/json11.hpp"
|
||||
|
|
@ -32,7 +32,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct Smt2Worker
|
||||
{
|
||||
CellTypes ct;
|
||||
NewCellTypes ct;
|
||||
SigMap sigmap;
|
||||
RTLIL::Module *module;
|
||||
bool bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode;
|
||||
|
|
@ -60,7 +60,7 @@ struct Smt2Worker
|
|||
const char *get_id(IdString n)
|
||||
{
|
||||
if (ids.count(n) == 0) {
|
||||
std::string str = log_id(n);
|
||||
std::string str = n.unescape();
|
||||
for (int i = 0; i < GetSize(str); i++) {
|
||||
if (str[i] == '\\')
|
||||
str[i] = '/';
|
||||
|
|
@ -207,7 +207,7 @@ struct Smt2Worker
|
|||
}
|
||||
else if (is_output || !is_input)
|
||||
log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n",
|
||||
log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type));
|
||||
conn.first.unescape(), module, cell, cell->type.unescape());
|
||||
|
||||
if (cell->type.in(ID($dff), ID($_DFF_P_), ID($_DFF_N_)) && conn.first.in(ID::CLK, ID::C))
|
||||
{
|
||||
|
|
@ -448,7 +448,7 @@ struct Smt2Worker
|
|||
}
|
||||
|
||||
if (verbose)
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell);
|
||||
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
|
||||
get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(bit)));
|
||||
|
|
@ -498,7 +498,7 @@ struct Smt2Worker
|
|||
processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr);
|
||||
|
||||
if (verbose)
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell);
|
||||
|
||||
if (type == 'b') {
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
|
||||
|
|
@ -529,7 +529,7 @@ struct Smt2Worker
|
|||
processed_expr += ch;
|
||||
|
||||
if (verbose)
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell);
|
||||
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
|
||||
get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y)));
|
||||
|
|
@ -541,7 +541,7 @@ struct Smt2Worker
|
|||
{
|
||||
if (verbose)
|
||||
log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new");
|
||||
cell, cell->type.unescape(), exported_cells.count(cell) ? "old" : "new");
|
||||
|
||||
if (recursive_cells.count(cell))
|
||||
log_error("Found logic loop in module %s! See cell %s.\n", get_id(module), get_id(cell));
|
||||
|
|
@ -750,7 +750,7 @@ struct Smt2Worker
|
|||
get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str());
|
||||
|
||||
if (verbose)
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
|
||||
log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell);
|
||||
|
||||
RTLIL::SigSpec sig = sigmap(cell->getPort(ID::Y));
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
|
||||
|
|
@ -786,9 +786,9 @@ struct Smt2Worker
|
|||
has_async_wr = true;
|
||||
}
|
||||
if (has_async_wr && has_sync_wr)
|
||||
log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module));
|
||||
log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", cell, module);
|
||||
|
||||
decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(mem->memid), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync"));
|
||||
decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", mem->memid.unescape(), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync"));
|
||||
decls.push_back(witness_memory(get_id(mem->memid), cell, mem));
|
||||
|
||||
string memstate;
|
||||
|
|
@ -813,7 +813,7 @@ struct Smt2Worker
|
|||
|
||||
if (port.clk_enable)
|
||||
log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! "
|
||||
"Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), log_id(mem->memid), log_id(module));
|
||||
"Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), mem->memid.unescape(), module);
|
||||
|
||||
decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
|
||||
get_id(module), i, get_id(mem->memid), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
|
||||
|
|
@ -857,7 +857,7 @@ struct Smt2Worker
|
|||
|
||||
if (port.clk_enable)
|
||||
log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! "
|
||||
"Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), log_id(mem->memid), log_id(module));
|
||||
"Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), mem->memid.unescape(), module);
|
||||
|
||||
decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
|
||||
get_id(module), i, get_id(mem->memid), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
|
||||
|
|
@ -928,30 +928,30 @@ struct Smt2Worker
|
|||
|
||||
if (cell->type.in(ID($dffe), ID($sdff), ID($sdffe), ID($sdffce)) || cell->type.str().substr(0, 6) == "$_SDFF" || (cell->type.str().substr(0, 6) == "$_DFFE" && cell->type.str().size() == 10)) {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `dffunmap` before `write_smt2`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
if (cell->type.in(ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($dffsr), ID($dffsre)) || cell->type.str().substr(0, 5) == "$_DFF" || cell->type.str().substr(0, 7) == "$_ALDFF") {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `async2sync; dffunmap` or `clk2fflogic` before `write_smt2`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
if (cell->type.in(ID($sr), ID($dlatch), ID($adlatch), ID($dlatchsr)) || cell->type.str().substr(0, 8) == "$_DLATCH" || cell->type.str().substr(0, 5) == "$_SR_") {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `clk2fflogic` before `write_smt2`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type, module, cell);
|
||||
}
|
||||
log_error("Unsupported cell type %s for cell %s.%s.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type, module, cell);
|
||||
}
|
||||
|
||||
void verify_smtlib2_module()
|
||||
{
|
||||
if (!module->get_blackbox_attribute())
|
||||
log_error("Module %s with smtlib2_module attribute must also have blackbox attribute.\n", log_id(module));
|
||||
log_error("Module %s with smtlib2_module attribute must also have blackbox attribute.\n", module);
|
||||
if (module->cells().size() > 0)
|
||||
log_error("Module %s with smtlib2_module attribute must not have any cells inside it.\n", log_id(module));
|
||||
log_error("Module %s with smtlib2_module attribute must not have any cells inside it.\n", module);
|
||||
for (auto wire : module->wires())
|
||||
if (!wire->port_id)
|
||||
log_error("Wire %s.%s must be input or output since module has smtlib2_module attribute.\n", log_id(module),
|
||||
log_id(wire));
|
||||
log_error("Wire %s.%s must be input or output since module has smtlib2_module attribute.\n", module,
|
||||
wire);
|
||||
}
|
||||
|
||||
void run()
|
||||
|
|
@ -991,8 +991,8 @@ struct Smt2Worker
|
|||
}
|
||||
bool is_smtlib2_comb_expr = wire->has_attribute(ID::smtlib2_comb_expr);
|
||||
if (is_smtlib2_comb_expr && !is_smtlib2_module)
|
||||
log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", log_id(module),
|
||||
log_id(wire));
|
||||
log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", module,
|
||||
wire);
|
||||
if (wire->port_id || is_register || contains_clock || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) {
|
||||
RTLIL::SigSpec sig = sigmap(wire);
|
||||
std::vector<std::string> comments;
|
||||
|
|
@ -1023,10 +1023,10 @@ struct Smt2Worker
|
|||
smtlib2_comb_expr =
|
||||
"(let (\n" + smtlib2_inputs + ")\n" + wire->get_string_attribute(ID::smtlib2_comb_expr) + "\n)";
|
||||
if (wire->port_input || !wire->port_output)
|
||||
log_error("smtlib2_comb_expr is only valid on output: wire %s.%s", log_id(module), log_id(wire));
|
||||
log_error("smtlib2_comb_expr is only valid on output: wire %s.%s", module, wire);
|
||||
if (!bvmode && GetSize(sig) > 1)
|
||||
log_error("smtlib2_comb_expr is unsupported on multi-bit wires when -nobv is specified: wire %s.%s",
|
||||
log_id(module), log_id(wire));
|
||||
module, wire);
|
||||
|
||||
comments.push_back(witness_signal("blackbox", wire->width, 0, get_id(wire), -1, wire));
|
||||
}
|
||||
|
|
@ -1075,7 +1075,7 @@ struct Smt2Worker
|
|||
if (wire->attributes.count(ID::init)) {
|
||||
if (is_smtlib2_module)
|
||||
log_error("init attribute not allowed on wires in module with smtlib2_module attribute: wire %s.%s",
|
||||
log_id(module), log_id(wire));
|
||||
module, wire);
|
||||
|
||||
RTLIL::SigSpec sig = sigmap(wire);
|
||||
Const val = wire->attributes.at(ID::init);
|
||||
|
|
@ -1381,7 +1381,7 @@ struct Smt2Worker
|
|||
}
|
||||
}
|
||||
|
||||
if (verbose) log("=> finalizing SMT2 representation of %s.\n", log_id(module));
|
||||
if (verbose) log("=> finalizing SMT2 representation of %s.\n", module);
|
||||
|
||||
for (auto c : hiercells) {
|
||||
assert_list.push_back(stringf("(|%s_a| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name)));
|
||||
|
|
@ -1867,12 +1867,12 @@ struct Smt2Backend : public Backend {
|
|||
for (auto &dep : it.second)
|
||||
if (module_deps.count(dep) > 0)
|
||||
goto not_ready_yet;
|
||||
// log("Next in topological sort: %s\n", log_id(it.first->name));
|
||||
// log("Next in topological sort: %s\n", it.first->name.unescape());
|
||||
sorted_modules.push_back(it.first);
|
||||
not_ready_yet:;
|
||||
}
|
||||
if (sorted_modules_idx == sorted_modules.size())
|
||||
log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", log_id(module_deps.begin()->first->name));
|
||||
log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", module_deps.begin()->first->name.unescape());
|
||||
while (sorted_modules_idx < sorted_modules.size())
|
||||
module_deps.erase(sorted_modules.at(sorted_modules_idx++));
|
||||
}
|
||||
|
|
@ -1902,7 +1902,7 @@ struct Smt2Backend : public Backend {
|
|||
if (module->has_processes_warn())
|
||||
continue;
|
||||
|
||||
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
|
||||
log("Creating SMT-LIBv2 representation of module %s.\n", module);
|
||||
|
||||
Smt2Worker worker(module, bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode, mod_stbv_width, mod_clk_cache);
|
||||
worker.run();
|
||||
|
|
|
|||
|
|
@ -735,6 +735,12 @@ def ywfile_signal(sig, step, mask=None):
|
|||
|
||||
output = []
|
||||
|
||||
def ywfile_signal_error(reason, detail=None):
|
||||
msg = f"Yosys witness signal mismatch for {sig.pretty()}: {reason}"
|
||||
if detail:
|
||||
msg += f" ({detail})"
|
||||
raise ValueError(msg)
|
||||
|
||||
if sig.path in smt_wires:
|
||||
for wire in smt_wires[sig.path]:
|
||||
width, offset = wire["width"], wire["offset"]
|
||||
|
|
@ -765,6 +771,12 @@ def ywfile_signal(sig, step, mask=None):
|
|||
for mem in smt_mems[sig.memory_path]:
|
||||
width, size, bv = mem["width"], mem["size"], mem["statebv"]
|
||||
|
||||
if sig.memory_addr is not None and sig.memory_addr >= size:
|
||||
ywfile_signal_error(
|
||||
"memory address out of bounds",
|
||||
f"address={sig.memory_addr} size={size}",
|
||||
)
|
||||
|
||||
smt_expr = smt.net_expr(topmod, f"s{step}", mem["smtpath"])
|
||||
|
||||
if bv:
|
||||
|
|
@ -781,18 +793,34 @@ def ywfile_signal(sig, step, mask=None):
|
|||
smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr)
|
||||
|
||||
output.append((0, sig.width, smt_expr))
|
||||
else:
|
||||
ywfile_signal_error("memory not found in design")
|
||||
|
||||
output.sort()
|
||||
|
||||
output = [chunk for chunk in output if chunk[0] != chunk[1]]
|
||||
|
||||
if not output:
|
||||
if sig.memory_path:
|
||||
ywfile_signal_error("memory signal has no matching bits in design")
|
||||
else:
|
||||
ywfile_signal_error("signal not found in design")
|
||||
|
||||
pos = 0
|
||||
|
||||
for start, end, smt_expr in output:
|
||||
assert start == pos
|
||||
if start != pos:
|
||||
ywfile_signal_error(
|
||||
"signal width/offset mismatch",
|
||||
f"expected coverage at bit {pos}",
|
||||
)
|
||||
pos = end
|
||||
|
||||
assert pos == sig.width
|
||||
if pos != sig.width:
|
||||
ywfile_signal_error(
|
||||
"signal width/offset mismatch",
|
||||
f"covered {pos} of {sig.width} bits",
|
||||
)
|
||||
|
||||
if len(output) == 1:
|
||||
return output[0][-1]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct SmvWorker
|
||||
{
|
||||
CellTypes ct;
|
||||
NewCellTypes ct;
|
||||
SigMap sigmap;
|
||||
RTLIL::Module *module;
|
||||
std::ostream &f;
|
||||
|
|
@ -217,7 +217,7 @@ struct SmvWorker
|
|||
partial_assignment_wires.insert(wire);
|
||||
|
||||
if (wire->port_input)
|
||||
inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, log_id(wire)));
|
||||
inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, wire));
|
||||
|
||||
if (wire->attributes.count(ID::init))
|
||||
assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at(ID::init))));
|
||||
|
|
@ -579,18 +579,18 @@ struct SmvWorker
|
|||
if (cell->type[0] == '$') {
|
||||
if (cell->type.in(ID($dffe), ID($sdff), ID($sdffe), ID($sdffce)) || cell->type.str().substr(0, 6) == "$_SDFF" || (cell->type.str().substr(0, 6) == "$_DFFE" && cell->type.str().size() == 10)) {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `dffunmap` before `write_smv`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
if (cell->type.in(ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($dffsr), ID($dffsre)) || cell->type.str().substr(0, 5) == "$_DFF" || cell->type.str().substr(0, 7) == "$_ALDFF") {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `async2sync; dffunmap` or `clk2fflogic` before `write_smv`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
if (cell->type.in(ID($sr), ID($dlatch), ID($adlatch), ID($dlatchsr)) || cell->type.str().substr(0, 8) == "$_DLATCH" || cell->type.str().substr(0, 5) == "$_SR_") {
|
||||
log_error("Unsupported cell type %s for cell %s.%s -- please run `clk2fflogic` before `write_smv`.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
log_error("Unsupported cell type %s for cell %s.%s.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
}
|
||||
|
||||
// f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
|
||||
|
|
@ -799,7 +799,7 @@ struct SmvBackend : public Backend {
|
|||
|
||||
*f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());
|
||||
|
||||
log("Creating SMV representation of module %s.\n", log_id(module));
|
||||
log("Creating SMV representation of module %s.\n", module);
|
||||
SmvWorker worker(module, verbose, *f);
|
||||
worker.run();
|
||||
|
||||
|
|
@ -819,7 +819,7 @@ struct SmvBackend : public Backend {
|
|||
*f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());
|
||||
|
||||
for (auto module : modules) {
|
||||
log("Creating SMV representation of module %s.\n", log_id(module));
|
||||
log("Creating SMV representation of module %s.\n", module);
|
||||
SmvWorker worker(module, verbose, *f);
|
||||
worker.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
static string spice_id2str(IdString id)
|
||||
{
|
||||
static const char *escape_chars = "$\\[]()<>=";
|
||||
string s = RTLIL::unescape_id(id);
|
||||
string s = id.unescape();
|
||||
|
||||
for (auto &ch : s)
|
||||
if (strchr(escape_chars, ch) != nullptr) ch = '_';
|
||||
|
|
@ -82,7 +82,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
|
|||
if (design->module(cell->type) == nullptr)
|
||||
{
|
||||
log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
cell->type.unescape(), module, cell);
|
||||
for (auto &conn : cell->connections()) {
|
||||
RTLIL::SigSpec sig = sigmap(conn.second);
|
||||
port_sigs.push_back(sig);
|
||||
|
|
@ -224,9 +224,9 @@ struct SpiceBackend : public Backend {
|
|||
continue;
|
||||
|
||||
if (module->processes.size() != 0)
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", log_id(module));
|
||||
log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", module);
|
||||
if (module->memories.size() != 0)
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", log_id(module));
|
||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", module);
|
||||
|
||||
if (module->name == RTLIL::escape_id(top_module_name)) {
|
||||
top_module = module;
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ struct TableBackend : public Backend {
|
|||
if (wire->port_id == 0)
|
||||
continue;
|
||||
|
||||
*f << log_id(module) << "\t";
|
||||
*f << log_id(wire) << "\t";
|
||||
*f << module->name.unescape() << "\t";
|
||||
*f << wire->name.unescape() << "\t";
|
||||
*f << "-" << "\t";
|
||||
*f << "-" << "\t";
|
||||
|
||||
|
|
@ -97,10 +97,10 @@ struct TableBackend : public Backend {
|
|||
for (auto cell : module->cells())
|
||||
for (auto conn : cell->connections())
|
||||
{
|
||||
*f << log_id(module) << "\t";
|
||||
*f << log_id(cell) << "\t";
|
||||
*f << log_id(cell->type) << "\t";
|
||||
*f << log_id(conn.first) << "\t";
|
||||
*f << module->name.unescape() << "\t";
|
||||
*f << cell->name.unescape() << "\t";
|
||||
*f << cell->type.unescape() << "\t";
|
||||
*f << conn.first.unescape() << "\t";
|
||||
|
||||
if (cell->input(conn.first) && cell->output(conn.first))
|
||||
*f << "inout" << "\t";
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ bool VERILOG_BACKEND::id_is_verilog_escaped(const std::string &str) {
|
|||
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog, simple_lhs, noparallelcase;
|
||||
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog, simple_lhs,
|
||||
noparallelcase, default_params;
|
||||
int auto_name_counter, auto_name_offset, auto_name_digits, extmem_counter;
|
||||
dict<RTLIL::IdString, int> auto_name_map;
|
||||
std::set<RTLIL::IdString> reg_wires;
|
||||
|
|
@ -108,22 +109,30 @@ IdString initial_id;
|
|||
|
||||
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
|
||||
{
|
||||
const char *str = id.c_str();
|
||||
|
||||
if (*str == '$' && may_rename && !norename)
|
||||
auto_name_map[id] = auto_name_counter++;
|
||||
|
||||
if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
|
||||
auto it = id.begin();
|
||||
auto it_end = id.end();
|
||||
if (it == it_end)
|
||||
return;
|
||||
|
||||
for (int i = 2; str[i] != 0; i++) {
|
||||
if (str[i] == '_' && str[i+1] == 0)
|
||||
continue;
|
||||
if (str[i] < '0' || str[i] > '9')
|
||||
if (*it == '$' && may_rename && !norename)
|
||||
auto_name_map[id] = auto_name_counter++;
|
||||
|
||||
if (*it != '\\' || (it + 1) == it_end || *(it + 1) != '_' || (it + 2) == it_end)
|
||||
return;
|
||||
|
||||
std::string s;
|
||||
it += 2;
|
||||
while (it != it_end) {
|
||||
char ch = *it;
|
||||
if (ch == '_' && (it + 1) == it_end)
|
||||
break;
|
||||
if (ch < '0' || ch > '9')
|
||||
return;
|
||||
s.push_back(ch);
|
||||
++it;
|
||||
}
|
||||
|
||||
int num = atoi(str+2);
|
||||
int num = atoi(s.c_str());
|
||||
if (num >= auto_name_offset)
|
||||
auto_name_offset = num + 1;
|
||||
}
|
||||
|
|
@ -413,6 +422,13 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
|
|||
}
|
||||
}
|
||||
|
||||
void dump_parameter(std::ostream &f, std::string indent, RTLIL::IdString id_string, RTLIL::Const parameter)
|
||||
{
|
||||
f << stringf("%sparameter %s = ", indent.c_str(), id(id_string).c_str());
|
||||
dump_const(f, parameter);
|
||||
f << ";\n";
|
||||
}
|
||||
|
||||
void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
||||
{
|
||||
dump_attributes(f, indent, wire->attributes, "\n", /*modattr=*/false, /*regattr=*/reg_wires.count(wire->name));
|
||||
|
|
@ -2135,6 +2151,9 @@ void dump_case_actions(std::ostream &f, std::string indent, RTLIL::CaseRule *cs)
|
|||
|
||||
bool dump_proc_switch_ifelse(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
|
||||
{
|
||||
if (sw->cases.empty())
|
||||
return true;
|
||||
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
|
||||
if ((*it)->compare.size() == 0) {
|
||||
break;
|
||||
|
|
@ -2369,7 +2388,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
log_warning("Module %s contains RTLIL processes with sync rules. Such RTLIL "
|
||||
"processes can't always be mapped directly to Verilog always blocks. "
|
||||
"unintended changes in simulation behavior are possible! Use \"proc\" "
|
||||
"to convert processes to logic networks and registers.\n", log_id(module));
|
||||
"to convert processes to logic networks and registers.\n", module);
|
||||
|
||||
f << stringf("\n");
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||
|
|
@ -2427,6 +2446,10 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
f << indent + " " << "reg " << id(initial_id) << " = 0;\n";
|
||||
}
|
||||
|
||||
if (default_params)
|
||||
for (auto p : module->parameter_default_values)
|
||||
dump_parameter(f, indent + " ", p.first, p.second);
|
||||
|
||||
// first dump input / output according to their order in module->ports
|
||||
for (auto port : module->ports)
|
||||
dump_wire(f, indent + " ", module->wire(port));
|
||||
|
|
@ -2534,6 +2557,10 @@ struct VerilogBackend : public Backend {
|
|||
log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
|
||||
log(" cell parameters.\n");
|
||||
log("\n");
|
||||
log(" -default_params\n");
|
||||
log(" emit module parameter declarations from\n");
|
||||
log(" parameter_default_values.\n");
|
||||
log("\n");
|
||||
log(" -blackboxes\n");
|
||||
log(" usually modules with the 'blackbox' attribute are ignored. with\n");
|
||||
log(" this option set only the modules with the 'blackbox' attribute\n");
|
||||
|
|
@ -2571,6 +2598,7 @@ struct VerilogBackend : public Backend {
|
|||
siminit = false;
|
||||
simple_lhs = false;
|
||||
noparallelcase = false;
|
||||
default_params = false;
|
||||
auto_prefix = "";
|
||||
|
||||
bool blackboxes = false;
|
||||
|
|
@ -2631,6 +2659,10 @@ struct VerilogBackend : public Backend {
|
|||
defparam = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-defaultparams") {
|
||||
default_params = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-decimal") {
|
||||
decimal = true;
|
||||
continue;
|
||||
|
|
@ -2682,7 +2714,7 @@ struct VerilogBackend : public Backend {
|
|||
continue;
|
||||
if (selected && !design->selected_whole_module(module->name)) {
|
||||
if (design->selected_module(module->name))
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", log_id(module->name));
|
||||
log_cmd_error("Can't handle partially selected module %s!\n", module->name.unescape());
|
||||
continue;
|
||||
}
|
||||
log("Dumping module `%s'.\n", module->name);
|
||||
|
|
|
|||
|
|
@ -32,8 +32,9 @@ FORCE:
|
|||
TEX_FILES := $(shell find . -name *.tex)
|
||||
all_tex: $(TEX_FILES:.tex=.pdf) $(TEX_FILES:.tex=.svg)
|
||||
|
||||
# limit output size to US letter (same as latexpdf output) to avoid oversize error
|
||||
%.pdf: %.dot
|
||||
$(FAKETIME) dot -Tpdf -o $@ $<
|
||||
$(FAKETIME) dot -Tpdf -Gsize="8.5,11" -o $@ $<
|
||||
|
||||
%.pdf: %.tex
|
||||
cd $(@D) && $(FAKETIME) pdflatex $(<F) --interaction=nonstopmode
|
||||
|
|
|
|||
|
|
@ -154,6 +154,10 @@ to the following Verilog code template, where ``RST_EDGE`` is ``posedge`` if
|
|||
``RST_LVL`` if ``1``, ``negedge`` otherwise, and ``SET_EDGE`` is ``posedge`` if
|
||||
``SET_LVL`` if ``1``, ``negedge`` otherwise.
|
||||
|
||||
When both set and reset are active, the state and output is undefined. The Verilog
|
||||
code model does not correspond to this due to limitations
|
||||
of synthesizable Verilog.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
|
|
@ -187,6 +191,10 @@ types relate to the following Verilog code template, where ``RST_EDGE`` is
|
|||
``posedge`` if ``RST_LVL`` if ``1``, ``negedge`` otherwise, and ``SET_EDGE`` is
|
||||
``posedge`` if ``SET_LVL`` if ``1``, ``negedge`` otherwise.
|
||||
|
||||
When both set and reset are active, the state and output is undefined. The Verilog
|
||||
code model does not correspond to this due to limitations
|
||||
of synthesizable Verilog.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ D-type flip-flops with asynchronous set and reset are represented by `$dffsr`
|
|||
cells. As the `$dff` cells they have ``CLK``, ``D`` and ``Q`` ports. In addition
|
||||
they also have multi-bit ``SET`` and ``CLR`` input ports and the corresponding
|
||||
polarity parameters, like `$sr` cells.
|
||||
When both set and reset are active, the state and output is undefined.
|
||||
|
||||
D-type flip-flops with enable are represented by `$dffe`, `$adffe`, `$aldffe`,
|
||||
`$dffsre`, `$sdffe`, and `$sdffce` cells, which are enhanced variants of `$dff`,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ struct MyPass : public Pass {
|
|||
|
||||
log("Modules in current design:\n");
|
||||
for (auto mod : design->modules())
|
||||
log(" %s (%d wires, %d cells)\n", log_id(mod),
|
||||
log(" %s (%d wires, %d cells)\n", mod,
|
||||
GetSize(mod->wires()), GetSize(mod->cells()));
|
||||
}
|
||||
} MyPass;
|
||||
|
|
@ -28,7 +28,7 @@ struct Test1Pass : public Pass {
|
|||
log_error("A module with the name absval already exists!\n");
|
||||
|
||||
RTLIL::Module *module = design->addModule("\\absval");
|
||||
log("Name of this module: %s\n", log_id(module));
|
||||
log("Name of this module: %s\n", module);
|
||||
|
||||
RTLIL::Wire *a = module->addWire("\\a", 4);
|
||||
a->port_input = true;
|
||||
|
|
|
|||
|
|
@ -24,19 +24,19 @@ struct FunctionalDummyBackend : public Backend {
|
|||
|
||||
// write node functions
|
||||
for (auto node : ir)
|
||||
*f << " assign " << id2cstr(node.name())
|
||||
*f << " assign " << node.name().unescape()
|
||||
<< " = " << node.to_string() << "\n";
|
||||
*f << "\n";
|
||||
|
||||
// write outputs and next state
|
||||
for (auto output : ir.outputs())
|
||||
*f << " " << id2cstr(output->kind)
|
||||
<< " " << id2cstr(output->name)
|
||||
<< " = " << id2cstr(output->value().name()) << "\n";
|
||||
*f << " " << output->kind.unescape()
|
||||
<< " " << output->name.unescape()
|
||||
<< " = " << output->value().name().unescape() << "\n";
|
||||
for (auto state : ir.states())
|
||||
*f << " " << id2cstr(state->kind)
|
||||
<< " " << id2cstr(state->name)
|
||||
<< " = " << id2cstr(state->next_value().name()) << "\n";
|
||||
*f << " " << state->kind.unescape()
|
||||
<< " " << state->name.unescape()
|
||||
<< " = " << state->next_value().name().unescape() << "\n";
|
||||
}
|
||||
}
|
||||
} FunctionalDummyBackend;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ coarse:
|
|||
opt_clean
|
||||
memory_collect
|
||||
opt -noff -keepdc -fast
|
||||
sort
|
||||
|
||||
check:
|
||||
stat
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ begin:
|
|||
proc
|
||||
|
||||
flatten:
|
||||
check
|
||||
flatten
|
||||
tribuf -logic
|
||||
deminout
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
|
|||
// count output lines for this module (needed only for summary output at the end)
|
||||
int line_count = 0;
|
||||
|
||||
log("Looking for stub wires in module %s:\n", RTLIL::id2cstr(module->name));
|
||||
log("Looking for stub wires in module %s:\n", module);
|
||||
|
||||
// For all ports on all cells
|
||||
for (auto &cell_iter : module->cells_)
|
||||
|
|
@ -74,11 +74,11 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
|
|||
// report stub bits and/or stub wires, don't report single bits
|
||||
// if called with report_bits set to false.
|
||||
if (GetSize(stub_bits) == GetSize(sig)) {
|
||||
log(" found stub wire: %s\n", RTLIL::id2cstr(wire->name));
|
||||
log(" found stub wire: %s\n", wire);
|
||||
} else {
|
||||
if (!report_bits)
|
||||
continue;
|
||||
log(" found wire with stub bits: %s [", RTLIL::id2cstr(wire->name));
|
||||
log(" found wire with stub bits: %s [", wire);
|
||||
for (int bit : stub_bits)
|
||||
log("%s%d", bit == *stub_bits.begin() ? "" : ", ", bit);
|
||||
log("]\n");
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import os
|
|||
|
||||
project = 'YosysHQ Yosys'
|
||||
author = 'YosysHQ GmbH'
|
||||
copyright ='2025 YosysHQ GmbH'
|
||||
yosys_ver = "0.59"
|
||||
copyright ='2026 YosysHQ GmbH'
|
||||
yosys_ver = "0.65"
|
||||
|
||||
# select HTML theme
|
||||
html_theme = 'furo-ys'
|
||||
|
|
|
|||
|
|
@ -291,7 +291,10 @@ In `synth_ice40` we get these:
|
|||
:name: synth_flatten
|
||||
:caption: ``flatten`` section
|
||||
|
||||
First off is `flatten`. Flattening the design like this can allow for
|
||||
We start by runnning `check`. This doesn't affect the design, but it can
|
||||
identify a few obvious problems which will cause errors later. Calling it here
|
||||
lets us fail faster rather than wasting time on something we know is impossible.
|
||||
Next up is `flatten`. Flattening the design like this can allow for
|
||||
optimizations between modules which would otherwise be missed. Let's run
|
||||
:yoscrypt:`flatten;;` on our design.
|
||||
|
||||
|
|
@ -363,17 +366,14 @@ In the iCE40 flow, we start with the following commands:
|
|||
:caption: ``coarse`` section (part 1)
|
||||
:name: synth_coarse1
|
||||
|
||||
We've already come across `opt_expr`, and `opt_clean` is the same as `clean` but
|
||||
with more verbose output. The `check` pass identifies a few obvious problems
|
||||
which will cause errors later. Calling it here lets us fail faster rather than
|
||||
wasting time on something we know is impossible.
|
||||
|
||||
Next up is :yoscrypt:`opt -nodffe -nosdff` performing a set of simple
|
||||
optimizations on the design. This command also ensures that only a specific
|
||||
subset of FF types are included, in preparation for the next command:
|
||||
:cmd:title:`fsm`. Both `opt` and `fsm` are macro commands which are explored in
|
||||
more detail in :doc:`/using_yosys/synthesis/opt` and
|
||||
:doc:`/using_yosys/synthesis/fsm` respectively.
|
||||
We've already come across `opt_expr` and `check`, and `opt_clean` is the same as
|
||||
`clean` but with more verbose output. Next up is :yoscrypt:`opt -nodffe
|
||||
-nosdff` performing a set of simple optimizations on the design. This command
|
||||
also ensures that only a specific subset of FF types are included, in
|
||||
preparation for the next command: :cmd:title:`fsm`. Both `opt` and `fsm` are
|
||||
macro commands which are explored in more detail in
|
||||
:doc:`/using_yosys/synthesis/opt` and :doc:`/using_yosys/synthesis/fsm`
|
||||
respectively.
|
||||
|
||||
Up until now, the data path for ``rdata`` has remained the same since
|
||||
:ref:`rdata_flat`. However the next call to `opt` does cause a change.
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ not regularly tested:
|
|||
Build prerequisites
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A C++ compiler with C++17 support is required as well as some standard tools
|
||||
A C++ compiler with C++20 support is required as well as some standard tools
|
||||
such as GNU Flex, GNU Bison (>=3.8), Make, and Python (>=3.11). Some additional
|
||||
tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see
|
||||
:makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ is still valid.
|
|||
:caption: Example test.sh for C-Reduce
|
||||
:name: egtest
|
||||
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
verilator --lint-only test.v &&/
|
||||
yosys -p 'logger -expect error "unsupported" 1; read_verilog test.v'
|
||||
|
||||
|
|
@ -333,7 +333,7 @@ an input argument: ``sv-bugpoint outDir/ test.sh test.v``
|
|||
.. code-block:: bash
|
||||
:caption: Example test.sh for sv-bugpoint
|
||||
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
verilator --lint-only $1 &&/
|
||||
yosys -p "logger -expect error \"unsupported\" 1; read_verilog $1"
|
||||
|
||||
|
|
|
|||
|
|
@ -117,3 +117,32 @@ Result with fixed :file:`axis_master.v`:
|
|||
|
||||
Solving problem with 159144 variables and 441626 clauses..
|
||||
SAT proof finished - no model found: SUCCESS!
|
||||
|
||||
Witness framework and per-property tracking
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When using AIGER-based formal verification flows (such as the ``abc`` engine in
|
||||
SBY), Yosys provides infrastructure for tracking individual formal
|
||||
properties through the verification pipeline.
|
||||
|
||||
The `rename -witness` pass assigns public names to all cells that participate in
|
||||
the witness framework:
|
||||
|
||||
- Witness signal cells: `$anyconst`, `$anyseq`, `$anyinit`,
|
||||
`$allconst`, `$allseq`
|
||||
- Formal property cells: `$assert`, `$assume`, `$cover`, `$live`,
|
||||
`$fair`, `$check`
|
||||
|
||||
These public names allow downstream tools to refer to individual properties by
|
||||
their hierarchical path rather than by anonymous internal identifiers.
|
||||
|
||||
The `write_aiger -ywmap` option generates a map file for conversion to and from
|
||||
Yosys witness traces, and also allows for mapping AIGER bad-state properties and
|
||||
invariant constraints back to individual formal properties by name. This enables
|
||||
features like per-property pass/fail reporting (e.g. ``abc pdr`` with
|
||||
``--keep-going`` mode).
|
||||
|
||||
The `write_smt2` backend similarly uses the public witness names when emitting
|
||||
SMT2 comments. Cells whose ``hdlname`` attribute contains the ``_witness_``
|
||||
marker are treated as having private names for comment purposes, keeping solver
|
||||
output clean.
|
||||
|
|
|
|||
|
|
@ -355,6 +355,9 @@ from SystemVerilog:
|
|||
design with `read_verilog`, all its packages are available to SystemVerilog
|
||||
files being read into the same design afterwards.
|
||||
|
||||
- nested packages are currently not supported (i.e. calling ``import`` inside
|
||||
a ``package`` .. ``endpackage`` block)
|
||||
|
||||
- typedefs are supported (including inside packages)
|
||||
|
||||
- type casts are currently not supported
|
||||
|
|
|
|||
|
|
@ -1,57 +1,18 @@
|
|||
Contributing to Yosys
|
||||
=====================
|
||||
|
||||
.. note::
|
||||
|
||||
For information on making a pull request on github, refer to our
|
||||
|CONTRIBUTING|_ file.
|
||||
|
||||
.. |CONTRIBUTING| replace:: :file:`CONTRIBUTING.md`
|
||||
.. _CONTRIBUTING: https://github.com/YosysHQ/yosys/blob/main/CONTRIBUTING.md
|
||||
|
||||
Coding Style
|
||||
------------
|
||||
|
||||
Formatting of code
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Yosys code is using tabs for indentation. Tabs are 8 characters.
|
||||
|
||||
- A continuation of a statement in the following line is indented by two
|
||||
additional tabs.
|
||||
|
||||
- Lines are as long as you want them to be. A good rule of thumb is to break
|
||||
lines at about column 150.
|
||||
|
||||
- Opening braces can be put on the same or next line as the statement opening
|
||||
the block (if, switch, for, while, do). Put the opening brace on its own line
|
||||
for larger blocks, especially blocks that contains blank lines.
|
||||
|
||||
- Otherwise stick to the `Linux Kernel Coding Style`_.
|
||||
|
||||
.. _Linux Kernel Coding Style: https://www.kernel.org/doc/Documentation/process/coding-style.rst
|
||||
|
||||
|
||||
C++ Language
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Yosys is written in C++17.
|
||||
|
||||
In general Yosys uses ``int`` instead of ``size_t``. To avoid compiler warnings
|
||||
for implicit type casts, always use ``GetSize(foobar)`` instead of
|
||||
``foobar.size()``. (``GetSize()`` is defined in :file:`kernel/yosys.h`)
|
||||
|
||||
Use range-based for loops whenever applicable.
|
||||
|
||||
|
||||
Reporting bugs
|
||||
--------------
|
||||
|
||||
- use the `bug report template`_
|
||||
We fix well-reported bugs the fastest. A good bug report is an issue on the `issue tracker`_
|
||||
and includes the following information:
|
||||
|
||||
.. _bug report template: https://github.com/YosysHQ/yosys/issues/new?template=bug_report.yml
|
||||
.. _`issue tracker`: https://github.com/YosysHQ/yosys/issues
|
||||
|
||||
- short title briefly describing the issue, e.g.
|
||||
Title
|
||||
~~~~~
|
||||
|
||||
briefly describe the issue, for example:
|
||||
|
||||
techmap of wide mux with undefined inputs raises error during synth_xilinx
|
||||
|
||||
|
|
@ -64,10 +25,20 @@ Reporting bugs
|
|||
Reproduction Steps
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- ideally a code-block (starting and ending with triple backquotes) containing
|
||||
the minimized design (Verilog or RTLIL), followed by a code-block containing
|
||||
the minimized yosys script OR a command line call to yosys with
|
||||
code-formatting (starting and ending with single backquotes)
|
||||
The reproduction steps should be a minimal, complete and verifiable
|
||||
example `MVCE`_.
|
||||
Providing an MVCE with your bug report drastically increases the likelihood that
|
||||
someone will be able to help resolve your issue.
|
||||
Make sure that your report input is free of any problems as reported by the
|
||||
`check` command.
|
||||
One way to minimize a design is to use the `bugpoint` command.
|
||||
You can learn more in the :doc:`how-to guide for bugpoint </using_yosys/bugpoint>`.
|
||||
|
||||
The reproduction steps are ideally a code-block (starting and ending with
|
||||
triple backquotes) containing
|
||||
the minimized design (Verilog or RTLIL), followed by a code-block containing
|
||||
the minimized yosys script OR a command line call to yosys with
|
||||
code-formatting (starting and ending with single backquotes).
|
||||
|
||||
.. code-block:: markdown
|
||||
|
||||
|
|
@ -86,9 +57,9 @@ Reproduction Steps
|
|||
|
||||
`yosys -p ': minimum sequence of commands;' min.v`
|
||||
|
||||
- alternatively can provide a single code-block which includes the minimized
|
||||
design as a "here document" followed by the sequence of commands which
|
||||
reproduce the error
|
||||
Alternatively, you can provide a single code-block which includes the minimized
|
||||
design as a "here document" followed by the sequence of commands which
|
||||
reproduce the error
|
||||
|
||||
+ see :doc:`/using_yosys/more_scripting/load_design` for more on heredocs.
|
||||
|
||||
|
|
@ -101,7 +72,9 @@ Reproduction Steps
|
|||
# minimum sequence of commands
|
||||
```
|
||||
|
||||
- any environment variables or command line options should also be mentioned
|
||||
Don't forget to mention:
|
||||
|
||||
- any important environment variables or command line options
|
||||
- if the problem occurs for a range of values/designs, what is that range
|
||||
- if you're using an external tool, such as ``valgrind``, to detect the issue,
|
||||
what version of that tool are you using and what options are you giving it
|
||||
|
|
@ -115,46 +88,57 @@ Reproduction Steps
|
|||
around Yosys such as OpenLane; you should instead minimize your input and
|
||||
reproduction steps to just the Yosys part.
|
||||
|
||||
"Expected Behaviour"
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
.. _MVCE: https://stackoverflow.com/help/minimal-reproducible-example
|
||||
.. _how-to guide for bugpoint: https://yosys.readthedocs.io/en/latest/using_yosys/bugpoint.html
|
||||
|
||||
- if you have a similar design/script that doesn't give the error, include it
|
||||
here as a reference
|
||||
- if the bug is that an error *should* be raised but isn't, are there any other
|
||||
commands with similar error messages
|
||||
|
||||
|
||||
"Actual Behaviour"
|
||||
Expected Behaviour
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- any error messages go here
|
||||
- any details relevant to the crash that were found with ``--trace`` or
|
||||
``--debug`` flags
|
||||
- if you identified the point of failure in the source code, you could mention
|
||||
it here, or as a comment below
|
||||
Describe what you'd expect to happen when we follow the reproduction steps
|
||||
if the bug was fixed.
|
||||
|
||||
+ if possible, use a permalink to the source on GitHub
|
||||
+ you can browse the source repository for a certain commit with the failure
|
||||
If you have a similar design/script that doesn't give the error, include it
|
||||
here as a reference. If the bug is that an error *should* be raised but isn't,
|
||||
note if there are any other commands with similar error messages.
|
||||
|
||||
|
||||
Actual Behaviour
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Describe what you actually see when you follow the reproduction steps.
|
||||
|
||||
This can include:
|
||||
|
||||
* any error messages
|
||||
* any details relevant to the crash that were found with ``--trace`` or
|
||||
``--debug`` flags
|
||||
* the part of the source code that triggers the bug
|
||||
|
||||
* if possible, use a permalink to the source on GitHub
|
||||
* you can browse the source repository for a certain commit with the failure
|
||||
and open the source file, select the relevant lines (click on the line
|
||||
number for the first relevant line, then while holding shift click on the
|
||||
line number for the last relevant line), click on the ``...`` that appears
|
||||
and select "Copy permalink"
|
||||
+ should look something like
|
||||
* should look something like
|
||||
``https://github.com/YosysHQ/yosys/blob/<commit_hash>/path/to/file#L139-L147``
|
||||
+ clicking on "Preview" should reveal a code block containing the lines of
|
||||
* clicking on "Preview" should reveal a code block containing the lines of
|
||||
source specified, with a link to the source file at the given commit
|
||||
|
||||
|
||||
Additional details
|
||||
Additional Details
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- once you have created the issue, any additional details can be added as a
|
||||
comment on that issue
|
||||
- could include any additional context as to what you were doing when you first
|
||||
encountered the bug
|
||||
- was this issue discovered through the use of a fuzzer
|
||||
- if you've minimized the script, consider including the `bugpoint` script you
|
||||
used, or the original script, e.g.
|
||||
Anything else you think might be helpful or relevant when verifying or fixing
|
||||
the bug.
|
||||
|
||||
Once you have created the issue, any additional details can be added as a
|
||||
comment on that issue. You can include any additional context as to what you
|
||||
were doing when you first encountered the bug.
|
||||
|
||||
If this issue discovered through the use of a fuzzer, ALWAYS declare that.
|
||||
If you've minimized the script, consider including the `bugpoint` script you
|
||||
used, or the original script, for example:
|
||||
|
||||
.. code-block:: markdown
|
||||
|
||||
|
|
@ -171,8 +155,257 @@ Additional details
|
|||
Minimized from
|
||||
`yosys -p ': original sequence of commands to produce error;' design.v`
|
||||
|
||||
- if you're able to, it may also help to share the original un-minimized design
|
||||
|
||||
+ if the design is too big for a comment, consider turning it into a `Gist`_
|
||||
If possible, it may also help to share the original un-minimized design.
|
||||
If the design is too big for a comment, consider turning it into a `Gist`_
|
||||
|
||||
.. _Gist: https://gist.github.com/
|
||||
|
||||
Contributing code
|
||||
-----------------
|
||||
|
||||
Code that matters
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you're adding complex functionality, or modifying core parts of yosys,
|
||||
we highly recommend discussing your motivation and approach
|
||||
ahead of time on the `Discourse forum`_. Please, be as explicit and concrete
|
||||
as possible when explaining the motivation for what you're building.
|
||||
Additionally, if you do so on the forum first before you starting hacking
|
||||
away at C++, you might solve your problem without writing a single line
|
||||
of code!
|
||||
|
||||
PRs are considered for relevance, priority, and quality
|
||||
based on their descriptions first, code second.
|
||||
|
||||
Before you build or fix something, also search for existing `issues`_.
|
||||
|
||||
We have open `developer 'jour fixe' (Dev JF) meetings`_
|
||||
where developers from YosysHQ and the
|
||||
community come together to discuss open issues and PRs. This is also a good
|
||||
place to talk to us about how to implement larger PRs.
|
||||
|
||||
.. _`developer 'jour fixe' (Dev JF) meetings`: https://docs.google.com/document/d/1SapA6QAsJcsgwsdKJDgnGR2mr97pJjV4eeXg_TVJhRU/edit?usp=sharing
|
||||
.. _`Discourse forum`: https://yosyshq.discourse.group/
|
||||
.. _`issues`: https://github.com/YosysHQ/yosys/issues
|
||||
|
||||
Making sense
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Given enough effort, the behavior of any code can be figured out to any
|
||||
desired extent. However, the author of the code is by far in the best
|
||||
position to make this as easy as possible.
|
||||
|
||||
Yosys is a long-standing project and has accumulated a lot of C-style code
|
||||
that's not written to be read, just written to run. We improve this bit
|
||||
by bit when opportunities arise, but it is what it is.
|
||||
New additions are expected to be a lot cleaner.
|
||||
|
||||
The purpose and behavior of the code changed should be described clearly.
|
||||
Your change should contain exactly what it needs to match that description.
|
||||
This means:
|
||||
|
||||
* nothing more than that - no dead code, no undocumented features
|
||||
* nothing missing - if something is partially built, that's fine,
|
||||
but you have to make that clear. For example, some passes
|
||||
only support some types of cells
|
||||
|
||||
Here are some software engineering approaches that help:
|
||||
|
||||
* Use abstraction to model the problem and hide details
|
||||
|
||||
* Maximize the usage of types (structs over loose variables),
|
||||
not necessarily in an object-oriented way
|
||||
* Use functions, scopes, type aliases
|
||||
|
||||
* In new passes, make sure the logic behind how and why it works is actually provided
|
||||
in coherent comments, and that variable and type naming is consistent with the terms
|
||||
you use in the description.
|
||||
* The logic of the implementation should be described in mathematical
|
||||
or algorithm theory terms. Correctness, termination, computational complexity.
|
||||
Make it clear if you're re-implementing a classic data structure for logic synthesis
|
||||
or graph traversal etc.
|
||||
|
||||
* There's various ways of traversing the design with use-def indices (for getting
|
||||
drivers and driven signals) available in Yosys. They have advantages and sometimes
|
||||
disadvantages. Prefer not re-implementing these
|
||||
* Prefer references over pointers, and smart pointers over raw pointers
|
||||
* Aggressively deduplicate code. Within functions, within passes,
|
||||
across passes, even against existing code
|
||||
* Prefer declaring things ``const``
|
||||
* Prefer range-based for loops over C-style
|
||||
|
||||
Common mistakes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
* Deleting design objects invalidates iterators. Defer deletions or hold a copy
|
||||
of the list of pointers to design objects
|
||||
* Deleting wires can get sketchy and is intended to be done solely by
|
||||
the ``opt_clean`` pass so just don't do it
|
||||
* Iterating over an entire design and checking if things are selected is more
|
||||
inefficient than using the ``selected_*`` methods
|
||||
* Remember to call ``fixup_ports`` at the end if you're modifying module interfaces
|
||||
|
||||
Testing your change
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Untested code can't be maintained. Inevitable codebase-wide changes
|
||||
are likely to break anything untested. Tests also help reviewers understand
|
||||
the purpose of the code change in practice.
|
||||
|
||||
Your code needs to come with tests. If it's a feature, a test that covers
|
||||
representative examples of the added behavior. If it's a bug fix, it should
|
||||
reproduce the original isolated bug. But in some situations, adding a test
|
||||
isn't viable. If you can't provide a test, explain this decision.
|
||||
|
||||
Prefer writing unit tests (:file:`tests/unit`) for isolated tests to
|
||||
the internals of more serious code changes, like those to the core of yosys,
|
||||
or more algorithmic ones.
|
||||
|
||||
The rest of the test suite is mostly based on running Yosys on various Yosys
|
||||
and Tcl scripts that manually call Yosys commands.
|
||||
See :doc:`/yosys_internals/extending_yosys/test_suites` for more information
|
||||
about how our test suite is structured.
|
||||
The basic test writing approach is checking
|
||||
for the presence of some kind of object or pattern with ``-assert-count`` in
|
||||
:doc:`/using_yosys/more_scripting/selections`.
|
||||
|
||||
It's often best to use equivalence checking with ``equiv_opt -assert``
|
||||
or similar to prove that the changes done to the design by a modified pass
|
||||
preserve equivalence. But some code isn't meant to preserve equivalence.
|
||||
Sometimes proving equivalence takes an impractically long time for larger
|
||||
inputs. Also beware, the ``equiv_`` passes are a bit quirky and might even
|
||||
have incorrect results in unusual situations.
|
||||
|
||||
.. Changes to core parts of Yosys or passes that are included in synthesis flows
|
||||
.. can change runtime and memory usage - for the better or for worse. This strongly
|
||||
.. depends on the design involved. Such risky changes should then be benchmarked
|
||||
.. with various designs.
|
||||
|
||||
.. TODO Emil benchmarking
|
||||
|
||||
Coding style
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Yosys is written in C++20.
|
||||
|
||||
In general Yosys uses ``int`` instead of ``size_t``. To avoid compiler warnings
|
||||
for implicit type casts, always use ``GetSize(foobar)`` instead of
|
||||
``foobar.size()``. (``GetSize()`` is defined in :file:`kernel/yosys.h`)
|
||||
|
||||
For auto formatting code, a :file:`.clang-format` file is present top-level.
|
||||
Yosys code is using tabs for indentation. A tab is 8 characters wide,
|
||||
but prefer not relying on it. A continuation of a statement
|
||||
in the following line is indented by two additional tabs. Lines are
|
||||
as long as you want them to be. A good rule of thumb is to break lines
|
||||
at about column 150. Opening braces can be put on the same or next line
|
||||
as the statement opening the block (if, switch, for, while, do).
|
||||
Put the opening brace on its own line for larger blocks, especially
|
||||
blocks that contains blank lines. Remove trailing whitespace on sight.
|
||||
|
||||
Otherwise stick to the `Linux Kernel Coding Style`_.
|
||||
|
||||
.. _Linux Kernel Coding Style: https://www.kernel.org/doc/Documentation/process/coding-style.rst
|
||||
|
||||
Pull requests (PRs)
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you are working on something to add to Yosys, or fix something that isn't
|
||||
working quite right,
|
||||
make a `pull request (PR)`_.
|
||||
|
||||
An open PR, even as a draft, tells everyone that you're working on it and they
|
||||
don't have to. It can also be a useful way to solicit feedback on in-progress
|
||||
changes.
|
||||
|
||||
We use `labels`_ to help categorise
|
||||
issues and PRs. If a label seems relevant to your work, please do add it; this
|
||||
also includes the labels beginning with 'status-'. The 'merge-' labels are used
|
||||
by maintainers for tracking and communicating which PRs are ready and pending
|
||||
merge; please do not use these labels if you are not a maintainer.
|
||||
|
||||
.. _`pull request (PR)`: https://github.com/YosysHQ/yosys/pulls
|
||||
.. _`labels`: https://github.com/YosysHQ/yosys/labels
|
||||
|
||||
Git style
|
||||
~~~~~~~~~
|
||||
|
||||
We don't have a strict commit message style.
|
||||
|
||||
Some style hints:
|
||||
|
||||
* Refactor and document existing code if you touch it,
|
||||
but in separate commits from your functional changes
|
||||
* Prefer smaller commits organized by good chunks. Git has a lot of features
|
||||
like fixup commits, interactive rebase with autosquash
|
||||
|
||||
Reviewing PRs
|
||||
-------------
|
||||
|
||||
Reviewing PRs is a totally valid form of external contributing to the project!
|
||||
|
||||
Who's the reviewer?
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
YosysHQ GmbH is a company with a mandate to make decisions for the good
|
||||
of YosysHQ open source software. It was co-founded by Claire Xenia Wolf,
|
||||
the original author of Yosys.
|
||||
Within it, we allocate reviews based on expertise with the topic at hand
|
||||
as well as member time constraints. However, decisions including reviews
|
||||
are also contributed by people external to the company.
|
||||
|
||||
If you're intimately acquainted with a part of the codebase, we will be happy
|
||||
to defer to your experience and have you review PRs. The official way we like
|
||||
is our CODEOWNERS file in the git repository. What we're looking for in code
|
||||
owners is activity and trust. For activity, if you're only interested in
|
||||
a yosys pass for example for the time you spend writing a thesis, it might be
|
||||
better to focus on writing good tests and docs in the PRs you submit rather than
|
||||
to commit to code ownership and therefore to be responsible for fixing things
|
||||
and reviewing other people's PRs at various unexpected points later. If you're
|
||||
prolific in some part of the codebase and not a code owner, we still value your
|
||||
experience and may tag you in PRs.
|
||||
|
||||
As a matter of fact, the purpose of code ownership is to avoid maintainer
|
||||
burnout by removing orphaned parts of the codebase. If you become a code owner
|
||||
and stop being responsive, in the future, we might decide to remove such code
|
||||
if convenient and costly to maintain. It's simply more respectful of the users'
|
||||
time to explicitly cut something out than let it "bitrot". Larger projects like
|
||||
LLVM or linux could not survive without such things, but Yosys is far smaller,
|
||||
and there are implicit expectations of stability we aim to
|
||||
respect within reason.
|
||||
|
||||
.. TODO this deserves its own section elsewhere I think? But it would be distracting elsewhere
|
||||
|
||||
Sometimes, multiple maintainers may add review comments. This is considered
|
||||
healthy collaborative even if it might create disagreement at times. If
|
||||
somebody is already reviewing a PR, others, even non-maintainers are free to
|
||||
leave comments with extra observations and alternate perspectives in a
|
||||
collaborative spirit.
|
||||
|
||||
How to review
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
First, read everything above about contributing. Those are the values you
|
||||
should gently enforce as a reviewer. They're ordered by importance, but
|
||||
explicitly, descriptions are more important than code, long-form comments
|
||||
describing the design are more important than piecemeal comments, etc.
|
||||
|
||||
If a PR is poorly described, incomplete, tests are broken, or if the
|
||||
author is not responding, please don't feel pressured to take over their
|
||||
role by reverse engineering the code or fixing things for them, unless
|
||||
there are good reasons to do so.
|
||||
|
||||
If a PR author submits LLM outputs they haven't understood themselves,
|
||||
they will not be able to implement feedback. Take this into consideration
|
||||
as well. We do not ban LLM code from the codebase, we ban bad code.
|
||||
|
||||
Reviewers may have diverse styles of communication while reviewing - one
|
||||
may do one thorough review, another may prefer a back and forth with the
|
||||
basics out the way before digging into the code. Generally, PRs may have
|
||||
several requests for modifications and long discussions, but often
|
||||
they just are good enough to merge as-is.
|
||||
|
||||
The CI is required to go green for merging. New contributors need a CI
|
||||
run to be triggered by a maintainer before their PRs take up computing
|
||||
resources. It's a single click from the github web interface.
|
||||
We test on various platforms and compilers. Sanitizer builds are only
|
||||
tested on the main branch.
|
||||
|
|
|
|||
|
|
@ -230,8 +230,7 @@ Use ``log_error()`` to report a non-recoverable error:
|
|||
.. code:: C++
|
||||
|
||||
if (design->modules.count(module->name) != 0)
|
||||
log_error("A module with the name %s already exists!\n",
|
||||
RTLIL::id2cstr(module->name));
|
||||
log_error("A module with the name %s already exists!\n", module);
|
||||
|
||||
Use ``log_cmd_error()`` to report a recoverable error:
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ pointer ``f`` to the output file, or stdout if none is given.
|
|||
|
||||
For this minimal example all we are doing is printing out each node. The
|
||||
``node.name()`` method returns an ``RTLIL::IdString``, which we convert for
|
||||
printing with ``id2cstr()``. Then, to print the function of the node, we use
|
||||
printing with ``unescape()``. Then, to print the function of the node, we use
|
||||
``node.to_string()`` which gives us a string of the form ``function(args)``. The
|
||||
``function`` part is the result of ``Functional::IR::fn_to_string(node.fn())``;
|
||||
while ``args`` is the zero or more arguments passed to the function, most
|
||||
|
|
|
|||
|
|
@ -8,7 +8,44 @@ Running the included test suite
|
|||
|
||||
The Yosys source comes with a test suite to avoid regressions and keep
|
||||
everything working as expected. Tests can be run by calling ``make test`` from
|
||||
the root Yosys directory.
|
||||
the root Yosys directory. By default, this runs vanilla and unit tests.
|
||||
|
||||
Vanilla tests
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
These make up the majority of our testing coverage.
|
||||
They can be run with ``make vanilla-test`` and are based on calls to
|
||||
make subcommands (``make makefile-tests``) and shell scripts
|
||||
(``make seed-tests`` and ``make abcopt-tests``). Both use ``run-test.sh``
|
||||
files, but make-based tests only call ``tests/gen-tests-makefile.sh``
|
||||
to generate a makefile appropriate for the given directory, so only
|
||||
afterwards when make is invoked do the tests actually run.
|
||||
|
||||
Usually their structure looks something like this:
|
||||
you write a .ys file that gets automatically run,
|
||||
which runs a frontend like ``read_verilog`` or ``read_rtlil`` with
|
||||
a relative path or a heredoc, then runs some commands including the command
|
||||
under test, and then uses :doc:`/using_yosys/more_scripting/selections`
|
||||
with ``-assert-count``. Usually it's unnecessary to "register" the test anywhere
|
||||
as if it's being added to an existing directory, depending
|
||||
on how the ``run-test.sh`` in that directory works.
|
||||
|
||||
Unit tests
|
||||
~~~~~~~~~~
|
||||
|
||||
Running the unit tests requires the following additional packages:
|
||||
|
||||
.. tab:: Ubuntu
|
||||
|
||||
.. code:: console
|
||||
|
||||
sudo apt-get install libgtest-dev
|
||||
|
||||
.. tab:: macOS
|
||||
|
||||
No additional requirements.
|
||||
|
||||
Unit tests can be run with ``make unit-test``.
|
||||
|
||||
Functional tests
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
@ -41,23 +78,6 @@ instructions <https://github.com/Z3Prover/z3>`_.
|
|||
Then, set the :makevar:`ENABLE_FUNCTIONAL_TESTS` make variable when calling
|
||||
``make test`` and the functional tests will be run as well.
|
||||
|
||||
Unit tests
|
||||
~~~~~~~~~~
|
||||
|
||||
Running the unit tests requires the following additional packages:
|
||||
|
||||
.. tab:: Ubuntu
|
||||
|
||||
.. code:: console
|
||||
|
||||
sudo apt-get install libgtest-dev
|
||||
|
||||
.. tab:: macOS
|
||||
|
||||
No additional requirements.
|
||||
|
||||
Unit tests can be run with ``make unit-test``.
|
||||
|
||||
Docs tests
|
||||
~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ wide range of real-world designs, including the `OpenRISC 1200 CPU`_, the
|
|||
|
||||
.. _k68 CPU: http://opencores.org/projects/k68
|
||||
|
||||
Yosys is written in C++, targeting C++17 at minimum. This chapter describes some
|
||||
Yosys is written in C++, targeting C++20 at minimum. This chapter describes some
|
||||
of the fundamental Yosys data structures. For the sake of simplicity the C++
|
||||
type names used in the Yosys implementation are used in this chapter, even
|
||||
though the chapter only explains the conceptual idea behind it and can be used
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ in the PATH. E.g. extract the release to /usr/local/libexec/super_prove
|
|||
and then create a /usr/local/bin/super_prove file with the following
|
||||
contents (and "chmod +x" that file):
|
||||
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
exec /usr/local/libexec/super_prove/bin/super_prove.sh "$@"
|
||||
|
||||
The "demo.sh" script also expects the "z3" SMT2 solver in the PATH for
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
yosys -p '
|
||||
read_verilog -formal demo.v
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
yosys demo.ys
|
||||
$TD_HOME/bin/td build.tcl
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
yosys run_yosys.ys
|
||||
vivado -nolog -nojournal -mode batch -source run_vivado.tcl
|
||||
vivado -nolog -nojournal -mode batch -source run_prog.tcl
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ struct ScopeinfoExamplePass : public Pass {
|
|||
|
||||
if (do_wires) {
|
||||
for (auto module : design->selected_modules()) {
|
||||
log("Source hierarchy for all selected wires within %s:\n", log_id(module));
|
||||
log("Source hierarchy for all selected wires within %s:\n", module);
|
||||
ModuleHdlnameIndex index(module);
|
||||
|
||||
index.index_scopeinfo_cells();
|
||||
|
|
@ -73,11 +73,11 @@ struct ScopeinfoExamplePass : public Pass {
|
|||
auto wire_scope = index.containing_scope(wire);
|
||||
|
||||
if (!wire_scope.first.valid()) {
|
||||
log_warning("Couldn't find containing scope for %s in index\n", log_id(wire));
|
||||
log_warning("Couldn't find containing scope for %s in index\n", wire);
|
||||
continue;
|
||||
}
|
||||
|
||||
log("%s %s\n", wire_scope.first.path_str(), log_id(wire_scope.second));
|
||||
log("%s %s\n", wire_scope.first.path_str(), wire_scope.second.unescape());
|
||||
for (auto src : index.sources(wire))
|
||||
log(" - %s\n", src);
|
||||
}
|
||||
|
|
@ -127,9 +127,9 @@ struct ScopeinfoExamplePass : public Pass {
|
|||
continue;
|
||||
|
||||
log("common_ancestor(%s %s%s%s, %s %s%s%s) = %s %s\n",
|
||||
log_id(module), scope_i.first.path_str().c_str(), scope_i.first.is_root() ? "" : " ", log_id(scope_i.second),
|
||||
log_id(module), scope_j.first.path_str().c_str(), scope_j.first.is_root() ? "" : " ", log_id(scope_j.second),
|
||||
log_id(module), common.path_str().c_str()
|
||||
module, scope_i.first.path_str().c_str(), scope_i.first.is_root() ? "" : " ", scope_i.second.unescape(),
|
||||
module, scope_j.first.path_str().c_str(), scope_j.first.is_root() ? "" : " ", scope_j.second.unescape(),
|
||||
module, common.path_str().c_str()
|
||||
);
|
||||
|
||||
if (++limit == 10)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v
|
||||
$GOWIN_HOME/bin/gowin -d demo_syn.v -cst demo.cst -sdc demo.sdc -p GW1NR-9-QFN88-6 -pn GW1NR-LV9QN88C6/I5 -cfg device.cfg -bit -tr -ph -timing -gpa -rpt -warning_all
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
|
||||
export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export REV="de2i"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
iverilog -D POST_IMPL -o verif_post -s tb_top tb_top.v top.vqm $(yosys-config --datdir/altera_intel/max10/cells_comb_max10.v)
|
||||
vvp -N verif_post
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
#!/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
yosys -p "synth_intel -family cycloneiv -top lfsr_updown -vqm top.vqm" lfsr_updown.v
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
#!/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
yosys -p "synth_intel -family max10 -top lfsr_updown -vqm top.vqm" lfsr_updown.v
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
iverilog -D POST_IMPL -o verif_post -s tb lfsr_updown_tb.v top.vqm $(yosys-config --datdir/altera_intel/max10/cells_comb_max10.v)
|
||||
vvp -N verif_post
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
iverilog -o presynth lfsr_updown_tb.v lfsr_updown.v &&\
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
yosys run_yosys.ys
|
||||
edif2ngd example.edif
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "aigerparse.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
|
@ -224,7 +224,7 @@ AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString
|
|||
module = new RTLIL::Module;
|
||||
module->name = module_name;
|
||||
if (design->module(module->name))
|
||||
log_error("Duplicate definition of module %s!\n", log_id(module->name));
|
||||
log_error("Duplicate definition of module %s!\n", module->name.unescape());
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger()
|
||||
|
|
@ -286,10 +286,15 @@ end_of_header:
|
|||
|
||||
RTLIL::IdString escaped_s = stringf("\\%s", s);
|
||||
RTLIL::Wire* wire;
|
||||
if (c == 'i') wire = inputs[l1];
|
||||
else if (c == 'l') wire = latches[l1];
|
||||
else if (c == 'o') {
|
||||
if (c == 'i') {
|
||||
log_assert(l1 < inputs.size());
|
||||
wire = inputs[l1];
|
||||
} else if (c == 'l') {
|
||||
log_assert(l1 < latches.size());
|
||||
wire = latches[l1];
|
||||
} else if (c == 'o') {
|
||||
wire = module->wire(escaped_s);
|
||||
log_assert(l1 < outputs.size());
|
||||
if (wire) {
|
||||
// Could have been renamed by a latch
|
||||
module->swap_names(wire, outputs[l1]);
|
||||
|
|
@ -297,9 +302,9 @@ end_of_header:
|
|||
goto next;
|
||||
}
|
||||
wire = outputs[l1];
|
||||
}
|
||||
else if (c == 'b') wire = bad_properties[l1];
|
||||
else log_abort();
|
||||
} else if (c == 'b') {
|
||||
wire = bad_properties[l1];
|
||||
} else log_abort();
|
||||
|
||||
module->rename(wire, escaped_s);
|
||||
}
|
||||
|
|
@ -652,6 +657,9 @@ void AigerReader::parse_aiger_binary()
|
|||
unsigned l1, l2, l3;
|
||||
std::string line;
|
||||
|
||||
if (M != I + L + A)
|
||||
log_error("Binary AIGER input is malformed: maximum variable index M is %u, but number of inputs, latches and AND gates adds up to %u.\n", M, I + L + A);
|
||||
|
||||
// Parse inputs
|
||||
int digits = decimal_digits(I);
|
||||
for (unsigned i = 1; i <= I; ++i) {
|
||||
|
|
@ -813,7 +821,7 @@ void AigerReader::post_process()
|
|||
RTLIL::Wire* wire = inputs[variable];
|
||||
log_assert(wire);
|
||||
log_assert(wire->port_input);
|
||||
log_debug("Renaming input %s", log_id(wire));
|
||||
log_debug("Renaming input %s", wire);
|
||||
|
||||
RTLIL::Wire *existing = nullptr;
|
||||
if (index == 0) {
|
||||
|
|
@ -827,7 +835,7 @@ void AigerReader::post_process()
|
|||
wire->port_input = false;
|
||||
module->connect(wire, existing);
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(escaped_s));
|
||||
log_debug(" -> %s\n", escaped_s.unescape());
|
||||
}
|
||||
else {
|
||||
RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s, index);
|
||||
|
|
@ -838,7 +846,7 @@ void AigerReader::post_process()
|
|||
module->connect(wire, existing);
|
||||
wire->port_input = false;
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(indexed_name));
|
||||
log_debug(" -> %s\n", indexed_name.unescape());
|
||||
}
|
||||
|
||||
if (wideports && !existing) {
|
||||
|
|
@ -858,7 +866,7 @@ void AigerReader::post_process()
|
|||
RTLIL::Wire* wire = outputs[variable + co_count];
|
||||
log_assert(wire);
|
||||
log_assert(wire->port_output);
|
||||
log_debug("Renaming output %s", log_id(wire));
|
||||
log_debug("Renaming output %s", wire);
|
||||
|
||||
RTLIL::Wire *existing;
|
||||
if (index == 0) {
|
||||
|
|
@ -874,7 +882,7 @@ void AigerReader::post_process()
|
|||
module->connect(wire, existing);
|
||||
wire = existing;
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(escaped_s));
|
||||
log_debug(" -> %s\n", escaped_s.unescape());
|
||||
}
|
||||
else {
|
||||
RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s, index);
|
||||
|
|
@ -886,7 +894,7 @@ void AigerReader::post_process()
|
|||
existing->port_output = true;
|
||||
module->connect(wire, existing);
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(indexed_name));
|
||||
log_debug(" -> %s\n", indexed_name.unescape());
|
||||
}
|
||||
|
||||
if (wideports && !existing) {
|
||||
|
|
@ -904,7 +912,7 @@ void AigerReader::post_process()
|
|||
else if (type == "box") {
|
||||
RTLIL::Cell* cell = module->cell(stringf("$box%d", variable));
|
||||
if (!cell)
|
||||
log_debug("Box %d (%s) no longer exists.\n", variable, log_id(escaped_s));
|
||||
log_debug("Box %d (%s) no longer exists.\n", variable, escaped_s.unescape());
|
||||
else
|
||||
module->rename(cell, escaped_s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,13 +80,13 @@ struct Xaiger2Frontend : public Frontend {
|
|||
extra_args(f, filename, args, argidx, true);
|
||||
|
||||
if (map_filename.empty())
|
||||
log_error("A '-map2' argument required\n");
|
||||
log_error("A '-map2' argument is required\n");
|
||||
if (module_name.empty())
|
||||
log_error("A '-module_name' argument required\n");
|
||||
log_error("A '-module_name' argument is required\n");
|
||||
|
||||
Module *module = design->module(module_name);
|
||||
if (!module)
|
||||
log_error("Module '%s' not found\n", log_id(module_name));
|
||||
log_error("Module '%s' not found\n", module_name.unescape());
|
||||
|
||||
std::ifstream map_file;
|
||||
map_file.open(map_filename);
|
||||
|
|
@ -110,7 +110,8 @@ struct Xaiger2Frontend : public Frontend {
|
|||
for (int i = 0; i < (int) O; i++) {
|
||||
int po;
|
||||
*f >> po;
|
||||
log_assert(f->get() == '\n');
|
||||
int c = f->get();
|
||||
log_assert(c == '\n');
|
||||
outputs.push_back(po);
|
||||
}
|
||||
|
||||
|
|
@ -127,10 +128,10 @@ struct Xaiger2Frontend : public Frontend {
|
|||
int woffset;
|
||||
std::string name;
|
||||
if (!(map_file >> pi_idx >> woffset >> name))
|
||||
log_error("Bad map file (1)\n");
|
||||
log_error("Bad map file: couldn't read 'pi' line\n");
|
||||
int lit = (2 * pi_idx) + 2;
|
||||
if (lit < 0 || lit >= (int) bits.size())
|
||||
log_error("Bad map file (2)\n");
|
||||
log_error("Bad map file: primary input literal out of range\n");
|
||||
Wire *w = module->wire(name);
|
||||
if (!w || woffset < 0 || woffset >= w->width)
|
||||
log_error("Map file references non-existent signal bit %s[%d]\n",
|
||||
|
|
@ -140,9 +141,9 @@ struct Xaiger2Frontend : public Frontend {
|
|||
int box_seq;
|
||||
std::string name;
|
||||
if (!(map_file >> box_seq >> name))
|
||||
log_error("Bad map file (20)\n");
|
||||
log_error("Bad map file: couldn't read 'box' line\n");
|
||||
if (box_seq < 0)
|
||||
log_error("Bad map file (21)\n");
|
||||
log_error("Bad map file: box out of range\n");
|
||||
|
||||
Cell *box = module->cell(RTLIL::escape_id(name));
|
||||
if (!box)
|
||||
|
|
@ -157,7 +158,7 @@ struct Xaiger2Frontend : public Frontend {
|
|||
}
|
||||
|
||||
if (!def)
|
||||
log_error("Bad map file (22)\n");
|
||||
log_error("Bad map file: no module found for box type '%s'\n", box->type.unescape());
|
||||
|
||||
if (box_seq >= (int) boxes.size()) {
|
||||
boxes.resize(box_seq + 1);
|
||||
|
|
@ -275,9 +276,9 @@ struct Xaiger2Frontend : public Frontend {
|
|||
uint32_t nins = read_be32(*f);
|
||||
for (uint32_t j = 0; j < nins; j++)
|
||||
cell.ins.push_back(read_idstring(*f));
|
||||
log_debug("M: Cell %s (out %s, ins", log_id(cell.type), log_id(cell.out));
|
||||
log_debug("M: Cell %s (out %s, ins", cell.type.unescape(), cell.out.unescape());
|
||||
for (auto in : cell.ins)
|
||||
log_debug(" %s", log_id(in));
|
||||
log_debug(" %s", in.unescape());
|
||||
log_debug(")\n");
|
||||
}
|
||||
|
||||
|
|
@ -402,15 +403,15 @@ struct Xaiger2Frontend : public Frontend {
|
|||
int woffset;
|
||||
std::string name;
|
||||
if (!(map_file >> po_idx >> woffset >> name))
|
||||
log_error("Bad map file (3)\n");
|
||||
log_error("Bad map file: couldn't read 'po' line\n");
|
||||
po_idx += co_counter;
|
||||
if (po_idx < 0 || po_idx >= (int) outputs.size())
|
||||
log_error("Bad map file (4)\n");
|
||||
log_error("Bad map file: primary output index out of range\n");
|
||||
int lit = outputs[po_idx];
|
||||
if (lit < 0 || lit >= (int) bits.size())
|
||||
log_error("Bad map file (5)\n");
|
||||
log_error("Bad map file: primary output literal out of range\n");
|
||||
if (bits[lit] == RTLIL::Sm)
|
||||
log_error("Bad map file (6)\n");
|
||||
log_error("Bad map file: primary output literal is a marker\n");
|
||||
Wire *w = module->wire(name);
|
||||
if (!w || woffset < 0 || woffset >= w->width)
|
||||
log_error("Map file references non-existent signal bit %s[%d]\n",
|
||||
|
|
@ -422,15 +423,15 @@ struct Xaiger2Frontend : public Frontend {
|
|||
std::string box_name;
|
||||
std::string box_port;
|
||||
if (!(map_file >> po_idx >> poffset >> box_name >> box_port))
|
||||
log_error("Bad map file (7)\n");
|
||||
log_error("Bad map file: couldn't read 'pseudopo' line\n");
|
||||
po_idx += co_counter;
|
||||
if (po_idx < 0 || po_idx >= (int) outputs.size())
|
||||
log_error("Bad map file (8)\n");
|
||||
log_error("Bad map file: pseudo primary output index out of range\n");
|
||||
int lit = outputs[po_idx];
|
||||
if (lit < 0 || lit >= (int) bits.size())
|
||||
log_error("Bad map file (9)\n");
|
||||
log_error("Bad map file: pseudo primary output literal out of range\n");
|
||||
if (bits[lit] == RTLIL::Sm)
|
||||
log_error("Bad map file (10)\n");
|
||||
log_error("Bad map file: pseudo primary output literal is a marker\n");
|
||||
Cell *cell = module->cell(box_name);
|
||||
if (!cell || !cell->hasPort(box_port))
|
||||
log_error("Map file references non-existent box port %s/%s\n",
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ std::string AST::type2str(AstNodeType type)
|
|||
X(AST_CAST_SIZE)
|
||||
X(AST_CONCAT)
|
||||
X(AST_REPLICATE)
|
||||
X(AST_ASSIGN_PATTERN)
|
||||
X(AST_BIT_NOT)
|
||||
X(AST_BIT_AND)
|
||||
X(AST_BIT_OR)
|
||||
|
|
@ -696,6 +697,16 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
fprintf(f, "}}");
|
||||
break;
|
||||
|
||||
case AST_ASSIGN_PATTERN:
|
||||
fprintf(f, "'{");
|
||||
for (int i = 0; i < GetSize(children); i++) {
|
||||
if (i != 0)
|
||||
fprintf(f, ", ");
|
||||
children[i]->dumpVlog(f, "");
|
||||
}
|
||||
fprintf(f, "}");
|
||||
break;
|
||||
|
||||
if (0) { case AST_BIT_NOT: txt = "~"; }
|
||||
if (0) { case AST_REDUCE_AND: txt = "&"; }
|
||||
if (0) { case AST_REDUCE_OR: txt = "|"; }
|
||||
|
|
@ -993,6 +1004,8 @@ RTLIL::Const AstNode::asParaConst() const
|
|||
RTLIL::Const val = asAttrConst();
|
||||
if (is_signed)
|
||||
val.flags |= RTLIL::CONST_FLAG_SIGNED;
|
||||
if (is_unsized)
|
||||
val.flags |= RTLIL::CONST_FLAG_UNSIZED;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
@ -1531,7 +1544,7 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
|
|||
for (auto w : intfmodule->wires()){
|
||||
auto loc = module_ast->location;
|
||||
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
|
||||
std::string origname = log_id(w->name);
|
||||
std::string origname = w->name.unescape();
|
||||
std::string newname = intfname + "." + origname;
|
||||
wire->str = newname;
|
||||
if (modport != NULL) {
|
||||
|
|
@ -1571,7 +1584,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design)
|
|||
continue;
|
||||
if (design->module(modname) || design->module("$abstract" + modname)) {
|
||||
log("Reprocessing module %s because instantiated module %s has become available.\n",
|
||||
log_id(name), log_id(modname));
|
||||
name.unescape(), RTLIL::unescape_id(modname));
|
||||
loadconfig();
|
||||
process_and_replace_module(design, this, ast.get(), NULL);
|
||||
return true;
|
||||
|
|
@ -1593,7 +1606,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
RTLIL::Module *intfmodule = intf.second;
|
||||
for (auto w : intfmodule->wires()){
|
||||
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
|
||||
std::string newname = log_id(w->name);
|
||||
std::string newname = w->name.unescape();
|
||||
newname = intfname + "." + newname;
|
||||
wire->str = newname;
|
||||
new_ast->children.push_back(std::move(wire));
|
||||
|
|
@ -1666,7 +1679,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
|
||||
bool has_interfaces = false;
|
||||
for(auto &intf : interfaces) {
|
||||
interf_info += log_id(intf.second->name);
|
||||
interf_info += intf.second->name.unescape();
|
||||
has_interfaces = true;
|
||||
}
|
||||
|
||||
|
|
@ -1722,7 +1735,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
new_subcell->set_bool_attribute(ID::is_interface);
|
||||
}
|
||||
else {
|
||||
log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname);
|
||||
log_error("No port with matching name found (%s) in %s. Stopping\n", intf.first, modname);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1766,7 +1779,10 @@ static std::string serialize_param_value(const RTLIL::Const &val) {
|
|||
res.push_back('s');
|
||||
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_REAL)
|
||||
res.push_back('r');
|
||||
res += stringf("%d", GetSize(val));
|
||||
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_UNSIZED)
|
||||
res.push_back('u');
|
||||
else
|
||||
res += stringf("%d", GetSize(val));
|
||||
res.push_back('\'');
|
||||
res.append(val.as_string("?"));
|
||||
return res;
|
||||
|
|
@ -1860,7 +1876,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
|
|||
} else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0)
|
||||
child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string());
|
||||
else
|
||||
child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
|
||||
child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0, (it->second.flags & RTLIL::CONST_FLAG_UNSIZED) != 0);
|
||||
rewritten.insert(it->first);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ namespace AST
|
|||
AST_CAST_SIZE,
|
||||
AST_CONCAT,
|
||||
AST_REPLICATE,
|
||||
AST_ASSIGN_PATTERN,
|
||||
AST_BIT_NOT,
|
||||
AST_BIT_AND,
|
||||
AST_BIT_OR,
|
||||
|
|
|
|||
|
|
@ -342,6 +342,9 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
// The most recently assigned $print or $check cell \PRIORITY.
|
||||
int last_effect_priority;
|
||||
|
||||
// Track which signals have been assigned in current_case to avoid unnecessary removeSignalFromCaseTree calls
|
||||
pool<RTLIL::SigBit> current_case_assigned_bits;
|
||||
|
||||
ProcessGenerator(std::unique_ptr<AstNode> a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
|
||||
{
|
||||
// rewrite lookahead references
|
||||
|
|
@ -403,6 +406,18 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
if (GetSize(syncrule->signal) != 1)
|
||||
always->input_error("Found posedge/negedge event on a signal that is not 1 bit wide!\n");
|
||||
addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
|
||||
// Automatic (nosync) variables must not become flip-flops: remove
|
||||
// them from clocked sync rules so that proc_dff does not infer
|
||||
// an unnecessary register for a purely combinational temporary.
|
||||
syncrule->actions.erase(
|
||||
std::remove_if(syncrule->actions.begin(), syncrule->actions.end(),
|
||||
[](const RTLIL::SigSig &ss) {
|
||||
for (auto &chunk : ss.first.chunks())
|
||||
if (chunk.wire && chunk.wire->get_bool_attribute(ID::nosync))
|
||||
return true;
|
||||
return false;
|
||||
}),
|
||||
syncrule->actions.end());
|
||||
proc->syncs.push_back(syncrule);
|
||||
}
|
||||
if (proc->syncs.empty()) {
|
||||
|
|
@ -418,6 +433,10 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
|
||||
} else {
|
||||
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
|
||||
// Track initial assignments
|
||||
for (auto &bit : subst_lvalue_to)
|
||||
if (bit.wire != NULL)
|
||||
current_case_assigned_bits.insert(bit);
|
||||
}
|
||||
|
||||
// process the AST
|
||||
|
|
@ -545,14 +564,42 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
|
||||
// function is called to clean up the first two assignments as they are overwritten by
|
||||
// the third assignment.
|
||||
void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)
|
||||
void removeSignalFromCaseTree(const pool<RTLIL::SigBit> &pattern_bits, RTLIL::CaseRule *cs)
|
||||
{
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
|
||||
it->first.remove2(pattern, &it->second);
|
||||
// Optimization: check actions in reverse order and stop early if we've found all pattern bits
|
||||
pool<RTLIL::SigBit> remaining_bits = pattern_bits;
|
||||
|
||||
for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ++it) {
|
||||
bool has_pattern = false;
|
||||
for (auto &bit : it->first) {
|
||||
if (bit.wire != NULL && remaining_bits.count(bit)) {
|
||||
has_pattern = true;
|
||||
remaining_bits.erase(bit);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_pattern) {
|
||||
it->first.remove2(pattern_bits, &it->second);
|
||||
}
|
||||
|
||||
// Early exit if we've processed all bits in pattern
|
||||
if (remaining_bits.empty())
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
|
||||
for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
|
||||
removeSignalFromCaseTree(pattern, *it2);
|
||||
removeSignalFromCaseTree(pattern_bits, *it2);
|
||||
}
|
||||
|
||||
void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)
|
||||
{
|
||||
pool<RTLIL::SigBit> pattern_bits;
|
||||
pattern_bits.reserve(pattern.size());
|
||||
for (auto &bit : pattern)
|
||||
if (bit.wire != NULL)
|
||||
pattern_bits.insert(bit);
|
||||
removeSignalFromCaseTree(pattern_bits, cs);
|
||||
}
|
||||
|
||||
// add an assignment (aka "action") but split it up in chunks. this way huge assignments
|
||||
|
|
@ -611,7 +658,23 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
|
||||
}
|
||||
|
||||
removeSignalFromCaseTree(lvalue, current_case);
|
||||
// Check if any bits in lvalue have been assigned before in current_case
|
||||
bool has_overlap = false;
|
||||
for (auto &bit : lvalue) {
|
||||
if (bit.wire != NULL && current_case_assigned_bits.count(bit)) {
|
||||
has_overlap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_overlap)
|
||||
removeSignalFromCaseTree(lvalue, current_case);
|
||||
|
||||
// Track newly assigned bits
|
||||
for (auto &bit : lvalue)
|
||||
if (bit.wire != NULL)
|
||||
current_case_assigned_bits.insert(bit);
|
||||
|
||||
remove_unwanted_lvalue_bits(lvalue, rvalue);
|
||||
current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
|
||||
}
|
||||
|
|
@ -658,9 +721,15 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
RTLIL::CaseRule *backup_case = current_case;
|
||||
current_case = new RTLIL::CaseRule;
|
||||
pool<RTLIL::SigBit> backup_assigned_bits = std::move(current_case_assigned_bits);
|
||||
current_case_assigned_bits.clear();
|
||||
set_src_attr(current_case, child.get());
|
||||
last_generated_case = current_case;
|
||||
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
|
||||
// Track temp assignments
|
||||
for (auto &bit : this_case_eq_ltemp)
|
||||
if (bit.wire != NULL)
|
||||
current_case_assigned_bits.insert(bit);
|
||||
for (auto& node : child->children) {
|
||||
if (node->type == AST_DEFAULT)
|
||||
default_case = current_case;
|
||||
|
|
@ -674,6 +743,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
else
|
||||
log_assert(current_case->compare.size() == 0);
|
||||
current_case = backup_case;
|
||||
current_case_assigned_bits = std::move(backup_assigned_bits);
|
||||
|
||||
subst_lvalue_map.restore();
|
||||
subst_rvalue_map.restore();
|
||||
|
|
@ -702,8 +772,24 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
|
||||
|
||||
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
|
||||
removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
|
||||
|
||||
// Check if any bits in lvalue have been assigned before in current_case
|
||||
bool has_overlap = false;
|
||||
for (auto &bit : this_case_eq_lvalue) {
|
||||
if (bit.wire != NULL && current_case_assigned_bits.count(bit)) {
|
||||
has_overlap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_overlap)
|
||||
removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
|
||||
|
||||
addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
|
||||
// Track newly assigned bits
|
||||
for (auto &bit : this_case_eq_lvalue)
|
||||
if (bit.wire != NULL)
|
||||
current_case_assigned_bits.insert(bit);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -712,7 +798,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
break;
|
||||
|
||||
case AST_ASSIGN:
|
||||
ast->input_error("Found continous assignment in always/initial block!\n");
|
||||
ast->input_error("Found continuous assignment in always/initial block!\n");
|
||||
break;
|
||||
|
||||
case AST_PARAMETER:
|
||||
|
|
@ -844,6 +930,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
RTLIL::Cell *cell = current_module->addCell(cellname, ID($check));
|
||||
set_src_attr(cell, ast);
|
||||
cell->set_bool_attribute(ID(keep));
|
||||
for (auto &attr : ast->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first);
|
||||
|
|
@ -1125,6 +1212,15 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
sign_hint = false;
|
||||
break;
|
||||
|
||||
case AST_ASSIGN_PATTERN:
|
||||
for (auto& child : children) {
|
||||
sub_width_hint = 0;
|
||||
sub_sign_hint = true;
|
||||
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
|
||||
}
|
||||
sign_hint = false;
|
||||
break;
|
||||
|
||||
case AST_NEG:
|
||||
case AST_BIT_NOT:
|
||||
case AST_POS:
|
||||
|
|
@ -1737,6 +1833,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
return sig;
|
||||
}
|
||||
|
||||
case AST_ASSIGN_PATTERN:
|
||||
input_error("Assignment pattern is only supported for whole unpacked array assignments.\n");
|
||||
|
||||
// generate cells for unary operations: $not, $pos, $neg
|
||||
if (0) { case AST_BIT_NOT: type_name = ID($not); }
|
||||
if (0) { case AST_POS: type_name = ID($pos); }
|
||||
|
|
@ -2084,8 +2183,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
check_unique_id(current_module, id, this, "cell");
|
||||
RTLIL::Cell *cell = current_module->addCell(id, "");
|
||||
set_src_attr(cell, this);
|
||||
// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
|
||||
cell->set_bool_attribute(ID::module_not_derived);
|
||||
|
||||
for (auto it = children.begin(); it != children.end(); it++) {
|
||||
auto* child = it->get();
|
||||
|
|
@ -2100,10 +2197,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
const auto* value = child->children[0].get();
|
||||
if (value->type == AST_REALVALUE)
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n",
|
||||
log_id(cell), log_id(paraname), value->realvalue);
|
||||
cell, paraname.unescape(), value->realvalue);
|
||||
else if (value->type != AST_CONSTANT)
|
||||
input_error("Parameter %s.%s with non-constant value!\n",
|
||||
log_id(cell), log_id(paraname));
|
||||
cell, paraname.unescape());
|
||||
cell->parameters[paraname] = value->asParaConst();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2148,6 +2245,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
log_abort();
|
||||
}
|
||||
|
||||
// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
|
||||
if (cell->type.isPublic())
|
||||
cell->set_bool_attribute(ID::module_not_derived);
|
||||
|
||||
for (auto &attr : attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
input_error("Attribute `%s' with non-constant value.\n", attr.first);
|
||||
|
|
|
|||
|
|
@ -91,6 +91,11 @@ void AstNode::fixup_hierarchy_flags(bool force_descend)
|
|||
children[0]->set_in_param_flag(true, force_descend);
|
||||
break;
|
||||
|
||||
case AST_ASSIGN_PATTERN:
|
||||
for (auto& child : children)
|
||||
child->set_in_param_flag(in_param, force_descend);
|
||||
break;
|
||||
|
||||
case AST_GENFOR:
|
||||
case AST_FOR:
|
||||
for (auto& child : children) {
|
||||
|
|
@ -269,6 +274,100 @@ static int add_dimension(AstNode *node, AstNode *rnode)
|
|||
node->input_error("Unpacked array in packed struct/union member %s\n", node->str);
|
||||
}
|
||||
|
||||
// Check if node is an unexpanded array reference (AST_IDENTIFIER -> AST_MEMORY without indexing)
|
||||
static bool is_unexpanded_array_ref(AstNode *node)
|
||||
{
|
||||
if (node->type != AST_IDENTIFIER)
|
||||
return false;
|
||||
if (node->id2ast == nullptr || node->id2ast->type != AST_MEMORY)
|
||||
return false;
|
||||
// No indexing children = whole array reference
|
||||
return node->children.empty();
|
||||
}
|
||||
|
||||
// Check if two memories have compatible unpacked dimensions for array assignment
|
||||
static bool arrays_have_compatible_dims(AstNode *mem_a, AstNode *mem_b)
|
||||
{
|
||||
if (mem_a->unpacked_dimensions != mem_b->unpacked_dimensions)
|
||||
return false;
|
||||
for (int i = 0; i < mem_a->unpacked_dimensions; i++) {
|
||||
if (mem_a->dimensions[i].range_width != mem_b->dimensions[i].range_width)
|
||||
return false;
|
||||
}
|
||||
// Also check packed dimensions (element width)
|
||||
int a_width, a_size, a_bits;
|
||||
int b_width, b_size, b_bits;
|
||||
mem_a->meminfo(a_width, a_size, a_bits);
|
||||
mem_b->meminfo(b_width, b_size, b_bits);
|
||||
return a_width == b_width;
|
||||
}
|
||||
|
||||
// Check if mem_b matches mem_a's unpacked dimensions starting at first_dim.
|
||||
static bool arrays_have_compatible_dims_from(AstNode *mem_a, int first_dim, AstNode *mem_b)
|
||||
{
|
||||
if (mem_b->unpacked_dimensions != mem_a->unpacked_dimensions - first_dim)
|
||||
return false;
|
||||
for (int i = 0; i < mem_b->unpacked_dimensions; i++) {
|
||||
if (mem_a->dimensions[first_dim + i].range_width != mem_b->dimensions[i].range_width)
|
||||
return false;
|
||||
}
|
||||
// Also check packed dimensions (element width)
|
||||
int a_width, a_size, a_bits;
|
||||
int b_width, b_size, b_bits;
|
||||
mem_a->meminfo(a_width, a_size, a_bits);
|
||||
mem_b->meminfo(b_width, b_size, b_bits);
|
||||
return a_width == b_width;
|
||||
}
|
||||
|
||||
// Convert per-dimension element positions to declared index values.
|
||||
// Position 0 is the first declared element for each unpacked dimension.
|
||||
static std::vector<int> array_indices_from_position(AstNode *mem, const std::vector<int> &position)
|
||||
{
|
||||
int num_dims = mem->unpacked_dimensions;
|
||||
log_assert(GetSize(position) == num_dims);
|
||||
|
||||
std::vector<int> indices(num_dims);
|
||||
for (int d = 0; d < num_dims; d++) {
|
||||
int low = mem->dimensions[d].range_right;
|
||||
int high = low + mem->dimensions[d].range_width - 1;
|
||||
indices[d] = mem->dimensions[d].range_swapped ? (low + position[d]) : (high - position[d]);
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
// Generate all element positions for a multi-dimensional unpacked array and
|
||||
// call callback once for each combination.
|
||||
static void foreach_array_position(AstNode *mem, std::function<void(const std::vector<int>&)> callback)
|
||||
{
|
||||
int num_dims = mem->unpacked_dimensions;
|
||||
if (num_dims == 0) {
|
||||
callback({});
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int> position(num_dims, 0);
|
||||
std::vector<int> sizes(num_dims);
|
||||
|
||||
for (int d = 0; d < num_dims; d++)
|
||||
sizes[d] = mem->dimensions[d].range_width;
|
||||
|
||||
// Iterate through all position combinations (rightmost dimension fastest).
|
||||
while (true) {
|
||||
callback(position);
|
||||
|
||||
int d = num_dims - 1;
|
||||
while (d >= 0) {
|
||||
position[d]++;
|
||||
if (position[d] < sizes[d])
|
||||
break;
|
||||
position[d] = 0;
|
||||
d--;
|
||||
}
|
||||
if (d < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int size_packed_struct(AstNode *snode, int base_offset)
|
||||
{
|
||||
// Struct members will be laid out in the structure contiguously from left to right.
|
||||
|
|
@ -879,7 +978,7 @@ static void check_auto_nosync(AstNode *node)
|
|||
}
|
||||
|
||||
// remove the attributes we've "consumed"
|
||||
for (const RTLIL::IdString &str : attrs_to_drop) {
|
||||
for (RTLIL::IdString str : attrs_to_drop) {
|
||||
auto it = node->attributes.find(str);
|
||||
node->attributes.erase(it);
|
||||
}
|
||||
|
|
@ -1393,7 +1492,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
|||
const RTLIL::Wire *ref = module->wire(port_name);
|
||||
if (ref == nullptr)
|
||||
input_error("Cell instance refers to port %s which does not exist in module %s!.\n",
|
||||
log_id(port_name), log_id(module->name));
|
||||
port_name.unescape(), module->name.unescape());
|
||||
|
||||
// select the argument, if present
|
||||
log_assert(child->children.size() <= 1);
|
||||
|
|
@ -1653,6 +1752,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
|||
children_are_self_determined = true;
|
||||
break;
|
||||
|
||||
case AST_ASSIGN_PATTERN:
|
||||
// Assignment pattern elements are context-determined by the target element type.
|
||||
// Keep child width context intact until whole-array assignment expansion creates scalar assignments.
|
||||
detect_width_simple = true;
|
||||
break;
|
||||
|
||||
case AST_NEG:
|
||||
case AST_BIT_NOT:
|
||||
case AST_POS:
|
||||
|
|
@ -2265,9 +2370,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
|||
}
|
||||
if (children[0]->type == AST_CONSTANT) {
|
||||
if (width != int(children[0]->bits.size())) {
|
||||
RTLIL::SigSpec sig(children[0]->bits);
|
||||
sig.extend_u0(width, children[0]->is_signed);
|
||||
children[0] = mkconst_bits(location, sig.as_const().to_bits(), is_signed);
|
||||
RTLIL::Const val;
|
||||
if (children[0]->is_unsized) {
|
||||
val = children[0]->bitsAsUnsizedConst(width);
|
||||
} else {
|
||||
val = children[0]->bitsAsConst(width);
|
||||
}
|
||||
children[0] = mkconst_bits(location, val.to_bits(), is_signed);
|
||||
fixup_hierarchy_flags();
|
||||
}
|
||||
children[0]->is_signed = is_signed;
|
||||
|
|
@ -3141,7 +3250,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
if (stage > 1 && type == AST_IDENTIFIER && id2ast != nullptr && id2ast->type == AST_MEMORY && !in_lvalue &&
|
||||
children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
|
||||
if (integer < (unsigned)id2ast->unpacked_dimensions)
|
||||
input_error("Insufficient number of array indices for %s.\n", log_id(str));
|
||||
input_error("Insufficient number of array indices for %s.\n", RTLIL::unescape_id(str));
|
||||
newNode = std::make_unique<AstNode>(location, AST_MEMRD, children[0]->children[0]->clone());
|
||||
newNode->str = str;
|
||||
newNode->id2ast = id2ast;
|
||||
|
|
@ -3196,6 +3305,217 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
}
|
||||
}
|
||||
|
||||
// Expand array assignment: arr_out = arr_in OR arr_out = cond ? arr_a : arr_b OR arr_out = '{a, b}
|
||||
// Supports multi-dimensional unpacked arrays
|
||||
if ((type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE || type == AST_ASSIGN) &&
|
||||
is_unexpanded_array_ref(children[0].get()))
|
||||
{
|
||||
AstNode *lhs = children[0].get();
|
||||
AstNode *rhs = children[1].get();
|
||||
AstNode *lhs_mem = lhs->id2ast;
|
||||
|
||||
// Case 1: Direct array assignment (b = a)
|
||||
bool is_direct_assign = is_unexpanded_array_ref(rhs);
|
||||
|
||||
// Case 2: Ternary array assignment (out = sel ? a : b)
|
||||
bool is_ternary_assign = (rhs->type == AST_TERNARY &&
|
||||
is_unexpanded_array_ref(rhs->children[1].get()) &&
|
||||
is_unexpanded_array_ref(rhs->children[2].get()));
|
||||
|
||||
// Case 3: Positional assignment pattern (out = '{a, b})
|
||||
bool is_pattern_assign = rhs->type == AST_ASSIGN_PATTERN;
|
||||
|
||||
if (is_direct_assign || is_ternary_assign || is_pattern_assign)
|
||||
{
|
||||
AstNode *direct_rhs_mem = nullptr;
|
||||
AstNode *true_mem = nullptr;
|
||||
AstNode *false_mem = nullptr;
|
||||
|
||||
int num_dims = lhs_mem->unpacked_dimensions;
|
||||
int total_elements = 1;
|
||||
for (int d = 0; d < num_dims; d++)
|
||||
total_elements *= lhs_mem->dimensions[d].range_width;
|
||||
int element_width, mem_size, addr_bits;
|
||||
lhs_mem->meminfo(element_width, mem_size, addr_bits);
|
||||
bool pattern_is_flat = false;
|
||||
|
||||
// Helper to add indices to an array identifier clone.
|
||||
auto add_indices_to_id = [&](std::unique_ptr<AstNode> id, const std::vector<int>& indices) {
|
||||
int indexed_dims = GetSize(indices);
|
||||
if (indexed_dims == 1) {
|
||||
// Single dimension: use AST_RANGE
|
||||
id->children.push_back(std::make_unique<AstNode>(location, AST_RANGE,
|
||||
mkconst_int(location, indices[0], true)));
|
||||
} else {
|
||||
// Multiple dimensions: use AST_MULTIRANGE
|
||||
auto multirange = std::make_unique<AstNode>(location, AST_MULTIRANGE);
|
||||
for (int idx : indices) {
|
||||
multirange->children.push_back(std::make_unique<AstNode>(location, AST_RANGE,
|
||||
mkconst_int(location, idx, true)));
|
||||
}
|
||||
id->children.push_back(std::move(multirange));
|
||||
}
|
||||
id->integer = indexed_dims;
|
||||
// Reset basic_prep so multirange gets resolved during subsequent simplify passes
|
||||
id->basic_prep = false;
|
||||
return id;
|
||||
};
|
||||
|
||||
auto add_position_to_id = [&](std::unique_ptr<AstNode> id, AstNode *mem, const std::vector<int>& position) {
|
||||
return add_indices_to_id(std::move(id), array_indices_from_position(mem, position));
|
||||
};
|
||||
|
||||
// Validate nested assignment pattern shape against unpacked dimensions.
|
||||
std::function<void(AstNode*, int)> validate_pattern_shape = [&](AstNode *pattern, int dim) {
|
||||
log_assert(pattern->type == AST_ASSIGN_PATTERN);
|
||||
|
||||
int expected = lhs_mem->dimensions[dim].range_width;
|
||||
if (GetSize(pattern->children) != expected)
|
||||
input_error("Assignment pattern element count mismatch at dimension %d: got %d, expected %d\n",
|
||||
dim + 1, GetSize(pattern->children), expected);
|
||||
|
||||
if (dim + 1 == num_dims)
|
||||
return;
|
||||
|
||||
for (auto& child : pattern->children) {
|
||||
if (child->type == AST_ASSIGN_PATTERN) {
|
||||
validate_pattern_shape(child.get(), dim + 1);
|
||||
} else if (is_unexpanded_array_ref(child.get()) &&
|
||||
arrays_have_compatible_dims_from(lhs_mem, dim + 1, child->id2ast)) {
|
||||
continue;
|
||||
} else {
|
||||
input_error("Nested assignment pattern or compatible array expression required for dimension %d\n", dim + 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Select the assignment pattern element for an unpacked array position.
|
||||
auto pattern_element_at_position = [&](const std::vector<int>& position, int flat_index) {
|
||||
if (pattern_is_flat)
|
||||
return rhs->children[flat_index]->clone();
|
||||
|
||||
AstNode *pattern = rhs;
|
||||
for (int d = 0; d < num_dims; d++) {
|
||||
log_assert(pattern->type == AST_ASSIGN_PATTERN);
|
||||
AstNode *element = pattern->children[position[d]].get();
|
||||
|
||||
if (d + 1 == num_dims)
|
||||
return element->clone();
|
||||
|
||||
if (element->type == AST_ASSIGN_PATTERN) {
|
||||
pattern = element;
|
||||
} else {
|
||||
std::vector<int> subposition(position.begin() + d + 1, position.end());
|
||||
return add_position_to_id(element->clone(), element->id2ast, subposition);
|
||||
}
|
||||
}
|
||||
log_abort();
|
||||
};
|
||||
|
||||
// Validate array compatibility
|
||||
if (is_direct_assign) {
|
||||
direct_rhs_mem = rhs->id2ast;
|
||||
if (!arrays_have_compatible_dims(lhs_mem, direct_rhs_mem))
|
||||
input_error("Array dimension mismatch in assignment\n");
|
||||
} else if (is_ternary_assign) {
|
||||
true_mem = rhs->children[1]->id2ast;
|
||||
false_mem = rhs->children[2]->id2ast;
|
||||
if (!arrays_have_compatible_dims(lhs_mem, true_mem) ||
|
||||
!arrays_have_compatible_dims(lhs_mem, false_mem))
|
||||
input_error("Array dimension mismatch in ternary expression\n");
|
||||
} else {
|
||||
if (num_dims > 1 && GetSize(rhs->children) == lhs_mem->dimensions[0].range_width) {
|
||||
validate_pattern_shape(rhs, 0);
|
||||
} else if (num_dims == 1 && GetSize(rhs->children) == total_elements) {
|
||||
pattern_is_flat = true;
|
||||
} else {
|
||||
if (num_dims > 1 && GetSize(rhs->children) == lhs_mem->dimensions[0].range_width)
|
||||
validate_pattern_shape(rhs, 0);
|
||||
int expected = num_dims > 1 ? lhs_mem->dimensions[0].range_width : total_elements;
|
||||
input_error("Assignment pattern element count mismatch: got %d, expected %d\n", GetSize(rhs->children), expected);
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if array assignment expansion is large.
|
||||
if (total_elements > 10000)
|
||||
log_warning("Expanding array assignment with %d elements at %s, this may be slow.\n",
|
||||
total_elements, location.to_string().c_str());
|
||||
|
||||
// Collect all assignments
|
||||
std::vector<std::unique_ptr<AstNode>> assignments;
|
||||
std::vector<std::unique_ptr<AstNode>> pattern_temp_assignments;
|
||||
|
||||
foreach_array_position(lhs_mem, [&](const std::vector<int>& position) {
|
||||
auto lhs_idx = add_position_to_id(lhs->clone(), lhs_mem, position);
|
||||
|
||||
std::unique_ptr<AstNode> rhs_expr;
|
||||
if (is_direct_assign) {
|
||||
rhs_expr = add_position_to_id(rhs->clone(), direct_rhs_mem, position);
|
||||
} else if (is_ternary_assign) {
|
||||
// Ternary case
|
||||
AstNode *cond = rhs->children[0].get();
|
||||
AstNode *true_val = rhs->children[1].get();
|
||||
AstNode *false_val = rhs->children[2].get();
|
||||
|
||||
auto true_idx = add_position_to_id(true_val->clone(), true_mem, position);
|
||||
auto false_idx = add_position_to_id(false_val->clone(), false_mem, position);
|
||||
|
||||
rhs_expr = std::make_unique<AstNode>(location, AST_TERNARY,
|
||||
cond->clone(), std::move(true_idx), std::move(false_idx));
|
||||
} else {
|
||||
auto pattern_rhs = pattern_element_at_position(position, GetSize(assignments));
|
||||
|
||||
if (type == AST_ASSIGN_EQ) {
|
||||
auto wire_tmp_owned = std::make_unique<AstNode>(location, AST_WIRE,
|
||||
std::make_unique<AstNode>(location, AST_RANGE,
|
||||
mkconst_int(location, element_width - 1, true),
|
||||
mkconst_int(location, 0, true)));
|
||||
auto wire_tmp = wire_tmp_owned.get();
|
||||
wire_tmp->str = stringf("$assignpattern$%s:%d$%d",
|
||||
RTLIL::encode_filename(*location.begin.filename), location.begin.line, autoidx++);
|
||||
current_scope[wire_tmp->str] = wire_tmp;
|
||||
current_ast_mod->children.push_back(std::move(wire_tmp_owned));
|
||||
wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false));
|
||||
while (wire_tmp->simplify(true, 1, -1, false)) { }
|
||||
wire_tmp->is_logic = true;
|
||||
wire_tmp->is_signed = lhs_mem->is_signed;
|
||||
|
||||
auto tmp_id = std::make_unique<AstNode>(location, AST_IDENTIFIER);
|
||||
tmp_id->str = wire_tmp->str;
|
||||
pattern_temp_assignments.push_back(std::make_unique<AstNode>(location, AST_ASSIGN_EQ,
|
||||
tmp_id->clone(), std::move(pattern_rhs)));
|
||||
rhs_expr = std::move(tmp_id);
|
||||
} else {
|
||||
rhs_expr = std::move(pattern_rhs);
|
||||
}
|
||||
}
|
||||
|
||||
auto assign = std::make_unique<AstNode>(location, type,
|
||||
std::move(lhs_idx), std::move(rhs_expr));
|
||||
assign->was_checked = true;
|
||||
assignments.push_back(std::move(assign));
|
||||
});
|
||||
|
||||
// For continuous assignments, add to module; for procedural, use block
|
||||
if (type == AST_ASSIGN) {
|
||||
// Add all but last to module
|
||||
for (size_t i = 0; i + 1 < assignments.size(); i++)
|
||||
current_ast_mod->children.push_back(std::move(assignments[i]));
|
||||
// Last one replaces current node
|
||||
newNode = std::move(assignments.back());
|
||||
} else {
|
||||
// Wrap in AST_BLOCK for procedural
|
||||
newNode = std::make_unique<AstNode>(location, AST_BLOCK);
|
||||
for (auto& assign : pattern_temp_assignments)
|
||||
newNode->children.push_back(std::move(assign));
|
||||
for (auto& assign : assignments)
|
||||
newNode->children.push_back(std::move(assign));
|
||||
}
|
||||
|
||||
goto apply_newNode;
|
||||
}
|
||||
}
|
||||
|
||||
// assignment with memory in left-hand side expression -> replace with memory write port
|
||||
if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER &&
|
||||
children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 &&
|
||||
|
|
@ -3203,7 +3523,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
(children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE)
|
||||
{
|
||||
if (children[0]->integer < (unsigned)children[0]->id2ast->unpacked_dimensions)
|
||||
input_error("Insufficient number of array indices for %s.\n", log_id(str));
|
||||
input_error("Insufficient number of array indices for %s.\n", RTLIL::unescape_id(str));
|
||||
|
||||
std::stringstream sstr;
|
||||
sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
|
||||
|
|
@ -4454,6 +4774,8 @@ replace_fcall_later:;
|
|||
tmp_bits.insert(tmp_bits.end(), children.at(1)->bits.begin(), children.at(1)->bits.end());
|
||||
newNode = children.at(1)->is_string ? mkconst_str(location, tmp_bits) : mkconst_bits(location, tmp_bits, false);
|
||||
break;
|
||||
case AST_ASSIGN_PATTERN:
|
||||
goto not_const;
|
||||
default:
|
||||
not_const:
|
||||
break;
|
||||
|
|
@ -4686,6 +5008,7 @@ void AstNode::expand_genblock(const std::string &prefix)
|
|||
|
||||
switch (child->type) {
|
||||
case AST_WIRE:
|
||||
case AST_AUTOWIRE:
|
||||
case AST_MEMORY:
|
||||
case AST_STRUCT:
|
||||
case AST_UNION:
|
||||
|
|
@ -4714,6 +5037,93 @@ void AstNode::expand_genblock(const std::string &prefix)
|
|||
}
|
||||
break;
|
||||
|
||||
case AST_IDENTIFIER:
|
||||
if (!child->str.empty() && prefix.size() > 0) {
|
||||
bool is_resolved = false;
|
||||
std::string identifier_str = child->str;
|
||||
if (current_ast_mod != nullptr && identifier_str.compare(0, current_ast_mod->str.size(), current_ast_mod->str) == 0) {
|
||||
if (identifier_str.at(current_ast_mod->str.size()) == '.') {
|
||||
identifier_str = '\\' + identifier_str.substr(current_ast_mod->str.size()+1, identifier_str.size());
|
||||
}
|
||||
}
|
||||
// search starting in the innermost scope and then stepping outward
|
||||
for (size_t ppos = prefix.size() - 1; ppos; --ppos) {
|
||||
if (prefix.at(ppos) != '.') continue;
|
||||
|
||||
std::string new_prefix = prefix.substr(0, ppos + 1);
|
||||
auto attempt_resolve = [&new_prefix](const std::string &ident) -> std::string {
|
||||
std::string new_name = prefix_id(new_prefix, ident);
|
||||
if (current_scope.count(new_name))
|
||||
return new_name;
|
||||
return {};
|
||||
};
|
||||
|
||||
// attempt to resolve the full identifier
|
||||
std::string resolved = attempt_resolve(identifier_str);
|
||||
if (!resolved.empty()) {
|
||||
is_resolved = true;
|
||||
break;
|
||||
}
|
||||
// attempt to resolve hierarchical prefixes within the identifier,
|
||||
// as the prefix could refer to a local scope which exists but
|
||||
// hasn't yet been elaborated
|
||||
for (size_t spos = identifier_str.size() - 1; spos; --spos) {
|
||||
if (identifier_str.at(spos) != '.') continue;
|
||||
resolved = attempt_resolve(identifier_str.substr(0, spos));
|
||||
if (!resolved.empty()) {
|
||||
is_resolved = true;
|
||||
identifier_str = resolved + identifier_str.substr(spos);
|
||||
ppos = 1; // break outer loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (current_scope.count(identifier_str) == 0) {
|
||||
AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
|
||||
for (auto& node : current_scope_ast->children) {
|
||||
switch (node->type) {
|
||||
case AST_PARAMETER:
|
||||
case AST_LOCALPARAM:
|
||||
case AST_WIRE:
|
||||
case AST_AUTOWIRE:
|
||||
case AST_GENVAR:
|
||||
case AST_MEMORY:
|
||||
case AST_FUNCTION:
|
||||
case AST_TASK:
|
||||
case AST_DPI_FUNCTION:
|
||||
if (prefix_id(new_prefix, identifier_str) == node->str) {
|
||||
is_resolved = true;
|
||||
current_scope[node->str] = node.get();
|
||||
}
|
||||
break;
|
||||
case AST_ENUM:
|
||||
current_scope[node->str] = node.get();
|
||||
for (auto& enum_node : node->children) {
|
||||
log_assert(enum_node->type==AST_ENUM_ITEM);
|
||||
if (prefix_id(new_prefix, identifier_str) == enum_node->str) {
|
||||
is_resolved = true;
|
||||
current_scope[enum_node->str] = enum_node.get();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((current_scope.count(identifier_str) == 0) && is_resolved == false) {
|
||||
if (current_ast_mod == nullptr) {
|
||||
input_error("Identifier `%s' is implicitly declared outside of a module.\n", child->str.c_str());
|
||||
} else if (flag_autowire || identifier_str == "\\$global_clock") {
|
||||
auto auto_wire = std::make_unique<AstNode>(child->location, AST_AUTOWIRE);
|
||||
auto_wire->str = identifier_str;
|
||||
children.push_back(std::move(auto_wire));
|
||||
} else {
|
||||
input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", identifier_str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -4863,7 +5273,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
|
|||
AstNode *mem = id2ast;
|
||||
|
||||
if (integer < (unsigned)mem->unpacked_dimensions)
|
||||
input_error("Insufficient number of array indices for %s.\n", log_id(str));
|
||||
input_error("Insufficient number of array indices for %s.\n", RTLIL::unescape_id(str));
|
||||
|
||||
// flag if used after blocking assignment (in same proc)
|
||||
if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) {
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
|
|||
obj_attributes = &module->attributes;
|
||||
obj_parameters = nullptr;
|
||||
if (design->module(module->name))
|
||||
log_error("Duplicate definition of module %s in line %d!\n", log_id(module->name), line_count);
|
||||
log_error("Duplicate definition of module %s in line %d!\n", module->name.unescape(), line_count);
|
||||
design->add(module);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
|
|||
if (undef_wire != nullptr)
|
||||
module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum));
|
||||
|
||||
autoidx = std::max(autoidx, blif_maxnum+1);
|
||||
autoidx.ensure_at_least(blif_maxnum+1);
|
||||
blif_maxnum = 0;
|
||||
}
|
||||
|
||||
|
|
@ -470,6 +470,27 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, ".gateinit"))
|
||||
{
|
||||
char *p = strtok(NULL, " \t\r\n");
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
|
||||
char *n = strtok(p, "=");
|
||||
char *init = strtok(NULL, "=");
|
||||
if (n == NULL || init == NULL)
|
||||
goto error;
|
||||
if (init[0] != '0' && init[0] != '1')
|
||||
goto error;
|
||||
|
||||
if (blif_wire(n)->attributes.find(ID::init) == blif_wire(n)->attributes.end())
|
||||
blif_wire(n)->attributes.emplace(ID::init, Const(init[0] == '1' ? 1 : 0, 1));
|
||||
else
|
||||
blif_wire(n)->attributes[ID::init] = Const(init[0] == '1' ? 1 : 0, 1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, ".names"))
|
||||
{
|
||||
char *p;
|
||||
|
|
@ -608,6 +629,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
|
|||
goto try_next_value;
|
||||
}
|
||||
}
|
||||
log_assert(i < lutptr->size());
|
||||
lutptr->set(i, !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1);
|
||||
try_next_value:;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,13 +295,16 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
module->name = RTLIL::escape_id(modname.c_str());
|
||||
|
||||
if (design->module(module->name))
|
||||
log_error("Re-definition of module %s.\n", log_id(module->name));
|
||||
log_error("Re-definition of module %s.\n", module->name.unescape());
|
||||
|
||||
design->add(module);
|
||||
|
||||
if (node->data_dict.count("attributes"))
|
||||
json_parse_attr_param(module->attributes, node->data_dict.at("attributes"));
|
||||
|
||||
if (node->data_dict.count("parameter_default_values"))
|
||||
json_parse_attr_param(module->parameter_default_values, node->data_dict.at("parameter_default_values"));
|
||||
|
||||
dict<int, SigBit> signal_bits;
|
||||
|
||||
if (node->data_dict.count("ports"))
|
||||
|
|
@ -317,22 +320,22 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
JsonNode *port_node = ports_node->data_dict.at(ports_node->data_dict_keys[port_id-1]);
|
||||
|
||||
if (port_node->type != 'D')
|
||||
log_error("JSON port node '%s' is not a dictionary.\n", log_id(port_name));
|
||||
log_error("JSON port node '%s' is not a dictionary.\n", port_name.unescape());
|
||||
|
||||
if (port_node->data_dict.count("direction") == 0)
|
||||
log_error("JSON port node '%s' has no direction attribute.\n", log_id(port_name));
|
||||
log_error("JSON port node '%s' has no direction attribute.\n", port_name.unescape());
|
||||
|
||||
if (port_node->data_dict.count("bits") == 0)
|
||||
log_error("JSON port node '%s' has no bits attribute.\n", log_id(port_name));
|
||||
log_error("JSON port node '%s' has no bits attribute.\n", port_name.unescape());
|
||||
|
||||
JsonNode *port_direction_node = port_node->data_dict.at("direction");
|
||||
JsonNode *port_bits_node = port_node->data_dict.at("bits");
|
||||
|
||||
if (port_direction_node->type != 'S')
|
||||
log_error("JSON port node '%s' has non-string direction attribute.\n", log_id(port_name));
|
||||
log_error("JSON port node '%s' has non-string direction attribute.\n", port_name.unescape());
|
||||
|
||||
if (port_bits_node->type != 'A')
|
||||
log_error("JSON port node '%s' has non-array bits attribute.\n", log_id(port_name));
|
||||
log_error("JSON port node '%s' has non-array bits attribute.\n", port_name.unescape());
|
||||
|
||||
Wire *port_wire = module->wire(port_name);
|
||||
|
||||
|
|
@ -367,7 +370,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
port_wire->port_input = true;
|
||||
port_wire->port_output = true;
|
||||
} else
|
||||
log_error("JSON port node '%s' has invalid '%s' direction attribute.\n", log_id(port_name), port_direction_node->data_string);
|
||||
log_error("JSON port node '%s' has invalid '%s' direction attribute.\n", port_name.unescape(), port_direction_node->data_string);
|
||||
|
||||
port_wire->port_id = port_id;
|
||||
|
||||
|
|
@ -387,7 +390,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
module->connect(sigbit, State::Sz);
|
||||
else
|
||||
log_error("JSON port node '%s' has invalid '%s' bit string value on bit %d.\n",
|
||||
log_id(port_name), bitval_node->data_string.c_str(), i);
|
||||
port_name.unescape(), bitval_node->data_string.c_str(), i);
|
||||
} else
|
||||
if (bitval_node->type == 'N') {
|
||||
int bitidx = bitval_node->data_number;
|
||||
|
|
@ -402,7 +405,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
signal_bits[bitidx] = sigbit;
|
||||
}
|
||||
} else
|
||||
log_error("JSON port node '%s' has invalid bit value on bit %d.\n", log_id(port_name), i);
|
||||
log_error("JSON port node '%s' has invalid bit value on bit %d.\n", port_name.unescape(), i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -422,15 +425,15 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
JsonNode *net_node = net.second;
|
||||
|
||||
if (net_node->type != 'D')
|
||||
log_error("JSON netname node '%s' is not a dictionary.\n", log_id(net_name));
|
||||
log_error("JSON netname node '%s' is not a dictionary.\n", net_name.unescape());
|
||||
|
||||
if (net_node->data_dict.count("bits") == 0)
|
||||
log_error("JSON netname node '%s' has no bits attribute.\n", log_id(net_name));
|
||||
log_error("JSON netname node '%s' has no bits attribute.\n", net_name.unescape());
|
||||
|
||||
JsonNode *bits_node = net_node->data_dict.at("bits");
|
||||
|
||||
if (bits_node->type != 'A')
|
||||
log_error("JSON netname node '%s' has non-array bits attribute.\n", log_id(net_name));
|
||||
log_error("JSON netname node '%s' has non-array bits attribute.\n", net_name.unescape());
|
||||
|
||||
Wire *wire = module->wire(net_name);
|
||||
|
||||
|
|
@ -465,7 +468,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
module->connect(sigbit, State::Sz);
|
||||
else
|
||||
log_error("JSON netname node '%s' has invalid '%s' bit string value on bit %d.\n",
|
||||
log_id(net_name), bitval_node->data_string.c_str(), i);
|
||||
net_name.unescape(), bitval_node->data_string.c_str(), i);
|
||||
} else
|
||||
if (bitval_node->type == 'N') {
|
||||
int bitidx = bitval_node->data_number;
|
||||
|
|
@ -476,7 +479,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
signal_bits[bitidx] = sigbit;
|
||||
}
|
||||
} else
|
||||
log_error("JSON netname node '%s' has invalid bit value on bit %d.\n", log_id(net_name), i);
|
||||
log_error("JSON netname node '%s' has invalid bit value on bit %d.\n", net_name.unescape(), i);
|
||||
}
|
||||
|
||||
if (net_node->data_dict.count("attributes"))
|
||||
|
|
@ -497,27 +500,27 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
JsonNode *cell_node = cell_node_it.second;
|
||||
|
||||
if (cell_node->type != 'D')
|
||||
log_error("JSON cells node '%s' is not a dictionary.\n", log_id(cell_name));
|
||||
log_error("JSON cells node '%s' is not a dictionary.\n", cell_name.unescape());
|
||||
|
||||
if (cell_node->data_dict.count("type") == 0)
|
||||
log_error("JSON cells node '%s' has no type attribute.\n", log_id(cell_name));
|
||||
log_error("JSON cells node '%s' has no type attribute.\n", cell_name.unescape());
|
||||
|
||||
JsonNode *type_node = cell_node->data_dict.at("type");
|
||||
|
||||
if (type_node->type != 'S')
|
||||
log_error("JSON cells node '%s' has a non-string type.\n", log_id(cell_name));
|
||||
log_error("JSON cells node '%s' has a non-string type.\n", cell_name.unescape());
|
||||
|
||||
IdString cell_type = RTLIL::escape_id(type_node->data_string.c_str());
|
||||
|
||||
Cell *cell = module->addCell(cell_name, cell_type);
|
||||
|
||||
if (cell_node->data_dict.count("connections") == 0)
|
||||
log_error("JSON cells node '%s' has no connections attribute.\n", log_id(cell_name));
|
||||
log_error("JSON cells node '%s' has no connections attribute.\n", cell_name.unescape());
|
||||
|
||||
JsonNode *connections_node = cell_node->data_dict.at("connections");
|
||||
|
||||
if (connections_node->type != 'D')
|
||||
log_error("JSON cells node '%s' has non-dictionary connections attribute.\n", log_id(cell_name));
|
||||
log_error("JSON cells node '%s' has non-dictionary connections attribute.\n", cell_name.unescape());
|
||||
|
||||
for (auto &conn_it : connections_node->data_dict)
|
||||
{
|
||||
|
|
@ -525,7 +528,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
JsonNode *conn_node = conn_it.second;
|
||||
|
||||
if (conn_node->type != 'A')
|
||||
log_error("JSON cells node '%s' connection '%s' is not an array.\n", log_id(cell_name), log_id(conn_name));
|
||||
log_error("JSON cells node '%s' connection '%s' is not an array.\n", cell_name.unescape(), conn_name.unescape());
|
||||
|
||||
SigSpec sig;
|
||||
|
||||
|
|
@ -544,7 +547,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
sig.append(State::Sz);
|
||||
else
|
||||
log_error("JSON cells node '%s' connection '%s' has invalid '%s' bit string value on bit %d.\n",
|
||||
log_id(cell_name), log_id(conn_name), bitval_node->data_string.c_str(), i);
|
||||
cell_name.unescape(), conn_name.unescape(), bitval_node->data_string.c_str(), i);
|
||||
} else
|
||||
if (bitval_node->type == 'N') {
|
||||
int bitidx = bitval_node->data_number;
|
||||
|
|
@ -553,7 +556,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
sig.append(signal_bits.at(bitidx));
|
||||
} else
|
||||
log_error("JSON cells node '%s' connection '%s' has invalid bit value on bit %d.\n",
|
||||
log_id(cell_name), log_id(conn_name), i);
|
||||
cell_name.unescape(), conn_name.unescape(), i);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -584,20 +587,20 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
mem->name = memory_name;
|
||||
|
||||
if (memory_node->type != 'D')
|
||||
log_error("JSON memory node '%s' is not a dictionary.\n", log_id(memory_name));
|
||||
log_error("JSON memory node '%s' is not a dictionary.\n", memory_name.unescape());
|
||||
|
||||
if (memory_node->data_dict.count("width") == 0)
|
||||
log_error("JSON memory node '%s' has no width attribute.\n", log_id(memory_name));
|
||||
log_error("JSON memory node '%s' has no width attribute.\n", memory_name.unescape());
|
||||
JsonNode *width_node = memory_node->data_dict.at("width");
|
||||
if (width_node->type != 'N')
|
||||
log_error("JSON memory node '%s' has a non-number width.\n", log_id(memory_name));
|
||||
log_error("JSON memory node '%s' has a non-number width.\n", memory_name.unescape());
|
||||
mem->width = width_node->data_number;
|
||||
|
||||
if (memory_node->data_dict.count("size") == 0)
|
||||
log_error("JSON memory node '%s' has no size attribute.\n", log_id(memory_name));
|
||||
log_error("JSON memory node '%s' has no size attribute.\n", memory_name.unescape());
|
||||
JsonNode *size_node = memory_node->data_dict.at("size");
|
||||
if (size_node->type != 'N')
|
||||
log_error("JSON memory node '%s' has a non-number size.\n", log_id(memory_name));
|
||||
log_error("JSON memory node '%s' has a non-number size.\n", memory_name.unescape());
|
||||
mem->size = size_node->data_number;
|
||||
|
||||
mem->start_offset = 0;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "passes/techmap/libparse.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
#include <array>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
|
|
@ -40,14 +41,14 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&
|
|||
expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++;
|
||||
|
||||
if (id_len == 0)
|
||||
log_error("Expected identifier at `%s'.\n", expr);
|
||||
log_error("Expected identifier at `%s' in %s.\n", expr, module);
|
||||
|
||||
if (id_len == 1 && (*expr == '0' || *expr == '1'))
|
||||
return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||
|
||||
std::string id = RTLIL::escape_id(std::string(expr, id_len));
|
||||
if (!module->wires_.count(id))
|
||||
log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id));
|
||||
log_error("Can't resolve wire name %s in %s.\n", RTLIL::unescape_id(id), module);
|
||||
|
||||
expr += id_len;
|
||||
return module->wires_.at(id);
|
||||
|
|
@ -174,7 +175,7 @@ static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
|
|||
#endif
|
||||
|
||||
if (stack.size() != 1 || stack.back().type != 3)
|
||||
log_error("Parser error in function expr `%s'.\n", orig_expr);
|
||||
log_error("Parser error in function expr `%s'in %s.\n", orig_expr, module);
|
||||
|
||||
return stack.back().sig;
|
||||
}
|
||||
|
|
@ -191,14 +192,29 @@ static RTLIL::SigSpec create_tristate(RTLIL::Module *module, RTLIL::SigSpec func
|
|||
return cell->getPort(ID::Y);
|
||||
}
|
||||
|
||||
static void create_latch_ff_wires(RTLIL::Module *module, const LibertyAst *node)
|
||||
{
|
||||
module->addWire(RTLIL::escape_id(node->args.at(0)));
|
||||
module->addWire(RTLIL::escape_id(node->args.at(1)));
|
||||
}
|
||||
|
||||
static std::pair<RTLIL::SigSpec, RTLIL::SigSpec> find_latch_ff_wires(RTLIL::Module *module, const LibertyAst *node)
|
||||
{
|
||||
auto* iq_wire = module->wire(RTLIL::escape_id(node->args.at(0)));
|
||||
auto* iqn_wire = module->wire(RTLIL::escape_id(node->args.at(1)));
|
||||
log_assert(iq_wire && iqn_wire);
|
||||
return std::make_pair(iq_wire, iqn_wire);
|
||||
}
|
||||
|
||||
static void create_ff(RTLIL::Module *module, const LibertyAst *node)
|
||||
{
|
||||
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
|
||||
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
|
||||
|
||||
auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node);
|
||||
RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
|
||||
bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
|
||||
const std::string name = module->name.unescape();
|
||||
|
||||
std::optional<char> clear_preset_var1;
|
||||
std::optional<char> clear_preset_var2;
|
||||
for (auto child : node->children) {
|
||||
if (child->id == "clocked_on")
|
||||
clk_sig = parse_func_expr(module, child->value.c_str());
|
||||
|
|
@ -208,10 +224,18 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node)
|
|||
clear_sig = parse_func_expr(module, child->value.c_str());
|
||||
if (child->id == "preset")
|
||||
preset_sig = parse_func_expr(module, child->value.c_str());
|
||||
|
||||
for (auto& [id, var] : {pair{"clear_preset_var1", &clear_preset_var1}, {"clear_preset_var2", &clear_preset_var2}})
|
||||
if (child->id == id) {
|
||||
if (child->value.size() != 1)
|
||||
log_error("Unexpected length of clear_preset_var* value %s in FF cell %s\n", child->value, name);
|
||||
*var = child->value[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (clk_sig.size() == 0 || data_sig.size() == 0)
|
||||
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name));
|
||||
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", name);
|
||||
|
||||
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
|
||||
{
|
||||
|
|
@ -236,43 +260,69 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node)
|
|||
}
|
||||
}
|
||||
|
||||
RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_NOT_));
|
||||
cell->setPort(ID::A, iq_sig);
|
||||
cell->setPort(ID::Y, iqn_sig);
|
||||
for (auto& [out_sig, cp_var, neg] : {tuple{iq_sig, clear_preset_var1, false}, {iqn_sig, clear_preset_var2, true}}) {
|
||||
SigSpec q_sig = out_sig;
|
||||
if (neg) {
|
||||
q_sig = module->addWire(NEW_ID, out_sig.as_wire());
|
||||
module->addNotGate(NEW_ID, q_sig, out_sig);
|
||||
}
|
||||
|
||||
cell = module->addCell(NEW_ID, "");
|
||||
cell->setPort(ID::D, data_sig);
|
||||
cell->setPort(ID::Q, iq_sig);
|
||||
cell->setPort(ID::C, clk_sig);
|
||||
RTLIL::Cell* cell = module->addCell(NEW_ID, "");
|
||||
cell->setPort(ID::D, data_sig);
|
||||
cell->setPort(ID::Q, q_sig);
|
||||
cell->setPort(ID::C, clk_sig);
|
||||
|
||||
if (clear_sig.size() == 0 && preset_sig.size() == 0) {
|
||||
cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N');
|
||||
if (clear_sig.size() == 0 && preset_sig.size() == 0) {
|
||||
cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N');
|
||||
}
|
||||
|
||||
if (clear_sig.size() == 1 && preset_sig.size() == 0) {
|
||||
cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
|
||||
cell->setPort(ID::R, clear_sig);
|
||||
}
|
||||
|
||||
if (clear_sig.size() == 0 && preset_sig.size() == 1) {
|
||||
cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N');
|
||||
cell->setPort(ID::R, preset_sig);
|
||||
}
|
||||
|
||||
if (clear_sig.size() == 1 && preset_sig.size() == 1) {
|
||||
cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
|
||||
|
||||
SigBit s_sig = preset_sig;
|
||||
SigBit r_sig = clear_sig;
|
||||
if (cp_var && *cp_var != 'X') {
|
||||
// Either set or reset dominates
|
||||
bool set_dominates;
|
||||
if (*cp_var == 'L') {
|
||||
set_dominates = neg;
|
||||
} else if (*cp_var == 'H') {
|
||||
set_dominates = !neg;
|
||||
} else {
|
||||
log_error("FF cell %s has unsupported clear&preset behavior \'%c\'.\n", name, *cp_var);
|
||||
}
|
||||
log_debug("cell %s variable %d cp_var %c set dominates? %d\n", name, (int)neg + 1, *cp_var, set_dominates);
|
||||
// S&R priority is well-defined now
|
||||
if (set_dominates) {
|
||||
r_sig = module->AndnotGate(NEW_ID, r_sig, s_sig);
|
||||
} else {
|
||||
s_sig = module->AndnotGate(NEW_ID, s_sig, r_sig);
|
||||
}
|
||||
} else {
|
||||
log_debug("cell %s variable %d undef c&p behavior\n", name, (int)neg + 1);
|
||||
}
|
||||
|
||||
cell->setPort(ID::S, s_sig);
|
||||
cell->setPort(ID::R, r_sig);
|
||||
}
|
||||
|
||||
log_assert(!cell->type.empty());
|
||||
}
|
||||
|
||||
if (clear_sig.size() == 1 && preset_sig.size() == 0) {
|
||||
cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
|
||||
cell->setPort(ID::R, clear_sig);
|
||||
}
|
||||
|
||||
if (clear_sig.size() == 0 && preset_sig.size() == 1) {
|
||||
cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N');
|
||||
cell->setPort(ID::R, preset_sig);
|
||||
}
|
||||
|
||||
if (clear_sig.size() == 1 && preset_sig.size() == 1) {
|
||||
cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
|
||||
cell->setPort(ID::S, preset_sig);
|
||||
cell->setPort(ID::R, clear_sig);
|
||||
}
|
||||
|
||||
log_assert(!cell->type.empty());
|
||||
}
|
||||
|
||||
static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool flag_ignore_miss_data_latch)
|
||||
{
|
||||
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
|
||||
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
|
||||
|
||||
auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node);
|
||||
RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig;
|
||||
bool enable_polarity = true, clear_polarity = true, preset_polarity = true;
|
||||
|
||||
|
|
@ -289,9 +339,9 @@ static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool fla
|
|||
|
||||
if (enable_sig.size() == 0 || data_sig.size() == 0) {
|
||||
if (!flag_ignore_miss_data_latch)
|
||||
log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
|
||||
log_error("Latch cell %s has no data_in and/or enable attribute.\n", module);
|
||||
else
|
||||
log("Ignored latch cell %s with no data_in and/or enable attribute.\n", log_id(module->name));
|
||||
log("Ignored latch cell %s with no data_in and/or enable attribute.\n", module);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -582,9 +632,9 @@ struct LibertyFrontend : public Frontend {
|
|||
{
|
||||
if (!flag_ignore_miss_dir)
|
||||
{
|
||||
log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0), log_id(module->name));
|
||||
log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0), module);
|
||||
} else {
|
||||
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0));
|
||||
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", module, node->args.at(0));
|
||||
delete module;
|
||||
goto skip_cell;
|
||||
}
|
||||
|
|
@ -596,13 +646,13 @@ struct LibertyFrontend : public Frontend {
|
|||
if (node->id == "bus" && node->args.size() == 1)
|
||||
{
|
||||
if (flag_ignore_buses) {
|
||||
log("Ignoring cell %s with a bus interface %s.\n", log_id(module->name), node->args.at(0));
|
||||
log("Ignoring cell %s with a bus interface %s.\n", module, node->args.at(0));
|
||||
delete module;
|
||||
goto skip_cell;
|
||||
}
|
||||
|
||||
if (!flag_lib)
|
||||
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
|
||||
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", RTLIL::unescape_id(cell_name));
|
||||
|
||||
const LibertyAst *dir = node->find("direction");
|
||||
|
||||
|
|
@ -613,7 +663,7 @@ struct LibertyFrontend : public Frontend {
|
|||
}
|
||||
|
||||
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
|
||||
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0), log_id(module->name));
|
||||
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0), module);
|
||||
|
||||
simple_comb_cell = false;
|
||||
|
||||
|
|
@ -624,7 +674,7 @@ struct LibertyFrontend : public Frontend {
|
|||
|
||||
if (!bus_type_node || !type_map.count(bus_type_node->value))
|
||||
log_error("Unknown or unsupported type for bus interface %s on cell %s.\n",
|
||||
node->args.at(0).c_str(), log_id(cell_name));
|
||||
node->args.at(0).c_str(), RTLIL::unescape_id(cell_name));
|
||||
|
||||
int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
|
||||
int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value));
|
||||
|
|
@ -646,6 +696,13 @@ struct LibertyFrontend : public Frontend {
|
|||
{
|
||||
// some liberty files do not put ff/latch at the beginning of a cell
|
||||
// try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes
|
||||
// but first, in case of balloon retention cells, we need all ff/latch output wires
|
||||
// defined before we add ff/latch cells
|
||||
for (auto node : cell->children)
|
||||
{
|
||||
if ((node->id == "ff" && node->args.size() == 2) || (node->id == "latch" && node->args.size() == 2))
|
||||
create_latch_ff_wires(module, node);
|
||||
}
|
||||
for (auto node : cell->children)
|
||||
{
|
||||
if (node->id == "ff" && node->args.size() == 2)
|
||||
|
|
@ -701,9 +758,9 @@ struct LibertyFrontend : public Frontend {
|
|||
if (dir->value != "inout") { // allow inout with missing function, can be used for power pins
|
||||
if (!flag_ignore_miss_func)
|
||||
{
|
||||
log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name));
|
||||
log_error("Missing function on output %s of cell %s.\n", wire, module);
|
||||
} else {
|
||||
log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name));
|
||||
log("Ignoring cell %s with missing function on output %s.\n", module, wire);
|
||||
delete module;
|
||||
goto skip_cell;
|
||||
}
|
||||
|
|
@ -757,13 +814,13 @@ struct LibertyFrontend : public Frontend {
|
|||
if (design->has(cell_name)) {
|
||||
Module *existing_mod = design->module(cell_name);
|
||||
if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) {
|
||||
log_error("Re-definition of cell/module %s!\n", log_id(cell_name));
|
||||
log_error("Re-definition of cell/module %s!\n", RTLIL::unescape_id(cell_name));
|
||||
} else if (flag_nooverwrite) {
|
||||
log("Ignoring re-definition of module %s.\n", log_id(cell_name));
|
||||
log("Ignoring re-definition of module %s.\n", RTLIL::unescape_id(cell_name));
|
||||
delete module;
|
||||
goto skip_cell;
|
||||
} else {
|
||||
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", log_id(cell_name));
|
||||
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", RTLIL::unescape_id(cell_name));
|
||||
design->remove(existing_mod);
|
||||
}
|
||||
}
|
||||
|
|
@ -780,3 +837,4 @@ skip_cell:;
|
|||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ struct RpcModule : RTLIL::Module {
|
|||
for (auto module : derived_design->modules_) {
|
||||
std::string mangled_name = name_mangling[module.first.str()];
|
||||
|
||||
log("Importing `%s' as `%s'.\n", log_id(module.first), log_id(mangled_name));
|
||||
log("Importing `%s' as `%s'.\n", module.first.unescape(), mangled_name);
|
||||
|
||||
module.second->name = mangled_name;
|
||||
module.second->design = design;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ struct RTLILFrontendWorker {
|
|||
bool flag_nooverwrite = false;
|
||||
bool flag_overwrite = false;
|
||||
bool flag_lib = false;
|
||||
bool flag_legalize = false;
|
||||
|
||||
int line_num;
|
||||
std::string line_buf;
|
||||
|
|
@ -285,6 +286,7 @@ struct RTLILFrontendWorker {
|
|||
if (width > MAX_CONST_WIDTH)
|
||||
error("Constant width %lld out of range before `%s`.", width, error_token());
|
||||
bits.reserve(width);
|
||||
int start_idx = idx;
|
||||
while (true) {
|
||||
RTLIL::State bit;
|
||||
switch (line[idx]) {
|
||||
|
|
@ -299,8 +301,9 @@ struct RTLILFrontendWorker {
|
|||
bits.push_back(bit);
|
||||
++idx;
|
||||
}
|
||||
done:
|
||||
std::reverse(bits.begin(), bits.end());
|
||||
done:
|
||||
if (start_idx < idx)
|
||||
std::reverse(bits.begin(), bits.end());
|
||||
|
||||
if (GetSize(bits) > width)
|
||||
bits.resize(width);
|
||||
|
|
@ -322,6 +325,17 @@ struct RTLILFrontendWorker {
|
|||
return val;
|
||||
}
|
||||
|
||||
RTLIL::Wire *legalize_wire(RTLIL::IdString id)
|
||||
{
|
||||
int wires_size = current_module->wires_size();
|
||||
if (wires_size == 0)
|
||||
error("No wires found for legalization");
|
||||
int hash = hash_ops<RTLIL::IdString>::hash(id).yield();
|
||||
RTLIL::Wire *wire = current_module->wire_at(abs(hash % wires_size));
|
||||
log("Legalizing wire `%s' to `%s'.\n", id.unescape(), wire->name.unescape());
|
||||
return wire;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec parse_sigspec()
|
||||
{
|
||||
RTLIL::SigSpec sig;
|
||||
|
|
@ -339,8 +353,12 @@ struct RTLILFrontendWorker {
|
|||
std::optional<RTLIL::IdString> id = try_parse_id();
|
||||
if (id.has_value()) {
|
||||
RTLIL::Wire *wire = current_module->wire(*id);
|
||||
if (wire == nullptr)
|
||||
error("Wire `%s' not found.", *id);
|
||||
if (wire == nullptr) {
|
||||
if (flag_legalize)
|
||||
wire = legalize_wire(*id);
|
||||
else
|
||||
error("Wire `%s' not found.", *id);
|
||||
}
|
||||
sig = RTLIL::SigSpec(wire);
|
||||
} else {
|
||||
sig = RTLIL::SigSpec(parse_const());
|
||||
|
|
@ -349,17 +367,44 @@ struct RTLILFrontendWorker {
|
|||
|
||||
while (try_parse_char('[')) {
|
||||
int left = parse_integer();
|
||||
if (left >= sig.size() || left < 0)
|
||||
error("bit index %d out of range", left);
|
||||
if (left >= sig.size() || left < 0) {
|
||||
if (flag_legalize) {
|
||||
int legalized;
|
||||
if (sig.size() == 0)
|
||||
legalized = 0;
|
||||
else
|
||||
legalized = std::max(0, std::min(left, sig.size() - 1));
|
||||
log("Legalizing bit index %d to %d.\n", left, legalized);
|
||||
left = legalized;
|
||||
} else {
|
||||
error("bit index %d out of range", left);
|
||||
}
|
||||
}
|
||||
if (try_parse_char(':')) {
|
||||
int right = parse_integer();
|
||||
if (right < 0)
|
||||
error("bit index %d out of range", right);
|
||||
if (left < right)
|
||||
error("invalid slice [%d:%d]", left, right);
|
||||
sig = sig.extract(right, left-right+1);
|
||||
if (right < 0) {
|
||||
if (flag_legalize) {
|
||||
log("Legalizing bit index %d to %d.\n", right, 0);
|
||||
right = 0;
|
||||
} else
|
||||
error("bit index %d out of range", right);
|
||||
}
|
||||
if (left < right) {
|
||||
if (flag_legalize) {
|
||||
log("Legalizing bit index %d to %d.\n", left, right);
|
||||
left = right;
|
||||
} else
|
||||
error("invalid slice [%d:%d]", left, right);
|
||||
}
|
||||
if (flag_legalize && left >= sig.size())
|
||||
log("Legalizing slice %d:%d by igoring it\n", left, right);
|
||||
else
|
||||
sig = sig.extract(right, left - right + 1);
|
||||
} else {
|
||||
sig = sig.extract(left);
|
||||
if (flag_legalize && left >= sig.size())
|
||||
log("Legalizing slice %d by igoring it\n", left);
|
||||
else
|
||||
sig = sig.extract(left);
|
||||
}
|
||||
expect_char(']');
|
||||
}
|
||||
|
|
@ -476,8 +521,14 @@ struct RTLILFrontendWorker {
|
|||
{
|
||||
std::optional<RTLIL::IdString> id = try_parse_id();
|
||||
if (id.has_value()) {
|
||||
if (current_module->wire(*id) != nullptr)
|
||||
error("RTLIL error: redefinition of wire %s.", *id);
|
||||
if (current_module->wire(*id) != nullptr) {
|
||||
if (flag_legalize) {
|
||||
log("Legalizing redefinition of wire %s.\n", *id);
|
||||
pool<RTLIL::Wire*> wires = {current_module->wire(*id)};
|
||||
current_module->remove(wires);
|
||||
} else
|
||||
error("RTLIL error: redefinition of wire %s.", *id);
|
||||
}
|
||||
wire = current_module->addWire(std::move(*id));
|
||||
break;
|
||||
}
|
||||
|
|
@ -528,8 +579,13 @@ struct RTLILFrontendWorker {
|
|||
{
|
||||
std::optional<RTLIL::IdString> id = try_parse_id();
|
||||
if (id.has_value()) {
|
||||
if (current_module->memories.count(*id) != 0)
|
||||
error("RTLIL error: redefinition of memory %s.", *id);
|
||||
if (current_module->memories.count(*id) != 0) {
|
||||
if (flag_legalize) {
|
||||
log("Legalizing redefinition of memory %s.\n", *id);
|
||||
current_module->remove(current_module->memories.at(*id));
|
||||
} else
|
||||
error("RTLIL error: redefinition of memory %s.", *id);
|
||||
}
|
||||
memory->name = std::move(*id);
|
||||
break;
|
||||
}
|
||||
|
|
@ -551,14 +607,36 @@ struct RTLILFrontendWorker {
|
|||
expect_eol();
|
||||
}
|
||||
|
||||
void legalize_width_parameter(RTLIL::Cell *cell, RTLIL::IdString port_name)
|
||||
{
|
||||
std::string width_param_name = port_name.str() + "_WIDTH";
|
||||
if (cell->parameters.count(width_param_name) == 0)
|
||||
return;
|
||||
RTLIL::Const ¶m = cell->parameters.at(width_param_name);
|
||||
if (param.as_int() != 0)
|
||||
return;
|
||||
cell->parameters[width_param_name] = RTLIL::Const(cell->getPort(port_name).size());
|
||||
}
|
||||
|
||||
void parse_cell()
|
||||
{
|
||||
RTLIL::IdString cell_type = parse_id();
|
||||
RTLIL::IdString cell_name = parse_id();
|
||||
expect_eol();
|
||||
|
||||
if (current_module->cell(cell_name) != nullptr)
|
||||
error("RTLIL error: redefinition of cell %s.", cell_name);
|
||||
if (current_module->cell(cell_name) != nullptr) {
|
||||
if (flag_legalize) {
|
||||
RTLIL::IdString new_name;
|
||||
int suffix = 1;
|
||||
do {
|
||||
new_name = RTLIL::IdString(cell_name.str() + "_" + std::to_string(suffix));
|
||||
++suffix;
|
||||
} while (current_module->cell(new_name) != nullptr);
|
||||
log("Legalizing redefinition of cell %s by renaming to %s.\n", cell_name, new_name);
|
||||
cell_name = new_name;
|
||||
} else
|
||||
error("RTLIL error: redefinition of cell %s.", cell_name);
|
||||
}
|
||||
RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type);
|
||||
cell->attributes = std::move(attrbuf);
|
||||
|
||||
|
|
@ -567,10 +645,13 @@ struct RTLILFrontendWorker {
|
|||
if (try_parse_keyword("parameter")) {
|
||||
bool is_signed = false;
|
||||
bool is_real = false;
|
||||
bool is_unsized = false;
|
||||
if (try_parse_keyword("signed")) {
|
||||
is_signed = true;
|
||||
} else if (try_parse_keyword("real")) {
|
||||
is_real = true;
|
||||
} else if (try_parse_keyword("unsized")) {
|
||||
is_unsized = true;
|
||||
}
|
||||
RTLIL::IdString param_name = parse_id();
|
||||
RTLIL::Const val = parse_const();
|
||||
|
|
@ -578,13 +659,21 @@ struct RTLILFrontendWorker {
|
|||
val.flags |= RTLIL::CONST_FLAG_SIGNED;
|
||||
if (is_real)
|
||||
val.flags |= RTLIL::CONST_FLAG_REAL;
|
||||
if (is_unsized)
|
||||
val.flags |= RTLIL::CONST_FLAG_UNSIZED;
|
||||
cell->parameters.insert({std::move(param_name), std::move(val)});
|
||||
expect_eol();
|
||||
} else if (try_parse_keyword("connect")) {
|
||||
RTLIL::IdString port_name = parse_id();
|
||||
if (cell->hasPort(port_name))
|
||||
error("RTLIL error: redefinition of cell port %s.", port_name);
|
||||
if (cell->hasPort(port_name)) {
|
||||
if (flag_legalize)
|
||||
log("Legalizing redefinition of cell port %s.", port_name);
|
||||
else
|
||||
error("RTLIL error: redefinition of cell port %s.", port_name);
|
||||
}
|
||||
cell->setPort(std::move(port_name), parse_sigspec());
|
||||
if (flag_legalize)
|
||||
legalize_width_parameter(cell, port_name);
|
||||
expect_eol();
|
||||
} else if (try_parse_keyword("end")) {
|
||||
expect_eol();
|
||||
|
|
@ -601,6 +690,11 @@ struct RTLILFrontendWorker {
|
|||
error("dangling attribute");
|
||||
RTLIL::SigSpec s1 = parse_sigspec();
|
||||
RTLIL::SigSpec s2 = parse_sigspec();
|
||||
if (flag_legalize) {
|
||||
int min_size = std::min(s1.size(), s2.size());
|
||||
s1 = s1.extract(0, min_size);
|
||||
s2 = s2.extract(0, min_size);
|
||||
}
|
||||
current_module->connect(std::move(s1), std::move(s2));
|
||||
expect_eol();
|
||||
}
|
||||
|
|
@ -677,8 +771,13 @@ struct RTLILFrontendWorker {
|
|||
RTLIL::IdString proc_name = parse_id();
|
||||
expect_eol();
|
||||
|
||||
if (current_module->processes.count(proc_name) != 0)
|
||||
error("RTLIL error: redefinition of process %s.", proc_name);
|
||||
if (current_module->processes.count(proc_name) != 0) {
|
||||
if (flag_legalize) {
|
||||
log("Legalizing redefinition of process %s.\n", proc_name);
|
||||
current_module->remove(current_module->processes.at(proc_name));
|
||||
} else
|
||||
error("RTLIL error: redefinition of process %s.", proc_name);
|
||||
}
|
||||
RTLIL::Process *proc = current_module->addProcess(std::move(proc_name));
|
||||
proc->attributes = std::move(attrbuf);
|
||||
|
||||
|
|
@ -799,6 +898,11 @@ struct RTLILFrontend : public Frontend {
|
|||
log(" -lib\n");
|
||||
log(" only create empty blackbox modules\n");
|
||||
log("\n");
|
||||
log(" -legalize\n");
|
||||
log(" prevent semantic errors (e.g. reference to unknown wire, redefinition of wire/cell)\n");
|
||||
log(" by deterministically rewriting the input into something valid. Useful when using\n");
|
||||
log(" fuzzing to generate random but valid RTLIL.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
|
|
@ -823,6 +927,10 @@ struct RTLILFrontend : public Frontend {
|
|||
worker.flag_lib = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-legalize") {
|
||||
worker.flag_legalize = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
|
|
|||
|
|
@ -1392,13 +1392,13 @@ void VerificImporter::merge_past_ffs_clock(pool<RTLIL::Cell*> &candidates, SigBi
|
|||
RTLIL::Cell *new_ff = module->addDff(NEW_ID, clock, sig_d, sig_q, clock_pol);
|
||||
|
||||
if (verific_verbose)
|
||||
log(" merging single-bit past_ffs into new %d-bit ff %s.\n", GetSize(sig_d), log_id(new_ff));
|
||||
log(" merging single-bit past_ffs into new %d-bit ff %s.\n", GetSize(sig_d), new_ff);
|
||||
|
||||
for (int i = 0; i < GetSize(sig_d); i++)
|
||||
for (auto old_ff : dbits_db[sig_d[i]])
|
||||
{
|
||||
if (verific_verbose)
|
||||
log(" replacing old ff %s on bit %d.\n", log_id(old_ff), i);
|
||||
log(" replacing old ff %s on bit %d.\n", old_ff, i);
|
||||
|
||||
SigBit old_q = old_ff->getPort(ID::Q);
|
||||
SigBit new_q = sig_q[i];
|
||||
|
|
@ -1492,10 +1492,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
design->add(module);
|
||||
|
||||
if (is_blackbox(nl)) {
|
||||
log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name));
|
||||
log("Importing blackbox module %s.\n", module);
|
||||
module->set_bool_attribute(ID::blackbox);
|
||||
} else {
|
||||
log("Importing module %s.\n", RTLIL::id2cstr(module->name));
|
||||
log("Importing module %s.\n", module);
|
||||
}
|
||||
import_attributes(module->attributes, nl, nl);
|
||||
if (module->name.isPublic())
|
||||
|
|
@ -1736,7 +1736,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : new_verific_id(net));
|
||||
|
||||
if (verific_verbose)
|
||||
log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
|
||||
log(" importing net %s as %s.\n", net->Name(), wire_name.unescape());
|
||||
|
||||
RTLIL::Wire *wire = module->addWire(wire_name);
|
||||
import_attributes(wire->attributes, net, nl, 1);
|
||||
|
|
@ -1760,7 +1760,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : new_verific_id(netbus));
|
||||
|
||||
if (verific_verbose)
|
||||
log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name));
|
||||
log(" importing netbus %s as %s.\n", netbus->Name(), wire_name.unescape());
|
||||
|
||||
RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
|
||||
wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());
|
||||
|
|
@ -1894,7 +1894,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : new_verific_id(inst));
|
||||
|
||||
if (verific_verbose)
|
||||
log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name));
|
||||
log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), inst_name.unescape());
|
||||
|
||||
if (mode_verific)
|
||||
goto import_verific_cells;
|
||||
|
|
@ -2258,7 +2258,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
|
||||
for (auto &it : cell_port_conns) {
|
||||
if (verific_verbose)
|
||||
log(" .%s(%s)\n", log_id(it.first), log_signal(it.second));
|
||||
log(" .%s(%s)\n", it.first.unescape(), log_signal(it.second));
|
||||
cell->setPort(it.first, it.second);
|
||||
}
|
||||
}
|
||||
|
|
@ -3114,9 +3114,11 @@ struct VerificPass : public Pass {
|
|||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||
log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv} <verilog-file>..\n");
|
||||
log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|\n");
|
||||
log(" -sv2017|-sv} <verilog-file>..\n");
|
||||
log("\n");
|
||||
log("Load the specified Verilog/SystemVerilog files into Verific.\n");
|
||||
log("Note that -sv option will use latest supported SystemVerilog standard.\n");
|
||||
log("\n");
|
||||
log("All files specified in one call to this command are one compilation unit.\n");
|
||||
log("Files passed to different calls to this command are treated as belonging to\n");
|
||||
|
|
@ -3161,7 +3163,10 @@ struct VerificPass : public Pass {
|
|||
#endif
|
||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||
log(" verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009|\n");
|
||||
log(" -sv2012|-sv|-formal] <command-file>\n");
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
log(" -vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl2019|-vhdl|\n");
|
||||
#endif
|
||||
log(" -sv2012|-sv2017|-sv|-formal] <command-file>\n");
|
||||
log("\n");
|
||||
log("Load and execute the specified command file.\n");
|
||||
log("Override verilog parsing mode can be set.\n");
|
||||
|
|
@ -3696,6 +3701,9 @@ struct VerificPass : public Pass {
|
|||
if (GetSize(args) > argidx && (args[argidx] == "-f" || args[argidx] == "-F"))
|
||||
{
|
||||
unsigned verilog_mode = veri_file::UNDEFINED;
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
unsigned vhdl_mode = vhdl_file::UNDEFINED;
|
||||
#endif
|
||||
bool is_formal = false;
|
||||
const char* filename = nullptr;
|
||||
|
||||
|
|
@ -3714,10 +3722,38 @@ struct VerificPass : public Pass {
|
|||
} else if (args[argidx] == "-sv2009") {
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG_2009;
|
||||
continue;
|
||||
} else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal") {
|
||||
} else if (args[argidx] == "-sv2012") {
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG_2012;
|
||||
continue;
|
||||
} else if (args[argidx] == "-sv2017") {
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG_2017;
|
||||
continue;
|
||||
} else if (args[argidx] == "-sv" || args[argidx] == "-formal") {
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG;
|
||||
if (args[argidx] == "-formal") is_formal = true;
|
||||
continue;
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
} else if (args[argidx] == "-vhdl87") {
|
||||
vhdl_mode = vhdl_file::VHDL_87;
|
||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str());
|
||||
continue;
|
||||
} else if (args[argidx] == "-vhdl93") {
|
||||
vhdl_mode = vhdl_file::VHDL_93;
|
||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
|
||||
continue;
|
||||
} else if (args[argidx] == "-vhdl2k") {
|
||||
vhdl_mode = vhdl_file::VHDL_2K;
|
||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
|
||||
continue;
|
||||
} else if (args[argidx] == "-vhdl2019") {
|
||||
vhdl_mode = vhdl_file::VHDL_2019;
|
||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2019").c_str());
|
||||
continue;
|
||||
} else if (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl") {
|
||||
vhdl_mode = vhdl_file::VHDL_2008;
|
||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
|
||||
continue;
|
||||
#endif
|
||||
} else if (args[argidx].compare(0, 1, "-") == 0) {
|
||||
cmd_error(args, argidx, "unknown option");
|
||||
goto check_error;
|
||||
|
|
@ -3742,10 +3778,36 @@ struct VerificPass : public Pass {
|
|||
veri_file::DefineMacro("VERIFIC");
|
||||
veri_file::DefineMacro(is_formal ? "FORMAL" : "SYNTHESIS");
|
||||
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
if (vhdl_mode == vhdl_file::UNDEFINED) {
|
||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
|
||||
vhdl_mode = vhdl_file::VHDL_2008;
|
||||
}
|
||||
int i;
|
||||
Array *file_names_sv = new Array(POINTER_HASH);
|
||||
FOREACH_ARRAY_ITEM(file_names, i, filename) {
|
||||
std::string filename_str = filename;
|
||||
if ((filename_str.substr(filename_str.find_last_of(".") + 1) == "vhd") ||
|
||||
(filename_str.substr(filename_str.find_last_of(".") + 1) == "vhdl")) {
|
||||
if (!vhdl_file::Analyze(filename, work.c_str(), vhdl_mode)) {
|
||||
verific_error_msg.clear();
|
||||
log_cmd_error("Reading VHDL sources failed.\n");
|
||||
}
|
||||
} else {
|
||||
file_names_sv->Insert(strdup(filename));
|
||||
}
|
||||
}
|
||||
if (!veri_file::AnalyzeMultipleFiles(file_names_sv, analysis_mode, work.c_str(), veri_file::MFCU)) {
|
||||
verific_error_msg.clear();
|
||||
log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n");
|
||||
}
|
||||
delete file_names_sv;
|
||||
#else
|
||||
if (!veri_file::AnalyzeMultipleFiles(file_names, analysis_mode, work.c_str(), veri_file::MFCU)) {
|
||||
verific_error_msg.clear();
|
||||
log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
delete file_names;
|
||||
verific_import_pending = true;
|
||||
|
|
@ -3753,7 +3815,8 @@ struct VerificPass : public Pass {
|
|||
}
|
||||
|
||||
if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" ||
|
||||
args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal"))
|
||||
args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv2017" || args[argidx] == "-sv" ||
|
||||
args[argidx] == "-formal"))
|
||||
{
|
||||
Array file_names;
|
||||
unsigned verilog_mode;
|
||||
|
|
@ -3766,7 +3829,11 @@ struct VerificPass : public Pass {
|
|||
verilog_mode = veri_file::SYSTEM_VERILOG_2005;
|
||||
else if (args[argidx] == "-sv2009")
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG_2009;
|
||||
else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")
|
||||
else if (args[argidx] == "-sv2012")
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG_2012;
|
||||
else if (args[argidx] == "-sv2017")
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG_2017;
|
||||
else if (args[argidx] == "-sv" || args[argidx] == "-formal")
|
||||
verilog_mode = veri_file::SYSTEM_VERILOG;
|
||||
else
|
||||
log_abort();
|
||||
|
|
|
|||
|
|
@ -1846,7 +1846,10 @@ struct VerificSvaImporter
|
|||
if (mode_assume) c = module->addAssume(root_name, sig_a_q, sig_en_q);
|
||||
if (mode_cover) c = module->addCover(root_name, sig_a_q, sig_en_q);
|
||||
|
||||
if (c) importer->import_attributes(c->attributes, root);
|
||||
if (c) {
|
||||
c->set_bool_attribute(ID(keep));
|
||||
importer->import_attributes(c->attributes, root);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ParserErrorException)
|
||||
|
|
|
|||
|
|
@ -500,7 +500,6 @@ struct VerilogFrontend : public Frontend {
|
|||
log("Parsing %s%s input from `%s' to AST representation.\n",
|
||||
parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
|
||||
|
||||
log("verilog frontend filename %s\n", filename.c_str());
|
||||
if (flag_relative_share) {
|
||||
auto share_path = proc_share_dirname();
|
||||
if (filename.substr(0, share_path.length()) == share_path)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
int current_function_or_task_port_id;
|
||||
std::vector<char> case_type_stack;
|
||||
bool do_not_require_port_stubs;
|
||||
bool current_wire_rand, current_wire_const;
|
||||
bool current_wire_rand, current_wire_const, current_wire_automatic;
|
||||
bool current_modport_input, current_modport_output;
|
||||
bool default_nettype_wire = true;
|
||||
std::istream* lexin;
|
||||
|
|
@ -546,7 +546,7 @@
|
|||
%token TOK_z "'z'"
|
||||
|
||||
%type <ast_t> range range_or_multirange non_opt_range non_opt_multirange
|
||||
%type <ast_t> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
|
||||
%type <ast_t> wire_type expr basic_expr concat_list assignment_pattern_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
|
||||
%type <string_t> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number
|
||||
%type <string_t> type_name
|
||||
%type <ast_t> opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type
|
||||
|
|
@ -958,14 +958,18 @@ delay:
|
|||
non_opt_delay | %empty;
|
||||
|
||||
io_wire_type:
|
||||
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; }
|
||||
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; extra->current_wire_automatic = false; }
|
||||
wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness
|
||||
{ $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); };
|
||||
|
||||
non_io_wire_type:
|
||||
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; }
|
||||
wire_type_const_rand wire_type_token wire_type_signedness
|
||||
{ $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); };
|
||||
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; extra->current_wire_automatic = false; }
|
||||
opt_lifetime wire_type_const_rand wire_type_token wire_type_signedness
|
||||
{
|
||||
if (extra->current_wire_automatic)
|
||||
extra->astbuf3->set_attribute(ID::nosync, AstNode::mkconst_int(extra->astbuf3->location, 1, false));
|
||||
$$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$);
|
||||
};
|
||||
|
||||
wire_type:
|
||||
io_wire_type { $$ = std::move($1); } |
|
||||
|
|
@ -1253,6 +1257,10 @@ opt_automatic:
|
|||
TOK_AUTOMATIC |
|
||||
%empty;
|
||||
|
||||
opt_lifetime:
|
||||
TOK_AUTOMATIC { extra->current_wire_automatic = true; } |
|
||||
%empty;
|
||||
|
||||
task_func_args_opt:
|
||||
TOK_LPAREN TOK_RPAREN | %empty | TOK_LPAREN {
|
||||
extra->albuf = nullptr;
|
||||
|
|
@ -3341,6 +3349,11 @@ basic_expr:
|
|||
TOK_LCURL concat_list TOK_RCURL {
|
||||
$$ = std::move($2);
|
||||
} |
|
||||
OP_CAST TOK_LCURL assignment_pattern_list optional_comma TOK_RCURL {
|
||||
if (!mode->sv)
|
||||
err_at_loc(@1, "Assignment patterns are only supported in SystemVerilog mode.");
|
||||
$$ = std::move($3);
|
||||
} |
|
||||
TOK_LCURL expr TOK_LCURL concat_list TOK_RCURL TOK_RCURL {
|
||||
$$ = std::make_unique<AstNode>(@$, AST_REPLICATE, std::move($2), std::move($4));
|
||||
} |
|
||||
|
|
@ -3572,6 +3585,16 @@ concat_list:
|
|||
$$->children.push_back(std::move($1));
|
||||
};
|
||||
|
||||
assignment_pattern_list:
|
||||
expr {
|
||||
$$ = std::make_unique<AstNode>(@$, AST_ASSIGN_PATTERN);
|
||||
$$->children.push_back(std::move($1));
|
||||
} |
|
||||
assignment_pattern_list TOK_COMMA expr {
|
||||
$$ = std::move($1);
|
||||
$$->children.push_back(std::move($3));
|
||||
};
|
||||
|
||||
integral_number:
|
||||
TOK_CONSTVAL { $$ = std::move($1); } |
|
||||
TOK_UNBASED_UNSIZED_CONSTVAL { $$ = std::move($1); } |
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Getting Started
|
|||
Outline of a Yosys command
|
||||
--------------------------
|
||||
|
||||
Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
|
||||
Here is the C++ code for a "hello_world" Yosys command (hello.cc):
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ the declarations for the following types in kernel/rtlil.h:
|
|||
The module is a container with connected cells and wires
|
||||
in it. The design is a container with modules in it.
|
||||
|
||||
All this types are also available without the RTLIL:: prefix in the Yosys
|
||||
All these types are also available without the RTLIL:: prefix in the Yosys
|
||||
namespace.
|
||||
|
||||
4. SigMap and other Helper Classes
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
|
|||
if (pos < 0)
|
||||
result.set(i, vacant_bits);
|
||||
else if (pos >= BigInteger(GetSize(arg1)))
|
||||
result.set(i, sign_ext ? arg1.back() : vacant_bits);
|
||||
result.set(i, sign_ext && !arg1.empty() ? arg1.back() : vacant_bits);
|
||||
else
|
||||
result.set(i, arg1[pos.toInt()]);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue