Compare commits
1207 commits
master
...
tracer-ysy
Author | SHA1 | Date | |
---|---|---|---|
|
8a24c518eb | ||
|
931fece0b0 | ||
|
259197ed67 | ||
|
64668c14a7 | ||
|
7f5dcd2775 | ||
|
a351534d47 | ||
|
e7e5346b78 | ||
|
eff6d2299f | ||
|
6f06bc60c7 | ||
|
fd57268a56 | ||
|
2b11bd5800 | ||
|
9b63b2a8a0 | ||
|
780a596a2e | ||
|
5c89a7f11f | ||
|
17c514fca5 | ||
|
5d03e68517 | ||
|
25c54012d9 | ||
|
e1fa3a6cb3 | ||
|
352bc538ce | ||
|
2d9163c64a | ||
|
c9d1eec2f2 | ||
|
651b40be10 | ||
|
caab852207 | ||
|
97a6d93bf0 | ||
|
ec09d6ca46 | ||
|
a50619438f | ||
|
52573cf68e | ||
|
c55e4e04af | ||
|
4db19ebd68 | ||
|
d622cc047a | ||
|
03afae61cb | ||
|
8a58dfc68a | ||
|
38da9c425a | ||
|
16ff4fa42e | ||
|
327db2ba3c | ||
|
f9bd7e25b7 | ||
|
abc6769675 | ||
|
4528e3bec3 | ||
|
dc03efa59c | ||
|
b2497342bf | ||
|
4287f22aa6 | ||
|
c93e6e9692 | ||
|
95ef6828ad | ||
|
3ebdcc39a4 | ||
|
7328053915 | ||
|
e444b091d6 | ||
|
e048a483ec | ||
|
20030dc8d5 | ||
|
31ad681337 | ||
|
f9d6e57afc | ||
|
15b0be76c2 | ||
|
a4cdd926ae | ||
|
e974d8c439 | ||
|
f9545ba88c | ||
|
d08c2860da | ||
|
a210694e82 | ||
|
5e1371248c | ||
|
1a65ceab6f | ||
|
27304ca30a | ||
|
92c8717920 | ||
|
8a61ac176b | ||
|
f970600a35 | ||
|
f2c726e647 | ||
|
874f1d92f6 | ||
|
28708f3774 | ||
|
f64392eedc | ||
|
00898f6264 | ||
|
94f7a9282a | ||
|
694ddb57dc | ||
|
9b3a6fd757 | ||
|
dcef7521f7 | ||
|
ee8bd50401 | ||
|
8e0d229f49 | ||
|
3358125504 | ||
|
f6630958b1 | ||
|
6ee929f0c7 | ||
|
551f0b9b13 | ||
|
59a4dfab7f | ||
|
ad8e7430c3 | ||
|
728fa8052d | ||
|
173d04977c | ||
|
4c3201b8e7 | ||
|
aa07f79378 | ||
|
53efdfc15c | ||
|
4ea59e6e01 | ||
|
5bae31990f | ||
|
f42498d96d | ||
|
01001c930b | ||
|
ecbb5c8392 | ||
|
3204c2a442 | ||
|
a594f38f05 | ||
|
21aa685e1b | ||
|
7bda549dd8 | ||
|
0eeabef770 | ||
|
4293898e4b | ||
|
e05da52cbe | ||
|
70f9c349e3 | ||
|
68da982554 | ||
|
d9fa92afb9 | ||
|
cd53fb04d5 | ||
|
8988980966 | ||
|
bcf8ec87ca | ||
|
46b603e572 | ||
|
5eb7785adf | ||
|
48786c9988 | ||
|
db6a9fdc5f | ||
|
5aee73e34d | ||
|
be9ae806d9 | ||
|
c0160faa42 | ||
|
8e03d125ce | ||
|
12b32de52d | ||
|
417952199a | ||
|
bcc8fc731d | ||
|
c7ce5a2d5b | ||
|
6602d1d7aa | ||
|
febe065b0f | ||
|
15c0ad2cd5 | ||
|
d6b293da6f | ||
|
c6cc74192c | ||
|
3bbd5cfbaf | ||
|
6fd3fa90bf | ||
|
8f686c59d9 | ||
|
db76d96f05 | ||
|
d4439a279b | ||
|
b350c43d42 | ||
|
a9e03f6461 | ||
|
3cc2e29178 | ||
|
1b44697a67 | ||
|
d62e53e8ad | ||
|
fd7c8c2700 | ||
|
a1de9b1656 | ||
|
758e93e83e | ||
|
add808138c | ||
|
49649b0db8 | ||
|
de4c8730af | ||
|
a2b9777ea4 | ||
|
baade9046d | ||
|
efacd975fc | ||
|
ce5e02c7c8 | ||
|
c102a89310 | ||
|
abd418c462 | ||
|
15f2fa649c | ||
|
9eaa04865c | ||
|
f49c12e752 | ||
|
58254afb1c | ||
|
32de3d30e5 | ||
|
f186e14fb0 | ||
|
8513980668 | ||
|
a20136aec5 | ||
|
39f0f75bf4 | ||
|
6a279a4429 | ||
|
a62105b482 | ||
|
c951843582 | ||
|
14e93a47cc | ||
|
1b7dd394fe | ||
|
fd754ceb7e | ||
|
ecff930585 | ||
|
7f3cbe0b33 | ||
|
0df2e277fb | ||
|
cbb58f2265 | ||
|
16d4aed3fb | ||
|
1ddee6ae9b | ||
|
32432b70b7 | ||
|
2240a685e1 | ||
|
3ad4ab8c9b | ||
|
596f9debf2 | ||
|
5d8572b1db | ||
|
ea11bd2425 | ||
|
91ea8de2b4 | ||
|
6aa4b4b8c4 | ||
|
9d26428a28 | ||
|
8688870aef | ||
|
3cee51c298 | ||
|
8ef51c8604 | ||
|
9a4b70d1f3 | ||
|
2047fe7e65 | ||
|
26f668141f | ||
|
2f1f38a359 | ||
|
061167cd10 | ||
|
e65b97f4ec | ||
|
b037d4897c | ||
|
cc2dffeac7 | ||
|
7d10fc3552 | ||
|
80e26a574b | ||
|
5a5635e11f | ||
|
ff3ebb9ac2 | ||
|
40b3e285af | ||
|
053f86020c | ||
|
696583b943 | ||
|
95aebe191e | ||
|
3a5bf0518a | ||
|
15f2b5674f | ||
|
e0e14d7ca4 | ||
|
1f1ec6654b | ||
|
47dedcbb43 | ||
|
12b18e77fd | ||
|
e391bdd5df | ||
|
5cf348aff6 | ||
|
5608d9ecfc | ||
|
f147be9b5a | ||
|
ed8cd21c75 | ||
|
9c69044641 | ||
|
aa7b91b900 | ||
|
802fcb0846 | ||
|
67a6ccdb6b | ||
|
f1ade93f9a | ||
|
c34f132985 | ||
|
bdd1069c6e | ||
|
0f6bc5ab08 | ||
|
7e1535e3ba | ||
|
2a65951bdb | ||
|
a9eaba1ffa | ||
|
f79f430acc | ||
|
08e1837cbe | ||
|
58985894f6 | ||
|
18d33c363b | ||
|
b5f076e957 | ||
|
020659b74e | ||
|
2c591550f7 | ||
|
3c476f0a57 | ||
|
dd22b882f8 | ||
|
2f6b381c9d | ||
|
54c8243167 | ||
|
6be0953168 | ||
|
545c64c479 | ||
|
3fc7b061a9 | ||
|
2688683069 | ||
|
a7be72f328 | ||
|
3d298ca442 | ||
|
3e3ad2ce06 | ||
|
a5c273ead8 | ||
|
efcfef915a | ||
|
b0793d3253 | ||
|
4cc3da1f37 | ||
|
718f180414 | ||
|
110d8d5288 | ||
|
2a27cd71c7 | ||
|
b3b2495a7b | ||
|
e55b17585d | ||
|
02c7ed6726 | ||
|
db7c0c436b | ||
|
93b264b448 | ||
|
08638dad89 | ||
|
677ae0bd70 | ||
|
6620c3759f | ||
|
d707535d60 | ||
|
cb2ecd29ac | ||
|
aeed35376f | ||
|
0cfa9d2eef | ||
|
2214ed95ab | ||
|
79adeb8f63 | ||
|
2914694445 | ||
|
7d581b47eb | ||
|
810a743e9e | ||
|
0a0c9d8fcb | ||
|
10f946e359 | ||
|
dd809b6712 | ||
|
a7d59b4d37 | ||
|
0560c97eda | ||
|
b1db549157 | ||
|
5eda7412d2 | ||
|
8fc1f3838b | ||
|
ee22c1541d | ||
|
f7f19ed102 | ||
|
705ee17b3c | ||
|
bc3fe23781 | ||
|
109036a4ca | ||
|
e0fd5031ef | ||
|
342939e228 | ||
|
b8bd6afa13 | ||
|
291ab7d16a | ||
|
3d2e72309b | ||
|
b03f203288 | ||
|
a7be56aa0c | ||
|
993b779854 | ||
|
68747c7d81 | ||
|
c97e7271b7 | ||
|
dee37632f1 | ||
|
147014c8fa | ||
|
1e10f8a249 | ||
|
3fde1fbac5 | ||
|
9a15f87c5e | ||
|
9735a8a7bb | ||
|
16c8af7dea | ||
|
ed7fca5a97 | ||
|
a9bb46ecb5 | ||
|
e3a7de2aff | ||
|
5db88a889f | ||
|
6fe73897dc | ||
|
4b8916a817 | ||
|
7f9a1da640 | ||
|
c7e841e43a | ||
|
4eb9acf89f | ||
|
f5cd1d2b06 | ||
|
ffd87d2746 | ||
|
17095f0bab | ||
|
abe0575323 | ||
|
f6f27cd93a | ||
|
5fec4a374d | ||
|
281b9712d7 | ||
|
de0efb4986 | ||
|
91315b7379 | ||
|
942666806e | ||
|
04a8a9c0ad | ||
|
ad58f7f164 | ||
|
854c0aa973 | ||
|
c751a89edf | ||
|
00065136ff | ||
|
9012266a88 | ||
|
36b8b41e25 | ||
|
75b5e9dbf5 | ||
|
c960901f15 | ||
|
78fcc445b8 | ||
|
fe2c36c628 | ||
|
438e11c601 | ||
|
a684a2364a | ||
|
9b51d595a0 | ||
|
0bc9f8419d | ||
|
f4c22467e9 | ||
|
9e9ad4d425 | ||
|
1852f1f209 | ||
|
08109959b6 | ||
|
79050953dd | ||
|
cf2dff4704 | ||
|
b6e39b5b4a | ||
|
dcae1fe183 | ||
|
9d3f6bb729 | ||
|
292f06b86f | ||
|
f50d27c825 | ||
|
57b2248f8a | ||
|
b8c611ba60 | ||
|
262b9d8763 | ||
|
24804a1546 | ||
|
9123986262 | ||
|
c3b4a2ed6e | ||
|
7a7cfb6d17 | ||
|
08a1ad30c6 | ||
|
636f93c369 | ||
|
b2ecdf5879 | ||
|
5c26da28bd | ||
|
6a74c48731 | ||
|
508ff1220c | ||
|
35867470e0 | ||
|
b623a71d8f | ||
|
20b153a334 | ||
|
167a15b85a | ||
|
d5d4a436a0 | ||
|
0449cb2b96 | ||
|
12b73de7f9 | ||
|
be942b362f | ||
|
991bed91d8 | ||
|
deb6687f98 | ||
|
1641437447 | ||
|
736ac0b0ac | ||
|
962d2c05f8 | ||
|
b95454d9f4 | ||
|
923d0200da | ||
|
47ea3967ab | ||
|
d821eff971 | ||
|
62718e8225 | ||
|
cb8ca4aba1 | ||
|
0be92d4c44 | ||
|
035a1e5cff | ||
|
874694b06f | ||
|
dc7cc0216c | ||
|
28a9d21f9e | ||
|
023dc80b98 | ||
|
357519363f | ||
|
0b3a3d34f2 | ||
|
da30b69262 | ||
|
99d71a14a5 | ||
|
7eb0e2817f | ||
|
9e92a32d15 | ||
|
e628e42959 | ||
|
c92096d729 | ||
|
a9f2d6a56a | ||
|
6132f650af | ||
|
4bade1f5d8 | ||
|
5cc71bcf5b | ||
|
2763cebb4f | ||
|
c8857248f0 | ||
|
016ea9b7b3 | ||
|
df546432b1 | ||
|
7d566158c6 | ||
|
4fc0e0e247 | ||
|
20c8c52468 | ||
|
4bec6d86ef | ||
|
8c36e50e6a | ||
|
d36bca5887 | ||
|
0c6d16efd8 | ||
|
eda2de1f21 | ||
|
a941200a81 | ||
|
ee20b97503 | ||
|
69b5017409 | ||
|
41bed73e10 | ||
|
22071af276 | ||
|
c06e1b2daa | ||
|
60a07edf6c | ||
|
32f76be917 | ||
|
95e819824b | ||
|
574043ede5 | ||
|
bbc087a4a3 | ||
|
b8bceb95ba | ||
|
b5c473419a | ||
|
7bb59857a4 | ||
|
682cc220f2 | ||
|
d9eb565c66 | ||
|
6b63bc9c05 | ||
|
7ed90d6241 | ||
|
9aea490721 | ||
|
427adbac29 | ||
|
737b62dbee | ||
|
12f8eda9d7 | ||
|
7c3c2ce973 | ||
|
7df9c941df | ||
|
e54b6110c0 | ||
|
bb71f3bcea | ||
|
2e8ff661b5 | ||
|
4cae21faff | ||
|
d42898fb7e | ||
|
dea0846feb | ||
|
4afbc21b33 | ||
|
63f5339b1d | ||
|
7e67e94a5c | ||
|
36d61e2d9e | ||
|
9a75bfd99f | ||
|
0390d7f2aa | ||
|
83dba69a54 | ||
|
38f1ed27a0 | ||
|
a757dd4b43 | ||
|
ef85b9f7bf | ||
|
c8f5c23463 | ||
|
66af7a5e2e | ||
|
4b1163d0ed | ||
|
125eb7c09b | ||
|
ec8fdcbe38 | ||
|
bc58e07285 | ||
|
14e442c0a7 | ||
|
ce399c14d9 | ||
|
c71b7bdb69 | ||
|
2148f492f5 | ||
|
e89e18811b | ||
|
468558417f | ||
|
b564f649f2 | ||
|
2170c014b5 | ||
|
455cf3d498 | ||
|
ee52b3b45a | ||
|
a76068db9f | ||
|
8b6d7689ca | ||
|
be5579f88d | ||
|
30cd92be1f | ||
|
0229b0601d | ||
|
4ca052cb1b | ||
|
3aceace0c3 | ||
|
5214b46f0d | ||
|
c60010964c | ||
|
9a4851ae1d | ||
|
743140e390 | ||
|
3238a7d4e7 | ||
|
3bcd10e12e | ||
|
2b28fdfb74 | ||
|
51d980a489 | ||
|
136bf5e2a5 | ||
|
7ec2bbc984 | ||
|
31618716e9 | ||
|
e9f3cf9ef1 | ||
|
5fae67a50a | ||
|
1b743d23f9 | ||
|
5c562f9ac5 | ||
|
527f5061df | ||
|
b142f15165 | ||
|
e569f20696 | ||
|
01960837e0 | ||
|
a915be2262 | ||
|
52e9b6669e | ||
|
f2a6cf21a5 | ||
|
e54e683cf5 | ||
|
a4d61ab418 | ||
|
33acaf4f65 | ||
|
4317af0dec | ||
|
2c5ef67d8e | ||
|
a85a65873f | ||
|
87cbb1571b | ||
|
d34c606c99 | ||
|
fa7173194f | ||
|
5790387639 | ||
|
0f2ccd6328 | ||
|
b77eb2f191 | ||
|
0dfe80c278 | ||
|
f1667e6aec | ||
|
bd617e3c7b | ||
|
18db693c0f | ||
|
b1fb8cd771 | ||
|
19218ee4fc | ||
|
4646631a8d | ||
|
4ccd4b7e2d | ||
|
999afe3664 | ||
|
867acd22fb | ||
|
c46b2b1ae0 | ||
|
a089f0df65 | ||
|
b8c4b91f2f | ||
|
2a1f781753 | ||
|
8101d73575 | ||
|
f1538e9662 | ||
|
e61ddae575 | ||
|
a91e261593 | ||
|
7cd29cee97 | ||
|
9f8ed6f17c | ||
|
1a1132a7db | ||
|
9e7baa4bf4 | ||
|
3911bb85f9 | ||
|
d50355d77b | ||
|
cb766b0d69 | ||
|
66f4e11d6a | ||
|
f42973dc9a | ||
|
b45e678f00 | ||
|
f9fde57436 | ||
|
46ad43c89e | ||
|
6163d76369 | ||
|
e5cfa3b6ab | ||
|
3b583720d9 | ||
|
65432889e1 | ||
|
989847e1cb | ||
|
4c3cd1ca9f | ||
|
cff522a5ca | ||
|
4946f6f435 | ||
|
14d91e6fe4 | ||
|
dbed45814b | ||
|
05dce9ed14 | ||
|
66240f56d4 | ||
|
c4049dfa39 | ||
|
0531eb060a | ||
|
53baebe06d | ||
|
29946273cd | ||
|
e444f69912 | ||
|
87d3a424f3 | ||
|
2b82e21363 | ||
|
7e4321a906 | ||
|
15417e3e7a | ||
|
2c89dd1f5d | ||
|
dd9dbc5d01 | ||
|
e00a227b62 | ||
|
ad4eb5a370 | ||
|
5f3581ad47 | ||
|
2cb8584055 | ||
|
71dc2933e2 | ||
|
ba85b52bc3 | ||
|
fee84cb218 | ||
|
6115718454 | ||
|
f4813afbdc | ||
|
7b5f53a170 | ||
|
1094074a3c | ||
|
00fc730e3e | ||
|
074ec5b4a1 | ||
|
d784f80261 | ||
|
10f368edbb | ||
|
d3eaab6a5f | ||
|
92b03e579b | ||
|
e4812c59d5 | ||
|
b6403747e0 | ||
|
6681ed935c | ||
|
cb13d4d6f8 | ||
|
375772441d | ||
|
d11dacef92 | ||
|
515e7be314 | ||
|
ace6b4a72b | ||
|
3d280fbe0b | ||
|
3a604683b0 | ||
|
59a4c87ed5 | ||
|
c9306cab5b | ||
|
7a45094712 | ||
|
80ccc78e9b | ||
|
96b1a5dcec | ||
|
d04c357e5c | ||
|
9a0957389f | ||
|
a0a3c459c4 | ||
|
576f911ee9 | ||
|
f8bfa45516 | ||
|
b837fed781 | ||
|
94d560187e | ||
|
6b9ae21fc6 | ||
|
5233b02844 | ||
|
40162a39ab | ||
|
ddc1510177 | ||
|
b9aa7724a0 | ||
|
a223953c52 | ||
|
64cf984f5f | ||
|
ce843e6adb | ||
|
8960f8b37a | ||
|
188c2d8bb5 | ||
|
b171442112 | ||
|
093fb733a0 | ||
|
3a0268ca34 | ||
|
91ad6d4335 | ||
|
38984882c1 | ||
|
312c5a99cc | ||
|
7cb08dc9fa | ||
|
4bb0fb31ae | ||
|
6846ae6781 | ||
|
6eb135a3b8 | ||
|
58e93a3848 | ||
|
3b98fd1372 | ||
|
c6933b1c3a | ||
|
536f134e4c | ||
|
4a78296ebd | ||
|
80c13c3f6b | ||
|
a9755df8de | ||
|
16c5601d6d | ||
|
6ae1b559b8 | ||
|
cde9611e61 | ||
|
7416c3efd6 | ||
|
21e6e0e708 | ||
|
1111a00067 | ||
|
16e1bc36e6 | ||
|
cada53f571 | ||
|
be9c694cab | ||
|
87b600d247 | ||
|
51c91e8371 | ||
|
c20efb9cd2 | ||
|
c35d714e1c | ||
|
dcecd62533 | ||
|
2318d48525 | ||
|
abcdb33dbf | ||
|
549aaa40fd | ||
|
72ab3ad041 | ||
|
4203d25098 | ||
|
c83dbf0854 | ||
|
f5ff6239c7 | ||
|
e6d3d052a1 | ||
|
487f4d8f3e | ||
|
d3f330e74a | ||
|
22ce94f4a4 | ||
|
fb0d244ddd | ||
|
ddd40738c8 | ||
|
768e8efe9d | ||
|
4404802163 | ||
|
70829c8d56 | ||
|
3ec0c3a635 | ||
|
5c6c03272c | ||
|
1ab8e91cc2 | ||
|
03de8f744e | ||
|
216d76ecef | ||
|
800cd64f98 | ||
|
8970a2cac4 | ||
|
0436356a3b | ||
|
3f9d84b539 | ||
|
370dc66f05 | ||
|
c05cf3ce21 | ||
|
d464f3f0c6 | ||
|
819b096cbb | ||
|
469c1f22e5 | ||
|
77080c0707 | ||
|
b4f72c1d57 | ||
|
3938534a04 | ||
|
7a387883ea | ||
|
06d81b80bd | ||
|
b2d030f081 | ||
|
3a1d39bebf | ||
|
3ed490ab52 | ||
|
435161caa3 | ||
|
b1a8710d27 | ||
|
20fc4cedbc | ||
|
88a963e177 | ||
|
b63d1203c9 | ||
|
15c6204a16 | ||
|
645d749c51 | ||
|
8094cf286e | ||
|
9d9c6f46fd | ||
|
a2ba5e8afd | ||
|
79f9a57165 | ||
|
31aceb7bc9 | ||
|
c995a80ce8 | ||
|
f5cdb499b8 | ||
|
9362deec51 | ||
|
a9b909b66f | ||
|
d3321a6fe8 | ||
|
dfada8101b | ||
|
1cd32d4968 | ||
|
f8b8ae50b7 | ||
|
e5c95f5767 | ||
|
a718c5c723 | ||
|
7ccd5d8e83 | ||
|
dd8a42d378 | ||
|
363867e231 | ||
|
296bd0483f | ||
|
294353437a | ||
|
9507e0e4ac | ||
|
c2c33ebc33 | ||
|
9e4228401a | ||
|
1e532e291b | ||
|
d8ca076590 | ||
|
8190bd4c1f | ||
|
1b6da73d6c | ||
|
e57e2391ee | ||
|
e98c720d0b | ||
|
c95d01a41c | ||
|
2eb45163a4 | ||
|
1f36080d06 | ||
|
faa5744d8f | ||
|
f21008931b | ||
|
abab954dbb | ||
|
f72f814469 | ||
|
e6d74ffc61 | ||
|
995babb9e4 | ||
|
eee17319a0 | ||
|
7d8c7c33dd | ||
|
c70ced4738 | ||
|
f5a7ed17f6 | ||
|
c74f692289 | ||
|
973429f199 | ||
|
27f68fcbbe | ||
|
a9a1b391c9 | ||
|
246fb09e16 | ||
|
48d7905d0a | ||
|
3fce44c3e5 | ||
|
73e355b21d | ||
|
99d4110a2c | ||
|
14a5d1d6b5 | ||
|
b51e58a20f | ||
|
d0e2e99305 | ||
|
ba9e90e090 | ||
|
7e0b6894fe | ||
|
f3e9318d98 | ||
|
32912eed06 | ||
|
5016ef5266 | ||
|
0fd2cb98d4 | ||
|
9e7d1f9f9f | ||
|
f614d7afd5 | ||
|
1811c60cf9 | ||
|
8da91efc80 | ||
|
436fd0a6cd | ||
|
ea30467cd6 | ||
|
8629a28ed5 | ||
|
7a000a01a7 | ||
|
b2e8c88532 | ||
|
be1ac1f0a6 | ||
|
862f8be292 | ||
|
1cb2e8ebdf | ||
|
565bd887cc | ||
|
cdd498e2be | ||
|
4c3fe9b49b | ||
|
b823a50a03 | ||
|
ed5286d81a | ||
|
507190a9f2 | ||
|
9273d0c7d8 | ||
|
a392840f6c | ||
|
9bafb10c43 | ||
|
bbdc49b229 | ||
|
d20ea706e8 | ||
|
6e4b46c26d | ||
|
bf538dd98e | ||
|
622aeb1c58 | ||
|
3d4e3243b3 | ||
|
30b6784b8e | ||
|
9b561034f5 | ||
|
f3b615a63e | ||
|
70028b686f | ||
|
8e6574b477 | ||
|
d0d15c6088 | ||
|
44a42b4d3c | ||
|
0f52515269 | ||
|
596a26b36c | ||
|
0cfb776bc1 | ||
|
2a3b7e9b2e | ||
|
b2bb61bd4b | ||
|
4bd3dd9803 | ||
|
694c54c044 | ||
|
5a9ac07d90 | ||
|
b7dbbaeedc | ||
|
d3f715fb4f | ||
|
0a571ee71b | ||
|
6988dfddbd | ||
|
41bf877ab7 | ||
|
c72c271524 | ||
|
4dd025b960 | ||
|
e79bf232dc | ||
|
755eaa921c | ||
|
74e272b7b5 | ||
|
6fe396f201 | ||
|
39078a89c0 | ||
|
f1bbfbbfc5 | ||
|
91370f0e4d | ||
|
bddf345f41 | ||
|
07cfd138c6 | ||
|
e481c738ea | ||
|
dca6a95b84 | ||
|
816ab15a75 | ||
|
a3e3ce99dc | ||
|
6e1385df6b | ||
|
ace487b36e | ||
|
1ec03cfb13 | ||
|
a0c0c2c776 | ||
|
b97e2bf469 | ||
|
70ec0a166a | ||
|
20bf8669d7 | ||
|
3ccf684730 | ||
|
570e2d97f2 | ||
|
32db339856 | ||
|
6b0a221401 | ||
|
b88c898e3b | ||
|
695a1d6acb | ||
|
2b478c7c47 | ||
|
a1e7000829 | ||
|
965ce580d8 | ||
|
3761d8b7b6 | ||
|
89132dd14d | ||
|
6de96db503 | ||
|
460a221325 | ||
|
b80e1a928b | ||
|
bada305a29 | ||
|
e6f189549e | ||
|
1fe8443630 | ||
|
37ae884365 | ||
|
def5654aa5 | ||
|
a3d60c6b24 | ||
|
63393e0648 | ||
|
8edca8921c | ||
|
566ea65ff6 | ||
|
436948cfb2 | ||
|
c23729e4dc | ||
|
67bf630b6b | ||
|
831b0b6889 | ||
|
49fac50878 | ||
|
2cbfd0dbfb | ||
|
527cca1e9b | ||
|
a1953d329b | ||
|
70eaa7c2bf | ||
|
03a073a56d | ||
|
f6e3993939 | ||
|
44cd3c1fb3 | ||
|
e1e510bd1a | ||
|
d49f403def | ||
|
db7df57f9e | ||
|
0836546f6a | ||
|
c8f6eb8ea1 | ||
|
6c46a1d918 | ||
|
72c1de1a91 | ||
|
d8dd740c97 | ||
|
eee0b219db | ||
|
89bca987dc | ||
|
15d3ff87e2 | ||
|
f7481e5870 | ||
|
4290e11bc7 | ||
|
fed7bc355d | ||
|
b4ee94a1dd | ||
|
9e09270bde | ||
|
47109ce3f2 | ||
|
34e53c9d92 | ||
|
ef896f8c3e | ||
|
8f4aa65a0f | ||
|
44874a3696 | ||
|
7e74c0c20b | ||
|
c344fcd2d2 | ||
|
680b1d1913 | ||
|
4c1ec5b003 | ||
|
74fcff1ca7 | ||
|
2f28626c6f | ||
|
d64ce4f9ad | ||
|
c959913320 | ||
|
4d35124b2d | ||
|
42fb48b9da | ||
|
06659f91d0 | ||
|
572c21e107 | ||
|
c797ce8fb4 | ||
|
c5221fb06e | ||
|
2e79ea300a | ||
|
f899642a31 | ||
|
efdf654607 | ||
|
efd9877b30 | ||
|
d4ca18ee2e | ||
|
1ae4b8e87b | ||
|
2e10b2abe0 | ||
|
1b4338bb0f | ||
|
3ed5a7e2c2 | ||
|
8f73809a16 | ||
|
3eac7a318f | ||
|
1ecdd3e6e2 | ||
|
affc1c5ff9 | ||
|
a7b6bc015f | ||
|
09a6519005 | ||
|
86c55d7b06 | ||
|
146ba011af | ||
|
478aedf87a | ||
|
62a4d0f5c4 | ||
|
17e04161c2 | ||
|
2df6be0dfa | ||
|
2174a96662 | ||
|
a251ef6adc | ||
|
cc29fd2f1c | ||
|
0f88247e0d | ||
|
26df7f1440 | ||
|
991cc19536 | ||
|
2c1747eaab | ||
|
656ddd2dfd | ||
|
df71a7b030 | ||
|
2efa6cd15e | ||
|
f4c4758627 | ||
|
40dccf6a54 | ||
|
04ab911f43 | ||
|
efa7de48cc | ||
|
9385743084 | ||
|
262133eb4c | ||
|
b8c56ce819 | ||
|
10cdf4151f | ||
|
7bf17d3663 | ||
|
b3a7f26b9d | ||
|
08177e20f4 | ||
|
6c2aa3fa5c | ||
|
074ac0a663 | ||
|
14ae14bd41 | ||
|
fc41461acf | ||
|
9f11fdf30e | ||
|
bbc96cb7cf | ||
|
b1f026977e | ||
|
ed1d62143c | ||
|
04ccee4b8c | ||
|
44d5ac60aa | ||
|
8f7e17253f | ||
|
f354b3af92 | ||
|
eac5301908 | ||
|
3fd601183a | ||
|
32f5ddfed0 | ||
|
e824fa77dd | ||
|
d98cf10f17 | ||
|
e2d7943dd8 | ||
|
cecb184229 | ||
|
9674f3b0c2 | ||
|
6dde11822d | ||
|
21c7c9ce35 | ||
|
43ea6aac16 | ||
|
c0d4b9ff30 | ||
|
291935091a | ||
|
28aa2d11dc | ||
|
fabdb57796 | ||
|
c8a662c9e2 | ||
|
fc7a46b721 | ||
|
336213bdfc | ||
|
eff5ed0086 | ||
|
deb8742bc0 | ||
|
fe0fed108c | ||
|
ffe976ca81 | ||
|
2a51f1df41 | ||
|
d57c650281 | ||
|
d785479b62 | ||
|
4df280320a | ||
|
73a811a814 | ||
|
5ed1278cd7 | ||
|
28587868a2 | ||
|
60cb7ee36a | ||
|
ba8658f385 | ||
|
eb22a9779c | ||
|
9a0c647c48 | ||
|
8447e18ab9 | ||
|
9930dd6f20 | ||
|
a192a386e8 | ||
|
6576960b2c | ||
|
7d529b95c4 | ||
|
ee735b67d2 | ||
|
4a991f9773 | ||
|
e22f28b1c6 | ||
|
06ccc28961 | ||
|
094ac9557b | ||
|
b59a54d020 | ||
|
b1ce077811 | ||
|
06f8a46912 | ||
|
1b68eabc57 | ||
|
bcf00da892 | ||
|
734c1bbcfc | ||
|
4ef7fe649d | ||
|
dd5c889dde | ||
|
7c0812eceb | ||
|
e7a70564c0 | ||
|
9e3faba490 | ||
|
14929a3ea5 | ||
|
90b4f46467 | ||
|
037e6fdef9 | ||
|
2415d5400e | ||
|
21a88c7333 | ||
|
a3466a3fec | ||
|
f49dad2a0e | ||
|
bc41537fe2 | ||
|
39e23eeec0 | ||
|
053540b119 | ||
|
a3720bdcce | ||
|
e338bdf059 | ||
|
dc8644a8c5 | ||
|
d00209e32c | ||
|
10258e5894 | ||
|
150f858358 | ||
|
499874a7b9 | ||
|
e4b98e80ec | ||
|
05ba7cc2a7 | ||
|
aa62355a53 | ||
|
17fd4903c5 | ||
|
bdca6f53d5 | ||
|
49c7933690 | ||
|
72e9b7f2ae | ||
|
42f90bc227 | ||
|
78c21c38b7 | ||
|
d8993a1170 | ||
|
25a52d7fca | ||
|
cd677498e8 | ||
|
58445dc816 | ||
|
b606028fc0 | ||
|
81466dcfec | ||
|
8623165405 | ||
|
e9a0162871 | ||
|
4d66ecf0d3 | ||
|
38987ace72 | ||
|
e094a0e019 | ||
|
3df6358a6d | ||
|
1553586196 | ||
|
6b25e80704 | ||
|
b5c2838870 | ||
|
9c0cac63ff | ||
|
add54ff1c7 | ||
|
8102c8b7bb | ||
|
73449abc2b | ||
|
d8118d058e | ||
|
1ae82067ce | ||
|
2f8255e336 | ||
|
80c192b99b | ||
|
a260adda92 | ||
|
3819674d60 | ||
|
afb0748963 | ||
|
cbff32c35c | ||
|
8a51531a09 | ||
|
187aa3fc23 | ||
|
d35f3cea17 | ||
|
d64383ffd0 | ||
|
35ede2f567 | ||
|
5844ceb022 | ||
|
542c208dde | ||
|
87a2c70364 | ||
|
01e59ebc99 | ||
|
4244a6ca66 | ||
|
29e9fc5416 | ||
|
7a1358e291 | ||
|
982e28f43a | ||
|
6f08380bc3 | ||
|
5504cf6cf9 | ||
|
f44cedc71d | ||
|
b8d0ecf1b3 | ||
|
475b881843 | ||
|
01c708a1b7 | ||
|
602c9bdd2b | ||
|
16a3563224 | ||
|
1dff79ed45 | ||
|
df630abf1a | ||
|
d3812b75e3 | ||
|
285a079b55 | ||
|
3b03aee937 | ||
|
4a4ff0d3ae | ||
|
3595b4802e | ||
|
e13fd327e5 | ||
|
0f74d13b9e | ||
|
34c3b29d2d | ||
|
c03db677e8 | ||
|
333f61e96f | ||
|
3ce159ac56 | ||
|
336a2d1c27 | ||
|
32fa4c916e | ||
|
1a698bb4d2 | ||
|
8a539713b6 | ||
|
d4f0936612 | ||
|
5dd819c241 | ||
|
d5101dba35 | ||
|
e071d43cce | ||
|
aaf894d5e6 | ||
|
df20ddd658 | ||
|
b88d57976a | ||
|
f808bb6b13 | ||
|
b64875495c | ||
|
0fb20c00d7 | ||
|
aa6fd1e0f5 | ||
|
f17cfd7946 | ||
|
abb76552fb | ||
|
0458aba520 | ||
|
e28c482d5d | ||
|
b30b2170cb | ||
|
3ccbccee77 | ||
|
f715cbd941 | ||
|
6b8cd8ac33 | ||
|
45b0983c4a | ||
|
d02c8f5681 | ||
|
dd03e43fbd | ||
|
b4bef0fb64 | ||
|
d4ab3e5752 | ||
|
bdc86fba9f | ||
|
629cd5ba8e | ||
|
37bedd23e4 | ||
|
70168608dd | ||
|
dada9884cd | ||
|
a5fb5aade5 | ||
|
ed2a349a45 | ||
|
c988547827 | ||
|
88bc3723ee | ||
|
239492c366 | ||
|
323e36c454 | ||
|
077f785c26 | ||
|
50bdb461c1 | ||
|
44848fbf49 | ||
|
4d9ee0160d | ||
|
49327b8257 | ||
|
c2f07ab3bb | ||
|
a98f586258 | ||
|
bfd963d0d2 | ||
|
5c72f2ec32 | ||
|
f6ccc0873a | ||
|
ba36c9eda1 | ||
|
88918445be | ||
|
abf88be21e | ||
|
7bf937e4bb | ||
|
752a0cf178 | ||
|
0d85ad7ab8 | ||
|
82a8080af4 | ||
|
da1b895cc5 | ||
|
aced1bf25e | ||
|
cd8c1a686b | ||
|
66d0ce915b | ||
|
4c0d17004a | ||
|
f0ce5198cf | ||
|
0e11c2e0fb | ||
|
de7d50753d | ||
|
3b7e367af1 | ||
|
7e177f8b04 | ||
|
750c12d5b3 | ||
|
c1f25225e0 | ||
|
134633fb6c | ||
|
758ff7fef5 | ||
|
3543a2442d | ||
|
5810984cbb | ||
|
5a23c53fff | ||
|
2b96284bab | ||
|
fb03cbe36a | ||
|
8dfae1f22d | ||
|
5feabac34d | ||
|
ea05c4598d | ||
|
6a25f4def6 | ||
|
8cfd961e2a | ||
|
eb9c99b0fd | ||
|
5592866540 | ||
|
d9a1e124e8 | ||
|
aa62c3b7b7 | ||
|
6d90812a9b | ||
|
6f8ea382a0 | ||
|
4860b552d5 | ||
|
3deed069e8 | ||
|
9803dc5b07 | ||
|
47d9d90d46 | ||
|
e5c49478ad | ||
|
61b96bf48a | ||
|
7b9dbca4b4 | ||
|
1a6f02c20a | ||
|
23766bd467 | ||
|
fc920227b2 | ||
|
6615352b77 | ||
|
419fbdb941 | ||
|
e3d600fc21 | ||
|
19e19610f8 | ||
|
f0177f7cea | ||
|
d278cae607 | ||
|
88a55f87ea | ||
|
c1c37d64a4 | ||
|
73a0bfe5a8 | ||
|
5ab7080342 | ||
|
1d8692714e | ||
|
1e48a0d862 | ||
|
20004b4416 | ||
|
9af75b0fbb | ||
|
386c3ce04c | ||
|
ee94bc8eea | ||
|
a4d19717db | ||
|
ceb06fd70c | ||
|
702116d8ad | ||
|
cdf6ff8030 | ||
|
a1624036d1 | ||
|
fce7b3fcb3 | ||
|
764d95f844 | ||
|
2d510e0aa3 | ||
|
d3d2eaf59e | ||
|
8b71fb7db5 | ||
|
3b0310ef47 | ||
|
a58f8d9020 | ||
|
8303b1d6fe | ||
|
a2204cebed | ||
|
7013e53eb3 | ||
|
e5be598dc9 | ||
|
df992995ca | ||
|
b66f0c6d56 | ||
|
a3aa285f55 | ||
|
4de7238c45 | ||
|
d6227bf009 | ||
|
a315f9ac2b | ||
|
24f8dfbf52 | ||
|
f46c08ec71 | ||
|
0c20423285 | ||
|
355bd72c8d | ||
|
397cf4da54 | ||
|
aca54dbeeb | ||
|
4821733dbc | ||
|
91012bbf71 | ||
|
c5c607f91e | ||
|
3d19904c24 | ||
|
a293d46558 | ||
|
e8205c35c7 | ||
|
bd8a6c4d6c |
95 changed files with 3532 additions and 329 deletions
.gitea/workflows
.gitignore.gitmodulesMakefileabstract-machine
am-kernelsflake.lockflake.nixgit_commit.shnemu
.clang-format.gitignore.result.tmpKconfigLICENSEMakefile
configs
default.nixinclude
scripts
src
cpu
isa
memory
monitor
utils
tests
npc
.envrc.gitignoreCMakeLists.txtMakefile
constr
core
csrc
csrc_nvboard
flake.lockflake.nixresource
vsrc
21
.gitea/workflows/abstract-machine-build.yml
Normal file
21
.gitea/workflows/abstract-machine-build.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
name: Build abstract machine with nix
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-abstract-machine:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: https://github.com/cachix/cachix-action@v14
|
||||
with:
|
||||
name: ysyx
|
||||
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build abstract-machine
|
||||
run: |
|
||||
nix build .?submodules=1#abstract-machine
|
||||
- name: Build nemu
|
||||
run: |
|
||||
nix build .?submodules=1#nemu
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,5 +1,3 @@
|
|||
*.*
|
||||
*
|
||||
!*/
|
||||
!/nemu/*
|
||||
!/nexus-am/*
|
||||
|
@ -11,3 +9,6 @@
|
|||
!.gitignore
|
||||
!init.sh
|
||||
/fceux-am
|
||||
/nvboard
|
||||
**/.cache
|
||||
**/result
|
||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "am-kernels"]
|
||||
path = am-kernels
|
||||
url = https://git.xinyang.life/xin/am-kernels.git
|
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ STUNAME = 李心杨
|
|||
# DO NOT modify the following code!!!
|
||||
|
||||
TRACER = tracer-ysyx
|
||||
GITFLAGS = -q --author='$(TRACER) <tracer@ysyx.org>' --no-verify --allow-empty
|
||||
GITFLAGS = -q --author='$(TRACER) <tracer@ysyx.org>' --no-verify --allow-empty --no-gpg-sign
|
||||
|
||||
YSYX_HOME = $(NEMU_HOME)/..
|
||||
WORK_BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
|
23
abstract-machine/.gitignore
vendored
23
abstract-machine/.gitignore
vendored
|
@ -1,19 +1,6 @@
|
|||
*
|
||||
!*/
|
||||
!*.h
|
||||
!*.c
|
||||
!*.cc
|
||||
!*.S
|
||||
!*.ld
|
||||
!*.sh
|
||||
!*.py
|
||||
!*.mk
|
||||
!Makefile
|
||||
!README
|
||||
!LICENSE
|
||||
.*
|
||||
_*
|
||||
*~
|
||||
build/
|
||||
!.gitignore
|
||||
**/.direnv/
|
||||
**/build/
|
||||
**/.envrc
|
||||
**/.cache
|
||||
.vscode
|
||||
compile_commands.json
|
||||
|
|
87
abstract-machine/CMakeLists.txt
Normal file
87
abstract-machine/CMakeLists.txt
Normal file
|
@ -0,0 +1,87 @@
|
|||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(abstract-machine)
|
||||
enable_language(CXX C ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
include(CMakePackageConfigHelpers) # Used to find libcheck
|
||||
include(CTest)
|
||||
|
||||
# -- General options
|
||||
set(ISA CACHE STRING "Target ISA")
|
||||
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
|
||||
string(TOUPPER ${ISA} ISA_UPPER)
|
||||
|
||||
cmake_dependent_option(
|
||||
__PLATFORM_NEMU__ "Run on NEMU"
|
||||
ON "ISA MATCHES \"(riscv | x86)\"" OFF)
|
||||
cmake_dependent_option(
|
||||
__PLATFORM_NATIVE__ "Run on native"
|
||||
ON "ISA MATCHES native" OFF)
|
||||
|
||||
# -- Set PLATFORM according to options
|
||||
set(MATCH_PLATFORM_PATTERN "^__PLATFORM_([A-Z]*)__")
|
||||
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
|
||||
|
||||
message(STATUS "ISA: ${ISA}")
|
||||
foreach(VAR IN LISTS CACHE_VARS)
|
||||
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
|
||||
# Retrieve the value of the cache variable
|
||||
get_property(VAR_VALUE CACHE ${VAR} PROPERTY VALUE)
|
||||
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
|
||||
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
|
||||
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(${PLATFORM} MATCHES "native")
|
||||
set(ARCH "native")
|
||||
else()
|
||||
set(ARCH ${ISA}-${PLATFORM})
|
||||
endif()
|
||||
string(TOUPPER ${ARCH} ARCH_UPPER)
|
||||
|
||||
# -- Target specific options
|
||||
cmake_dependent_option(
|
||||
NATIVE_USE_KLIB "Use Klib even if on native"
|
||||
ON "NOT __ISA_NATIVE__" OFF)
|
||||
|
||||
# -- Add compile definitions based on options
|
||||
add_compile_definitions(
|
||||
$<MAKE_C_IDENTIFIER:__ARCH_${ARCH_UPPER}__>
|
||||
__ISA_${ISA_UPPER}__
|
||||
__PLATFORM_${PLATFORM_UPPER}__
|
||||
)
|
||||
|
||||
add_compile_definitions(
|
||||
$<$<BOOL:${NATIVE_USE_KLIB}>:__NATIVE_USE_KLIB__>
|
||||
)
|
||||
|
||||
# -- Required compiler flags
|
||||
add_compile_options(
|
||||
# -Werror
|
||||
-Wno-main
|
||||
-fno-asynchronous-unwind-tables
|
||||
-fno-builtin
|
||||
-fno-stack-protector
|
||||
-U_FORTIFY_SOURCE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-ffreestanding>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
|
||||
|
||||
add_link_options(
|
||||
-znoexecstack
|
||||
)
|
||||
|
||||
# -- Include linker script here. Use this linker script at link time if INCLUDE_LINKER_SCRIPT is set to true
|
||||
set(LINKER_SCRIPT linker.ld)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
add_compile_options(-march=rv32if -mabi=ilp32)
|
||||
add_link_options(-march=rv32if -mabi=ilp32)
|
||||
|
||||
add_subdirectory(klib)
|
||||
add_subdirectory(am)
|
29
abstract-machine/CMakePresets.json
Normal file
29
abstract-machine/CMakePresets.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"version": 6,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "native",
|
||||
"displayName": "Native",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"ISA": "native",
|
||||
"__PLATFORM_NATIVE__": true,
|
||||
"NATIVE_USE_KLIB": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "riscv-nemu",
|
||||
"displayName": "Riscv32 NEMU",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"ISA": "riscv",
|
||||
"__PLATFORM_NEMU__": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -47,33 +47,32 @@ endif
|
|||
|
||||
### Create the destination directory (`build/$ARCH`)
|
||||
WORK_DIR = $(shell pwd)
|
||||
DST_DIR = $(WORK_DIR)/build/$(ARCH)
|
||||
BUILD_DIR ?= $(WORK_DIR)/build
|
||||
DST_DIR = $(BUILD_DIR)/$(ARCH)
|
||||
$(shell mkdir -p $(DST_DIR))
|
||||
|
||||
### Compilation targets (a binary image or archive)
|
||||
IMAGE_REL = build/$(NAME)-$(ARCH)
|
||||
IMAGE_REL = $(DST_DIR)/$(NAME)-$(ARCH)
|
||||
IMAGE = $(abspath $(IMAGE_REL))
|
||||
ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a
|
||||
ARCHIVE = $(BUILD_DIR)/$(NAME)-$(ARCH).a
|
||||
|
||||
### Collect the files to be linked: object files (`.o`) and libraries (`.a`)
|
||||
OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS))))
|
||||
LIBS := $(sort $(LIBS) am klib) # lazy evaluation ("=") causes infinite recursions
|
||||
LINKAGE = $(OBJS) \
|
||||
$(addsuffix -$(ARCH).a, $(join \
|
||||
$(addsuffix /build/, $(addprefix $(AM_HOME)/, $(LIBS))), \
|
||||
$(LIBS) ))
|
||||
$(addsuffix -$(ARCH).a, $(addprefix $(BUILD_DIR)/, $(LIBS)))
|
||||
|
||||
## 3. General Compilation Flags
|
||||
|
||||
### (Cross) compilers, e.g., mips-linux-gnu-g++
|
||||
AS = $(CROSS_COMPILE)gcc
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CXX = $(CROSS_COMPILE)g++
|
||||
LD = $(CROSS_COMPILE)ld
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
OBJDUMP = $(CROSS_COMPILE)objdump
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
READELF = $(CROSS_COMPILE)readelf
|
||||
AS ?= $(CROSS_COMPILE)gcc
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
CXX ?= $(CROSS_COMPILE)g++
|
||||
LD ?= $(CROSS_COMPILE)ld
|
||||
AR ?= $(CROSS_COMPILE)ar
|
||||
OBJDUMP ?= $(CROSS_COMPILE)objdump
|
||||
OBJCOPY ?= $(CROSS_COMPILE)objcopy
|
||||
READELF ?= $(CROSS_COMPILE)readelf
|
||||
|
||||
### Compilation flags
|
||||
INC_PATH += $(WORK_DIR)/include $(addsuffix /include/, $(addprefix $(AM_HOME)/, $(LIBS)))
|
||||
|
|
10
abstract-machine/am/CMakeLists.txt
Normal file
10
abstract-machine/am/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
add_library(am_interface INTERFACE)
|
||||
target_include_directories(am_interface INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
install(DIRECTORY include/ DESTINATION include/abstract-machine)
|
53
abstract-machine/am/src/CMakeLists.txt
Normal file
53
abstract-machine/am/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,53 @@
|
|||
if(ISA MATCHES "native")
|
||||
set(SOURCEDIR "./${PLATFORM}")
|
||||
else()
|
||||
set(SOURCEDIR "./${ISA}/${PLATFORM}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(${SOURCEDIR})
|
||||
|
||||
target_include_directories(am-${ARCH}
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
||||
target_link_libraries(am-${ARCH}
|
||||
PUBLIC klib_interface
|
||||
INTERFACE m)
|
||||
|
||||
# TODO: Check
|
||||
target_link_options(am-${ARCH} INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/${LINKER_SCRIPT}>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH}/${LINKER_SCRIPT}>)
|
||||
|
||||
# Interface compile flags
|
||||
target_link_options(am-${ARCH} INTERFACE
|
||||
-znoexecstack)
|
||||
|
||||
target_compile_options(am-${ARCH} INTERFACE
|
||||
-fno-asynchronous-unwind-tables
|
||||
-fno-builtin
|
||||
-fno-stack-protector
|
||||
-U_FORTIFY_SOURCE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-ffreestanding>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
|
||||
|
||||
install(TARGETS am-${ARCH} klib_interface am_interface
|
||||
EXPORT amTargets
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(EXPORT amTargets
|
||||
FILE amTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||
|
||||
configure_package_config_file(${CMAKE_SOURCE_DIR}/cmake/am-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||
|
||||
# TODO: check
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/scripts/${LINKER_SCRIPT}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
26
abstract-machine/am/src/native/CMakeLists.txt
Normal file
26
abstract-machine/am/src/native/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
include(CheckPIESupported)
|
||||
check_pie_supported()
|
||||
|
||||
set(SOURCES
|
||||
trap.S
|
||||
cte.c
|
||||
ioe.c
|
||||
mpe.c
|
||||
platform.c
|
||||
trm.c
|
||||
vme.c
|
||||
ioe/audio.c
|
||||
ioe/disk.c
|
||||
ioe/gpu.c
|
||||
ioe/input.c
|
||||
ioe/timer.c
|
||||
)
|
||||
add_library(am-native ${SOURCES})
|
||||
|
||||
# FIXME: get free(): invalid address when user program compiled without pie
|
||||
set_target_properties(am-native PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE TRUE
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
target_link_libraries(am-${ARCH} PUBLIC SDL2::SDL2)
|
34
abstract-machine/am/src/riscv/nemu/CMakeLists.txt
Normal file
34
abstract-machine/am/src/riscv/nemu/CMakeLists.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
include(nemu-settings)
|
||||
include(riscv-settings)
|
||||
|
||||
add_library(am-${ISA}-nemu
|
||||
cte.c
|
||||
start.S
|
||||
trap.S
|
||||
vme.c
|
||||
${NEMU_SOURCES}
|
||||
)
|
||||
|
||||
target_compile_options(am-${ISA}-nemu PRIVATE
|
||||
${NEMU_COMPILE_OPTIONS}
|
||||
${RISCV_COMPILE_OPTIONS})
|
||||
target_link_options(am-${ISA}-nemu PRIVATE
|
||||
${NEMU_LINK_OPITIONS}
|
||||
${RISCV_LINK_OPTIONS})
|
||||
target_include_directories(am-${ISA}-nemu PRIVATE
|
||||
${NEMU_INCLUDE_DIRECTORIES})
|
||||
target_link_options(am-${ISA}-nemu INTERFACE
|
||||
LINKER:--defsym=_pmem_start=0x80000000
|
||||
LINKER:--defsym=_entry_offset=0x0
|
||||
LINKER:--gc-sections
|
||||
LINKER:-e _start
|
||||
-nostartfiles)
|
||||
|
||||
target_compile_definitions(am-${ISA}-nemu PUBLIC
|
||||
ARCH_H="arch/riscv.h")
|
||||
target_compile_definitions(am-${ISA}-nemu PRIVATE
|
||||
ISA_H="riscv/riscv.h")
|
||||
|
||||
set_target_properties(am-${ISA}-nemu PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE OFF
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
|
9
abstract-machine/cmake/am-config.cmake.in
Normal file
9
abstract-machine/cmake/am-config.cmake.in
Normal file
|
@ -0,0 +1,9 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
if(${ARCH} MATCHES "native")
|
||||
find_dependency(SDL2 REQUIRED)
|
||||
endif()
|
||||
|
||||
# Include the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")
|
6
abstract-machine/cmake/klib-config.cmake.in
Normal file
6
abstract-machine/cmake/klib-config.cmake.in
Normal file
|
@ -0,0 +1,6 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# Include the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/klibTargets.cmake")
|
11
abstract-machine/cmake/nemu-settings.cmake
Normal file
11
abstract-machine/cmake/nemu-settings.cmake
Normal file
|
@ -0,0 +1,11 @@
|
|||
set(NEMU_COMPILE_OPTIONS -fdata-sections -ffunction-sections)
|
||||
set(NEMU_LINK_OPTIONS
|
||||
--defsym=_pmem_start=0x80000000
|
||||
--defsym=_entry_offset=0x0
|
||||
--gc-sections
|
||||
-e _start)
|
||||
set(NEMU_INCLUDE_DIRECTORIES
|
||||
${CMAKE_SOURCE_DIR}/am/src/platform/nemu/include)
|
||||
file(GLOB_RECURSE NEMU_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/am/src/platform/nemu/*.[cS])
|
||||
set(INCLUDE_LINKER_SCRIPT ON)
|
2
abstract-machine/cmake/riscv-settings.cmake
Normal file
2
abstract-machine/cmake/riscv-settings.cmake
Normal file
|
@ -0,0 +1,2 @@
|
|||
set(RISCV_COMPILE_OPTIONS)
|
||||
set(RISCV_LINK_OPTIONS)
|
26
abstract-machine/default.nix
Normal file
26
abstract-machine/default.nix
Normal file
|
@ -0,0 +1,26 @@
|
|||
{ stdenv,
|
||||
lib,
|
||||
cmake,
|
||||
SDL2,
|
||||
isa ? "native",
|
||||
platform ? "NEMU"
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "abstract-machine";
|
||||
version = "2024.02.18";
|
||||
|
||||
src = ./.;
|
||||
|
||||
cmakeFlags = [
|
||||
(lib.cmakeFeature "ISA" isa)
|
||||
(lib.cmakeBool "__PLATFORM_${lib.strings.toUpper platform}__" true)
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
|
||||
] ++ (if platform=="native" then [ SDL2 ] else [ ]);
|
||||
}
|
12
abstract-machine/klib/CMakeLists.txt
Normal file
12
abstract-machine/klib/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
add_library(klib_interface INTERFACE)
|
||||
target_include_directories(klib_interface
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
||||
|
||||
add_subdirectory(src)
|
||||
# add_subdirectory(tests)
|
||||
|
||||
install(DIRECTORY include/ DESTINATION include/abstract-machine)
|
|
@ -35,6 +35,7 @@ int atoi (const char *nptr);
|
|||
int printf (const char *format, ...);
|
||||
int sprintf (char *str, const char *format, ...);
|
||||
int snprintf (char *str, size_t size, const char *format, ...);
|
||||
int vprintf (const char *format, va_list ap);
|
||||
int vsprintf (char *str, const char *format, va_list ap);
|
||||
int vsnprintf (char *str, size_t size, const char *format, va_list ap);
|
||||
|
||||
|
|
33
abstract-machine/klib/src/CMakeLists.txt
Normal file
33
abstract-machine/klib/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
# find_package(FLEX)
|
||||
# find_package(BISON)
|
||||
|
||||
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
|
||||
|
||||
set(SOURCES
|
||||
cpp.c
|
||||
int64.c
|
||||
stdio.c
|
||||
stdlib.c
|
||||
string.c
|
||||
# ${FLEX_fmt_scanner_OUTPUTS}
|
||||
)
|
||||
|
||||
add_library(klib ${SOURCES})
|
||||
target_include_directories(klib PUBLIC $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
target_compile_definitions(klib PUBLIC $<TARGET_PROPERTY:am-${ARCH},INTERFACE_COMPILE_DEFINITIONS>)
|
||||
|
||||
install(TARGETS klib
|
||||
EXPORT klibTargets
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(EXPORT klibTargets
|
||||
FILE klibTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
configure_package_config_file(${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
|
@ -5,8 +5,20 @@
|
|||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
|
||||
int vprintf(const char *fmt, va_list ap) {
|
||||
const char *p = fmt;
|
||||
while(*p != '\0') {
|
||||
putch(*p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
panic("Not implemented");
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vsprintf(char *out, const char *fmt, va_list ap) {
|
||||
|
|
|
@ -5,43 +5,115 @@
|
|||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
panic("Not implemented");
|
||||
const char *p = s;
|
||||
size_t len = 0;
|
||||
while(*(p++) != '\0') len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *strcpy(char *dst, const char *src) {
|
||||
panic("Not implemented");
|
||||
char *p_dst = dst;
|
||||
const char *p_src = src;
|
||||
for(; *p_src != '\0'; p_src++, p_dst++) {
|
||||
*p_dst = *p_src;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *dst, const char *src, size_t n) {
|
||||
panic("Not implemented");
|
||||
int i = 0;
|
||||
for(; i < n && src[i] != '\0'; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
for(; i < n; i++) {
|
||||
dst[i] = '\0';
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strcat(char *dst, const char *src) {
|
||||
panic("Not implemented");
|
||||
char *p_dst = dst;
|
||||
const char *p_src = src;
|
||||
while(*p_dst != '\0') p_dst++;
|
||||
for(; *p_src != '\0'; p_src++, p_dst++) {
|
||||
*p_dst = *p_src;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
return dst;
|
||||
}
|
||||
|
||||
int strcmp(const char *s1, const char *s2) {
|
||||
panic("Not implemented");
|
||||
const char *p_s1 = s1, *p_s2 = s2;
|
||||
for(; *p_s1 == *p_s2; p_s1++, p_s2++) {
|
||||
if(*p_s1 == '\0' || *p_s2 == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *p_s1 - *p_s2;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
panic("Not implemented");
|
||||
const char *p_s1 = s1, *p_s2 = s2;
|
||||
int i = 0;
|
||||
for(i = 0; i < n - 1; i++) {
|
||||
if(s1[i] == '\0' || s2[i] == '\0')
|
||||
break;
|
||||
}
|
||||
return s1[i] - s2[i];
|
||||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
panic("Not implemented");
|
||||
uint8_t *p = s;
|
||||
for(int i = 0; i < n; i++) {
|
||||
p[i] = c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, size_t n) {
|
||||
panic("Not implemented");
|
||||
if (src + n > dst && src < dst) {
|
||||
size_t len = dst - src;
|
||||
void *p_dst = (void *)src + n;
|
||||
const void *p_src = src + n - len;
|
||||
while(p_dst >= dst) {
|
||||
memcpy(p_dst, p_src, len);
|
||||
p_src -= len;
|
||||
p_dst -= len;
|
||||
}
|
||||
if(n % len) memcpy(dst, src, n % len);
|
||||
} else if (dst < src && dst + n > src) {
|
||||
size_t len = src - dst;
|
||||
void *p_dst = dst;
|
||||
const void *p_src = src;
|
||||
while(p_src < src + n) {
|
||||
memcpy(p_dst, p_src, len);
|
||||
p_src += len;
|
||||
p_dst += len;
|
||||
}
|
||||
if(n % len) memcpy(p_dst, p_src, n % len);
|
||||
} else {
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memcpy(void *out, const void *in, size_t n) {
|
||||
panic("Not implemented");
|
||||
for (size_t i = 0 ; i < n ; i++) {
|
||||
*(uint8_t *)(out + i) = *(uint8_t *)(in + i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
panic("Not implemented");
|
||||
const uint8_t *p1 = s1, *p2 = s2;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if(*p1 != *p2)
|
||||
return p1 - p2;
|
||||
p1++; p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
17
abstract-machine/klib/tests/CMakeLists.txt
Normal file
17
abstract-machine/klib/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
set(TEST_SOURCES
|
||||
stdio
|
||||
string
|
||||
)
|
||||
|
||||
foreach(TEST IN LISTS TEST_SOURCES)
|
||||
add_executable(${TEST} ${TEST}.c)
|
||||
target_link_libraries(${TEST} am-${ARCH} klib m)
|
||||
target_include_directories(${TEST}
|
||||
PRIVATE $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
PRIVATE $<TARGET_PROPERTY:klib_interface,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
# TODO: Run tests in other configurations
|
||||
if(__PLATFORM_NATIVE__)
|
||||
add_test(NAME ${TEST} COMMAND ${TEST})
|
||||
endif()
|
||||
endforeach()
|
5
abstract-machine/klib/tests/stdio.c
Normal file
5
abstract-machine/klib/tests/stdio.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include <klib.h>
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
75
abstract-machine/klib/tests/string.c
Normal file
75
abstract-machine/klib/tests/string.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void test_strcpy() {
|
||||
char b[32];
|
||||
char *s;
|
||||
b[16]='a'; b[17]='b'; b[18]='c'; b[19]=0;
|
||||
panic_on((s = strcpy(b, b+16)) != b, "strcpy wrong return value");
|
||||
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
|
||||
panic_on((s = strcpy(b+1, b+16)) != b+1, "strcpy wrong return value");
|
||||
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
|
||||
|
||||
panic_on((s = strcpy(b+1, b+17)) != b+1, "strcpy wrong return value");
|
||||
panic_on(strcmp(s, "bc") != 0, "strcpy gave incorrect string");
|
||||
}
|
||||
|
||||
void test_strncpy() {
|
||||
char b[32];
|
||||
char *s;
|
||||
int i;
|
||||
b[3] = 'x'; b[4] = 0;
|
||||
panic_on((s = strncpy(b, "abc", 3)) != b, "strncpy wrong return value");
|
||||
panic_on(b[2] != 'c', "strncpy fails to copy last byte");
|
||||
panic_on(b[3] != 'x', "strncpy overruns buffer to null-terminate");
|
||||
}
|
||||
|
||||
void test_strncmp() {
|
||||
panic_on(strncmp("abcd", "abce", 3) != 0, "strncmp compares past n");
|
||||
panic_on(strncmp("abc", "abd", 3) == 0, "strncmp fails to compare n-1st byte");
|
||||
}
|
||||
|
||||
void test_memset() {
|
||||
uint8_t arr[128];
|
||||
arr[120] = 0xd;
|
||||
panic_on(memset(arr, 0xf, 120) != arr, "memset wrong return value");
|
||||
panic_on(arr[7] != 0xf, "memset fails to set value in range");
|
||||
panic_on(arr[120] != 0xd, "memset set value past n");
|
||||
}
|
||||
|
||||
void test_memcpy() {
|
||||
const uint8_t src[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
|
||||
uint8_t dst[8] = {0};
|
||||
memcpy(dst, src, 8);
|
||||
panic_on(memcmp(dst, src, 8) != 0, "memcpy fails to copy memory");
|
||||
}
|
||||
|
||||
void test_memmove() {
|
||||
const uint8_t ref[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
|
||||
uint8_t dst[8] = {0};
|
||||
const uint8_t ans1[] = { 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x0, 0x0 };
|
||||
const uint8_t ans2[] = { 0x1, 0x2, 0x2, 0x3, 0x4, 0x3, 0x0, 0x0 };
|
||||
const uint8_t ans3[] = { 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x3, 0x4 };
|
||||
memmove(dst, ref, 8);
|
||||
panic_on(memcmp(dst, ref, 8) != 0, "memmove fails to copy non-overlapping memory");
|
||||
|
||||
memmove(dst, dst + 2, 4);
|
||||
panic_on(memcmp(dst, ans1, 8) != 0, "memmove fails to copy overlapping memory (dst < src)");
|
||||
|
||||
memmove(dst + 2, dst + 1, 4);
|
||||
panic_on(memcmp(dst, ans2, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
|
||||
|
||||
memmove(dst + 3, dst, 5);
|
||||
panic_on(memcmp(dst, ans3, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_strcpy();
|
||||
test_strncpy();
|
||||
test_strncmp();
|
||||
test_memset();
|
||||
test_memcpy();
|
||||
test_memmove();
|
||||
return 0;
|
||||
}
|
BIN
abstract-machine/out/install/lib/libklib.a
Normal file
BIN
abstract-machine/out/install/lib/libklib.a
Normal file
Binary file not shown.
1
am-kernels
Submodule
1
am-kernels
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 2f559823a63cf6909d5a9e32dee47d6891caf553
|
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
59
flake.nix
Normal file
59
flake.nix
Normal file
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, ... }@inputs: with inputs;
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
crossPkgs = import nixpkgs {
|
||||
localSystem = system;
|
||||
crossSystem = {
|
||||
config = "riscv32-none-elf";
|
||||
gcc = {
|
||||
abi = "ilp32";
|
||||
arch = "rv32if";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; };
|
||||
packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = "nemu"; };
|
||||
|
||||
packages.am-kernels = crossPkgs.stdenv.mkDerivation rec {
|
||||
pname = "am-kernels-cmake";
|
||||
version = "2024.02.18";
|
||||
|
||||
src = ./am-kernels;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.cmake
|
||||
];
|
||||
|
||||
cmakeFlags = [
|
||||
(pkgs.lib.cmakeFeature "ISA" "riscv")
|
||||
(pkgs.lib.cmakeFeature "PLATFORM" "nemu")
|
||||
(pkgs.lib.cmakeFeature "CMAKE_INSTALL_DATADIR" "share")
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
# SDL2
|
||||
self.packages.${system}.abstract-machine
|
||||
];
|
||||
};
|
||||
|
||||
devShells.nemu = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
clang-tools
|
||||
gdb
|
||||
];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.nemu
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
41
git_commit.sh
Executable file
41
git_commit.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#/usr/bin/env bash
|
||||
|
||||
STUID=ysyx_22040000
|
||||
STUNAME=李心杨
|
||||
|
||||
TRACER=tracer-ysyx
|
||||
GITFLAGS="-q --author=$TRACER<tracer@ysyx.org> --no-verify --allow-empty --no-gpg-sign"
|
||||
|
||||
WORK_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
WORK_INDEX=.git/index.${WORK_BRANCH}
|
||||
TRACER_BRANCH=$TRACER
|
||||
|
||||
LOCK_DIR=.git/
|
||||
|
||||
git_soft_checkout () {
|
||||
git checkout --detach -q && git reset --soft $1 -q -- && git checkout $1 -q -- ;
|
||||
}
|
||||
|
||||
git_commit () {
|
||||
# create tracer branch if not existent
|
||||
git branch $TRACER_BRANCH -q 2>/dev/null || true
|
||||
# backup git index
|
||||
cp -a .git/index $WORK_INDEX
|
||||
# switch to tracer branch
|
||||
git_soft_checkout "$TRACER_BRANCH"
|
||||
# add files to commit
|
||||
git add . -A --ignore-errors
|
||||
# generate commit msg, commit changes in tracer branch
|
||||
printf "> $1 \n $STUID $STUNAME \n $(uname -a) \n $(uptime)\n" | git commit -F - $GITFLAGS
|
||||
git_soft_checkout "$WORK_BRANCH"
|
||||
mv $WORK_INDEX .git/index
|
||||
}
|
||||
|
||||
git_commit $1
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[OK] Git commit track"
|
||||
else
|
||||
echo "[FAIL] Git commit track" && false
|
||||
fi
|
||||
|
3
nemu/.clang-format
Normal file
3
nemu/.clang-format
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
74
nemu/.gitignore
vendored
74
nemu/.gitignore
vendored
|
@ -1,12 +1,66 @@
|
|||
*.*
|
||||
*
|
||||
!*/
|
||||
!Makefile
|
||||
!*.mk
|
||||
!*.[cSh]
|
||||
!*.cc
|
||||
!.gitignore
|
||||
!README.md
|
||||
!Kconfig
|
||||
include/config
|
||||
include/generated
|
||||
configs/defconfig
|
||||
build/
|
||||
.cache/
|
||||
.direnv/
|
||||
.config
|
||||
.config.old
|
||||
.envrc
|
||||
.metals/
|
||||
.vscode/
|
||||
compile_commands.json
|
||||
|
||||
### C ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
|
0
nemu/.result.tmp
Normal file
0
nemu/.result.tmp
Normal file
42
nemu/Kconfig
42
nemu/Kconfig
|
@ -143,14 +143,54 @@ config TRACE_END
|
|||
|
||||
config ITRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
||||
bool "Enable instruction tracer"
|
||||
bool "Enable instruction tracing"
|
||||
default y
|
||||
help
|
||||
Instraction tracing will log past instructions into a ring buffer
|
||||
and print them when NEMU exit unexpectedly.
|
||||
|
||||
config ITRACE_COND
|
||||
depends on ITRACE
|
||||
string "Only trace instructions when the condition is true"
|
||||
default "true"
|
||||
|
||||
config ITRACE_BUFFER
|
||||
depends on ITRACE
|
||||
int "Buffer size for intruction trace (unit: number of instructions)"
|
||||
default 10
|
||||
|
||||
config MTRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
||||
bool "Enable memory tracing"
|
||||
default n
|
||||
|
||||
config MTRACE_RANGE
|
||||
depends on MTRACE
|
||||
string "Memory trace active range"
|
||||
default "0x0-0xfffffff"
|
||||
help
|
||||
Memory tracer will only print memory access in these ranges.
|
||||
Use comma to seperate between ranges.
|
||||
|
||||
config MTRACE_RANGE_MAX
|
||||
depends on MTRACE
|
||||
int "Max range count in MTRACE_RANGE"
|
||||
default 10
|
||||
|
||||
config FTRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
||||
bool "Enable function tracing"
|
||||
default n
|
||||
|
||||
config FTRACE_STACK_SIZE
|
||||
depends on FTRACE
|
||||
int "Max function track stack size"
|
||||
default 256
|
||||
|
||||
config FTRACE_LOG
|
||||
depends on FTRACE
|
||||
bool "Print log when entering a funciton"
|
||||
default n
|
||||
|
||||
config DIFFTEST
|
||||
depends on TARGET_NATIVE_ELF
|
||||
|
|
127
nemu/LICENSE
Normal file
127
nemu/LICENSE
Normal file
|
@ -0,0 +1,127 @@
|
|||
木兰宽松许可证, 第2版
|
||||
|
||||
木兰宽松许可证, 第2版
|
||||
2020年1月 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体”是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
6. 语言
|
||||
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
|
||||
|
||||
条款结束
|
||||
|
||||
如何将木兰宽松许可证,第2版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
NEMU is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
|
||||
|
||||
Mulan Permissive Software License,Version 2
|
||||
|
||||
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
|
||||
January 2020 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular Contributor under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its Affiliates.
|
||||
|
||||
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
6. Language
|
||||
|
||||
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
|
||||
|
||||
END OF THE TERMS AND CONDITIONS
|
||||
|
||||
How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software
|
||||
|
||||
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
|
||||
|
||||
i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
|
||||
|
||||
ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
|
||||
|
||||
iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
|
||||
|
||||
|
||||
Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
NEMU is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
|
@ -40,7 +40,9 @@ SRCS-y += $(shell find -L $(DIRS-y) -name "*.c")
|
|||
SRCS = $(filter-out $(SRCS-BLACKLIST-y),$(SRCS-y))
|
||||
|
||||
# Extract compiler and options from menuconfig
|
||||
ifneq ($(CONFIG_CC),)
|
||||
CC = $(call remove_quote,$(CONFIG_CC))
|
||||
endif
|
||||
CFLAGS_BUILD += $(call remove_quote,$(CONFIG_CC_OPT))
|
||||
CFLAGS_BUILD += $(if $(CONFIG_CC_LTO),-flto,)
|
||||
CFLAGS_BUILD += $(if $(CONFIG_CC_DEBUG),-Og -ggdb3,)
|
||||
|
@ -48,6 +50,7 @@ CFLAGS_BUILD += $(if $(CONFIG_CC_ASAN),-fsanitize=address,)
|
|||
CFLAGS_TRACE += -DITRACE_COND=$(if $(CONFIG_ITRACE_COND),$(call remove_quote,$(CONFIG_ITRACE_COND)),true)
|
||||
CFLAGS += $(CFLAGS_BUILD) $(CFLAGS_TRACE) -D__GUEST_ISA__=$(GUEST_ISA)
|
||||
LDFLAGS += $(CFLAGS_BUILD)
|
||||
INC_PATH += $(NEMU_HOME)/src/isa/$(GUEST_ISA)/local-include
|
||||
|
||||
# Include rules for menuconfig
|
||||
include $(NEMU_HOME)/scripts/config.mk
|
||||
|
@ -59,3 +62,36 @@ else
|
|||
# Include rules to build NEMU
|
||||
include $(NEMU_HOME)/scripts/native.mk
|
||||
endif
|
||||
|
||||
include $(NEMU_HOME)/tests/Makefile
|
||||
unit-tests: TEST_OBJS = $(filter-out $(OBJ_DIR)/src/nemu-main.o, $(OBJS))
|
||||
unit-tests: CFLAGS += $(shell pkg-config --cflags check)
|
||||
unit-tests: LDFLAGS += $(shell pkg-config --libs check)
|
||||
unit-tests: $(TEST_SRCS:%.c=$(OBJ_DIR)/%)
|
||||
|
||||
IMAGES = $(patsubst %.bin, %, $(shell find $(IMAGES_PATH) -type f -name '*.bin'))
|
||||
|
||||
COLOR_RED = \033[1;31m
|
||||
COLOR_GREEN = \033[1;32m
|
||||
COLOR_BLUE = \033[1;34m
|
||||
COLOR_NONE = \033[0m
|
||||
|
||||
RESULT = .result.tmp
|
||||
$(shell > $(RESULT)) # Clear result file
|
||||
|
||||
$(IMAGES): %: %.bin $(BINARY)
|
||||
@echo + TEST $(notdir $<)
|
||||
@$(BINARY) -b $< >/dev/null 2>&1 || printf "\t%14s\n" $(notdir $<) >> $(RESULT)
|
||||
|
||||
integration-tests: $(IMAGES)
|
||||
@printf "$(COLOR_BLUE)INTEGRATION TEST:$(COLOR_NONE)\n\tALL: %s\n\tFAILED: %s\n" $(words $(IMAGES)) $(shell wc -l $(RESULT) | cut -f1 -d' ')
|
||||
@test ! -s $(RESULT) || printf "$(COLOR_RED)FAILED:$(COLOR_NONE)\n"
|
||||
@cat $(RESULT)
|
||||
@test ! -s $(RESULT); \
|
||||
r=$$?; \
|
||||
$(RM) $(RESULT); \
|
||||
test $$r -eq 0
|
||||
|
||||
test: unit-tests integration-tests
|
||||
|
||||
.PHONY: test unit-tests integration-tests
|
||||
|
|
74
nemu/configs/rv32_defconfig
Normal file
74
nemu/configs/rv32_defconfig
Normal file
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# NEMU Configuration Menu
|
||||
#
|
||||
# CONFIG_ISA_x86 is not set
|
||||
# CONFIG_ISA_mips32 is not set
|
||||
CONFIG_ISA_riscv=y
|
||||
# CONFIG_ISA_loongarch32r is not set
|
||||
CONFIG_ISA="riscv32"
|
||||
|
||||
#
|
||||
# ISA-dependent Options for riscv
|
||||
#
|
||||
# CONFIG_RV64 is not set
|
||||
# CONFIG_RVE is not set
|
||||
# end of ISA-dependent Options for riscv
|
||||
|
||||
CONFIG_ENGINE_INTERPRETER=y
|
||||
CONFIG_ENGINE="interpreter"
|
||||
CONFIG_MODE_SYSTEM=y
|
||||
CONFIG_TARGET_NATIVE_ELF=y
|
||||
# CONFIG_TARGET_SHARE is not set
|
||||
# CONFIG_TARGET_AM is not set
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
CONFIG_CC_GCC=y
|
||||
# CONFIG_CC_GPP is not set
|
||||
# CONFIG_CC_CLANG is not set
|
||||
CONFIG_CC="gcc"
|
||||
# CONFIG_CC_O0 is not set
|
||||
# CONFIG_CC_O1 is not set
|
||||
CONFIG_CC_O2=y
|
||||
# CONFIG_CC_O3 is not set
|
||||
CONFIG_CC_OPT="-O2"
|
||||
# CONFIG_CC_LTO is not set
|
||||
# CONFIG_CC_DEBUG is not set
|
||||
CONFIG_CC_ASAN=y
|
||||
# end of Build Options
|
||||
|
||||
#
|
||||
# Testing and Debugging
|
||||
#
|
||||
CONFIG_TRACE=y
|
||||
CONFIG_TRACE_START=0
|
||||
CONFIG_TRACE_END=10000
|
||||
CONFIG_ITRACE=y
|
||||
CONFIG_ITRACE_COND="true"
|
||||
# CONFIG_DIFFTEST is not set
|
||||
CONFIG_DIFFTEST_REF_PATH="none"
|
||||
CONFIG_DIFFTEST_REF_NAME="none"
|
||||
# end of Testing and Debugging
|
||||
|
||||
#
|
||||
# Memory Configuration
|
||||
#
|
||||
CONFIG_MBASE=0x80000000
|
||||
CONFIG_MSIZE=0x8000000
|
||||
CONFIG_PC_RESET_OFFSET=0
|
||||
# CONFIG_PMEM_MALLOC is not set
|
||||
CONFIG_PMEM_GARRAY=y
|
||||
CONFIG_MEM_RANDOM=y
|
||||
# end of Memory Configuration
|
||||
|
||||
# CONFIG_DEVICE is not set
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
CONFIG_TIMER_GETTIMEOFDAY=y
|
||||
# CONFIG_TIMER_CLOCK_GETTIME is not set
|
||||
CONFIG_RT_CHECK=y
|
||||
# end of Miscellaneous
|
63
nemu/default.nix
Normal file
63
nemu/default.nix
Normal file
|
@ -0,0 +1,63 @@
|
|||
{ pkgs,
|
||||
lib,
|
||||
stdenv,
|
||||
am-kernels,
|
||||
dtc
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "nemu";
|
||||
version = "2024-03-02";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
gnumake
|
||||
pkg-config
|
||||
flex
|
||||
bison
|
||||
dtc
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
readline
|
||||
libllvm
|
||||
];
|
||||
|
||||
checkInputs = [
|
||||
pkgs.check
|
||||
am-kernels
|
||||
];
|
||||
|
||||
configurePhase = ''
|
||||
export NEMU_HOME=$(pwd)
|
||||
make alldefconfig
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
make
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
checkPhase = ''
|
||||
export IMAGES_PATH=${am-kernels}/share/binary
|
||||
make test
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
make PREFIX=$out install
|
||||
'';
|
||||
|
||||
shellHook = ''
|
||||
export NEMU_HOME=$(pwd)
|
||||
export IMAGES_PATH=${am-kernels}/share/binary
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "NJU EMUlator, a full system x86/mips32/riscv32/riscv64 emulator for teaching";
|
||||
homepage = "https://github.com/NJU-ProjectN/nemu.git";
|
||||
license = with licenses; [ ];
|
||||
maintainers = with maintainers; [ ];
|
||||
};
|
||||
}
|
|
@ -17,12 +17,12 @@
|
|||
#define __COMMON_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <generated/autoconf.h>
|
||||
#include <macro.h>
|
||||
#include <types.h>
|
||||
|
||||
#ifdef CONFIG_TARGET_AM
|
||||
#include <klib.h>
|
||||
|
@ -31,19 +31,6 @@
|
|||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
|
||||
#define PMEM64 1
|
||||
#endif
|
||||
|
||||
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
|
||||
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
|
||||
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
|
||||
|
||||
typedef word_t vaddr_t;
|
||||
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
|
||||
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
|
||||
typedef uint16_t ioaddr_t;
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,6 @@ typedef struct Decode {
|
|||
vaddr_t snpc; // static next pc
|
||||
vaddr_t dnpc; // dynamic next pc
|
||||
ISADecodeInfo isa;
|
||||
IFDEF(CONFIG_ITRACE, char logbuf[128]);
|
||||
} Decode;
|
||||
|
||||
// --- pattern matching mechanism ---
|
||||
|
|
|
@ -16,12 +16,25 @@
|
|||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <stdio.h>
|
||||
#include <utils.h>
|
||||
#include <macro.h>
|
||||
|
||||
IFDEF(CONFIG_ITRACE, void log_itrace_print());
|
||||
|
||||
#define Trace(format, ...) \
|
||||
_Log("[TRACE] " format "\n", ## __VA_ARGS__)
|
||||
|
||||
#define Log(format, ...) \
|
||||
_Log(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \
|
||||
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||
|
||||
#define Warning(format, ...) \
|
||||
_Log(ANSI_FMT("[WARNING] %s:%d %s() ", ANSI_FG_YELLOW) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||
|
||||
#define Error(format, ...) \
|
||||
_Log(ANSI_FMT("[ERROR] %s:%d %s() ", ANSI_FG_RED) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||
|
||||
#define Assert(cond, format, ...) \
|
||||
|
@ -30,6 +43,7 @@
|
|||
MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \
|
||||
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \
|
||||
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
|
||||
IFDEF(CONFIG_ITRACE, log_itrace_print()); \
|
||||
extern void assert_fail_msg(); \
|
||||
assert_fail_msg(); \
|
||||
assert(cond); \
|
||||
|
|
18
nemu/include/ftrace.h
Normal file
18
nemu/include/ftrace.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef __FUNC_DEF_H__
|
||||
#define __FUNC_DEF_H__
|
||||
#include <common.h>
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
typedef struct {
|
||||
vaddr_t start;
|
||||
vaddr_t len;
|
||||
char * name;
|
||||
} func_t;
|
||||
|
||||
extern func_t *func_table;
|
||||
void ftrace_call(vaddr_t, vaddr_t);
|
||||
void ftrace_return(vaddr_t, vaddr_t);
|
||||
// const char *get_func_name(vaddr_t addr);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -92,6 +92,8 @@
|
|||
|
||||
#define PG_ALIGN __attribute((aligned(4096)))
|
||||
|
||||
#define FAILED_GOTO(tag, exp) do {if((exp)) goto tag;} while(0)
|
||||
|
||||
#if !defined(likely)
|
||||
#define likely(cond) __builtin_expect(cond, 1)
|
||||
#define unlikely(cond) __builtin_expect(cond, 0)
|
||||
|
|
21
nemu/include/types.h
Normal file
21
nemu/include/types.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
#include <inttypes.h>
|
||||
#include <macro.h>
|
||||
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
|
||||
#define PMEM64 1
|
||||
#endif
|
||||
|
||||
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
|
||||
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
|
||||
static const word_t WORD_T_MAX = MUXDEF(CONFIG_ISA64, UINT64_MAX, UINT32_MAX);
|
||||
static const sword_t SWORD_T_MAX = MUXDEF(CONFIG_ISA64, INT64_MAX, INT32_MAX);
|
||||
static const sword_t SWORD_T_MIN = MUXDEF(CONFIG_ISA64, INT64_MIN, INT32_MIN);
|
||||
#define WORD_BYTES MUXDEF(CONFIG_ISA64, 8, 4)
|
||||
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
|
||||
|
||||
typedef word_t vaddr_t;
|
||||
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
|
||||
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
|
||||
typedef uint16_t ioaddr_t;
|
||||
#endif
|
|
@ -16,7 +16,7 @@
|
|||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <types.h>
|
||||
|
||||
// ----------- state -----------
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ endif
|
|||
WORK_DIR = $(shell pwd)
|
||||
BUILD_DIR = $(WORK_DIR)/build
|
||||
|
||||
INC_PATH := $(WORK_DIR)/include $(INC_PATH)
|
||||
INC_PATH := $(WORK_DIR)/include $(BUILD_DIR)/include $(INC_PATH)
|
||||
OBJ_DIR = $(BUILD_DIR)/obj-$(NAME)$(SO)
|
||||
BINARY = $(BUILD_DIR)/$(NAME)$(SO)
|
||||
|
||||
|
@ -40,12 +40,34 @@ $(OBJ_DIR)/%.o: %.cc
|
|||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
$(call call_fixdep, $(@:.o=.d), $@)
|
||||
|
||||
$(OBJ_DIR)/%.tag.c: %.y
|
||||
@echo + YACC $<
|
||||
@mkdir -p $(dir $@) $(BUILD_DIR)/include
|
||||
@$(YACC) $(YFLAGS) --header=$(BUILD_DIR)/include/$(notdir $(<:.y=.h)) -o $@ $<
|
||||
|
||||
$(OBJ_DIR)/%.yy.c: %.l $(OBJ_DIR)/%.tag.c
|
||||
@echo + LEX $<
|
||||
@mkdir -p $(dir $@) $(BUILD_DIR)/include
|
||||
@$(LEX) $(LFLAGS) --header=$(BUILD_DIR)/include/$(notdir $(<:.l=_lex.h)) -o $@ $<
|
||||
|
||||
$(OBJ_DIR)/%.tag.o: $(OBJ_DIR)/%.tag.c
|
||||
@echo + CC $<
|
||||
@mkdir -p $(dir $@)
|
||||
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(call call_fixdep, $(@:.o=.d), $@)
|
||||
|
||||
$(OBJ_DIR)/%.yy.o: $(OBJ_DIR)/%.yy.c
|
||||
@echo + CC $<
|
||||
@mkdir -p $(dir $@)
|
||||
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(call call_fixdep, $(@:.o=.d), $@)
|
||||
|
||||
# Depencies
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
# Some convenient rules
|
||||
|
||||
.PHONY: app clean
|
||||
.PHONY: app install clean
|
||||
|
||||
app: $(BINARY)
|
||||
|
||||
|
@ -53,5 +75,9 @@ $(BINARY):: $(OBJS) $(ARCHIVES)
|
|||
@echo + LD $@
|
||||
@$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS)
|
||||
|
||||
install: $(BINARY)
|
||||
@mkdir -p $(PREFIX)/bin
|
||||
@cp $(BINARY) $(PREFIX)/bin/
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILD_DIR)
|
||||
|
|
|
@ -48,6 +48,9 @@ menuconfig: $(MCONF) $(CONF) $(FIXDEP)
|
|||
savedefconfig: $(CONF)
|
||||
$(Q)$< $(silent) --$@=configs/defconfig $(Kconfig)
|
||||
|
||||
alldefconfig: $(CONF) $(FIXDEP)
|
||||
$(Q)$(CONF) $(silent) --$@ $(Kconfig)
|
||||
|
||||
%defconfig: $(CONF) $(FIXDEP)
|
||||
$(Q)$< $(silent) --defconfig=configs/$@ $(Kconfig)
|
||||
$(Q)$< $(silent) --syncconfig $(Kconfig)
|
||||
|
@ -60,7 +63,7 @@ help:
|
|||
@echo ' savedefconfig - Save current config as configs/defconfig (minimal config)'
|
||||
|
||||
distclean: clean
|
||||
-@rm -rf $(rm-distclean)
|
||||
-rm -rf $(rm-distclean)
|
||||
|
||||
.PHONY: help distclean
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <utils.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/decode.h>
|
||||
#include <cpu/difftest.h>
|
||||
|
@ -29,14 +30,17 @@ CPU_state cpu = {};
|
|||
uint64_t g_nr_guest_inst = 0;
|
||||
static uint64_t g_timer = 0; // unit: us
|
||||
static bool g_print_step = false;
|
||||
IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]);
|
||||
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
|
||||
|
||||
void device_update();
|
||||
bool wp_eval_all();
|
||||
|
||||
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
||||
#ifdef CONFIG_ITRACE_COND
|
||||
if (ITRACE_COND) { log_write("%s\n", _this->logbuf); }
|
||||
if (ITRACE_COND) { log_write("%s\n", logbuf[logbuf_rear]); }
|
||||
#endif
|
||||
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(_this->logbuf)); }
|
||||
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); }
|
||||
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
|
||||
}
|
||||
|
||||
|
@ -46,8 +50,9 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
|||
isa_exec_once(s);
|
||||
cpu.pc = s->dnpc;
|
||||
#ifdef CONFIG_ITRACE
|
||||
char *p = s->logbuf;
|
||||
p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc);
|
||||
logbuf_rear = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER;
|
||||
char *p = logbuf[logbuf_rear];
|
||||
p += snprintf(p, sizeof(logbuf[logbuf_rear]), FMT_WORD ":", s->pc);
|
||||
int ilen = s->snpc - s->pc;
|
||||
int i;
|
||||
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
|
||||
|
@ -63,7 +68,7 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
|||
|
||||
#ifndef CONFIG_ISA_loongarch32r
|
||||
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
|
||||
disassemble(p, s->logbuf + sizeof(s->logbuf) - p,
|
||||
disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - p,
|
||||
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
|
||||
#else
|
||||
p[0] = '\0'; // the upstream llvm does not support loongarch32r
|
||||
|
@ -77,6 +82,10 @@ static void execute(uint64_t n) {
|
|||
exec_once(&s, cpu.pc);
|
||||
g_nr_guest_inst ++;
|
||||
trace_and_difftest(&s, cpu.pc);
|
||||
if (wp_eval_all()) {
|
||||
puts(logbuf[logbuf_rear]);
|
||||
break;
|
||||
}
|
||||
if (nemu_state.state != NEMU_RUNNING) break;
|
||||
IFDEF(CONFIG_DEVICE, device_update());
|
||||
}
|
||||
|
@ -116,13 +125,16 @@ void cpu_exec(uint64_t n) {
|
|||
switch (nemu_state.state) {
|
||||
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
|
||||
|
||||
case NEMU_END: case NEMU_ABORT:
|
||||
case NEMU_END: case NEMU_ABORT: {
|
||||
Log("nemu: %s at pc = " FMT_WORD,
|
||||
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
|
||||
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
|
||||
ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
|
||||
nemu_state.halt_pc);
|
||||
// fall through
|
||||
if(nemu_state.halt_ret != 0) {
|
||||
log_itrace_print();
|
||||
}
|
||||
} // fall through
|
||||
case NEMU_QUIT: statistic();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include "../local-include/reg.h"
|
||||
|
||||
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
|
||||
return false;
|
||||
for(int i = 0; i < MUXDEF(CONFIG_RVE, 16, 32); i++) {
|
||||
if(!difftest_check_reg(reg_name(i), pc, ref_r->gpr[i], gpr(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void isa_difftest_attach() {
|
||||
|
|
|
@ -1,29 +1,33 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan
|
||||
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
#include "local-include/reg.h"
|
||||
#include "macro.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <cpu/decode.h>
|
||||
#include <ftrace.h>
|
||||
#include <utils.h>
|
||||
|
||||
#define R(i) gpr(i)
|
||||
#define Mr vaddr_read
|
||||
#define Mw vaddr_write
|
||||
|
||||
enum {
|
||||
TYPE_I, TYPE_U, TYPE_S,
|
||||
TYPE_R, TYPE_I, TYPE_I_SHIFT, TYPE_U, TYPE_S, TYPE_B, TYPE_J,
|
||||
TYPE_N, // none
|
||||
};
|
||||
|
||||
|
@ -31,20 +35,45 @@ enum {
|
|||
#define src2R() do { *src2 = R(rs2); } while (0)
|
||||
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
|
||||
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
|
||||
#define immS() do { *imm = (SEXT(BITS(i, 31, 25), 7) << 5) | BITS(i, 11, 7); } while(0)
|
||||
#define immS() do { *imm = SEXT(BITS(i, 31, 25), 7) << 5 | BITS(i, 11, 7); } while(0)
|
||||
#define immB() do { *imm = SEXT(BITS(i, 31, 31), 1) << 12 | BITS(i, 30, 25) << 5 | BITS(i, 11, 8) << 1 | BITS(i, 7, 7) << 11; } while(0)
|
||||
#define immJ() do { *imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; } while(0)
|
||||
|
||||
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) {
|
||||
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
|
||||
word_t *imm, int type) {
|
||||
uint32_t i = s->isa.inst.val;
|
||||
int rs1 = BITS(i, 19, 15);
|
||||
int rs2 = BITS(i, 24, 20);
|
||||
*rd = BITS(i, 11, 7);
|
||||
switch (type) {
|
||||
case TYPE_R: src1R(); src2R(); break;
|
||||
case TYPE_I: src1R(); immI(); break;
|
||||
case TYPE_U: immU(); break;
|
||||
case TYPE_J: immJ(); break;
|
||||
case TYPE_S: src1R(); src2R(); immS(); break;
|
||||
case TYPE_B: src1R(); src2R(); immB(); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_branch(Decode *s, bool condition, word_t offset) {
|
||||
if (condition) {
|
||||
// puts(s->logbuf[s->logbuf_rear]);
|
||||
s->dnpc = s->pc + offset;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
|
||||
uint32_t i = s->isa.inst.val;
|
||||
int rs1 = BITS(i, 19, 15);
|
||||
if(rs1 == 1 && rd == 0) {
|
||||
ftrace_return(s->pc, dst);
|
||||
} else {
|
||||
ftrace_call(s->pc, dst);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int decode_exec(Decode *s) {
|
||||
int rd = 0;
|
||||
word_t src1 = 0, src2 = 0, imm = 0;
|
||||
|
@ -57,11 +86,63 @@ static int decode_exec(Decode *s) {
|
|||
}
|
||||
|
||||
INSTPAT_START();
|
||||
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui , U, R(rd) = imm);
|
||||
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
|
||||
|
||||
INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal , J, do {
|
||||
s->dnpc = s->pc + imm; R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm)); } while(0));
|
||||
INSTPAT("??????? ????? ????? ??? ????? 11001 11", jalr , I, do {
|
||||
s->dnpc = src1 + imm; R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm)); } while(0));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq , B, do_branch(s, src1 == src2, imm));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne , B, do_branch(s, src1 != src2, imm));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt , B, do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge , B, do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu , B, do_branch(s, src1 < src2, imm));
|
||||
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu , B, do_branch(s, src1 >= src2, imm));
|
||||
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb , I, R(rd) = SEXT(Mr(src1 + imm, 1), 8));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh , I, R(rd) = SEXT(Mr(src1 + imm, 2), 16));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw , I, R(rd) = SEXT(Mr(src1 + imm, 4), 32));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu , I, R(rd) = Mr(src1 + imm, 2));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh , S, Mw(src1 + imm, 2, src2));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw , S, Mw(src1 + imm, 4, src2));
|
||||
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi , I, R(rd) = src1 + imm);
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti , I, R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu , I, R(rd) = src1 < imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori , I, R(rd) = src1 ^ imm);
|
||||
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori , I, R(rd) = src1 | imm);
|
||||
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi , I, R(rd) = src1 & imm);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli , I, R(rd) = src1 << imm);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli , I, R(rd) = src1 >> imm);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai , I, R(rd) = (sword_t)src1 >> (imm & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add , R, R(rd) = src1 + src2);
|
||||
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub , R, R(rd) = src1 - src2);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll , R, R(rd) = src1 << src2);
|
||||
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt , R, R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu , R, R(rd) = src1 < src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor , R, R(rd) = src1 ^ src2);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl , R, R(rd) = src1 >> src2);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra , R, R(rd) = (sword_t)src1 >> (src2 & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or , R, R(rd) = src1 | src2);
|
||||
INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and , R, R(rd) = src1 & src2);
|
||||
|
||||
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
|
||||
|
||||
// "M"
|
||||
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul , R, R(rd) = src1 * src2);
|
||||
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh , R, R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu , R, R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu , R, R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div , R, R(rd) = (sword_t)src1 / (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu , R, R(rd) = src1 / src2);
|
||||
INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem , R, R(rd) = (sword_t)src1 % (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu , R, R(rd) = src1 % src2);
|
||||
|
||||
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
|
||||
INSTPAT_END();
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <isa.h>
|
||||
#include "local-include/reg.h"
|
||||
#include "macro.h"
|
||||
|
||||
const char *regs[] = {
|
||||
"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||
|
@ -24,8 +25,27 @@ const char *regs[] = {
|
|||
};
|
||||
|
||||
void isa_reg_display() {
|
||||
int colomn_per_row = 4;
|
||||
for(int i = 0; i < ARRLEN(regs); i++) {
|
||||
printf("\e[1;34m%3s\e[0m: " FMT_PADDR, reg_name(i), gpr(i));
|
||||
if (i % colomn_per_row == 3)
|
||||
putchar('\n');
|
||||
else
|
||||
putchar('|');
|
||||
}
|
||||
}
|
||||
|
||||
word_t isa_reg_str2val(const char *s, bool *success) {
|
||||
assert(s);
|
||||
int i;
|
||||
for (i = 0; i < 32 && strcmp(s, regs[i]) != 0; i++)
|
||||
;
|
||||
|
||||
if (i == 32) {
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
*success = true;
|
||||
|
||||
return gpr(i);
|
||||
}
|
||||
|
|
1
nemu/src/isa/riscv64
Symbolic link
1
nemu/src/isa/riscv64
Symbolic link
|
@ -0,0 +1 @@
|
|||
riscv32
|
|
@ -13,6 +13,8 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
#include <memory/host.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <device/mmio.h>
|
||||
|
@ -23,6 +25,11 @@ static uint8_t *pmem = NULL;
|
|||
#else // CONFIG_PMEM_GARRAY
|
||||
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
|
||||
#endif
|
||||
#ifdef CONFIG_MTRACE
|
||||
static word_t mtrace_start[CONFIG_MTRACE_RANGE_MAX] = {0};
|
||||
static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0};
|
||||
static int range_count = 0;
|
||||
#endif
|
||||
|
||||
uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
|
||||
paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; }
|
||||
|
@ -41,23 +48,58 @@ static void out_of_bound(paddr_t addr) {
|
|||
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTRACE
|
||||
static void mtrace_print(char type, word_t addr, int len, word_t data) {
|
||||
for (int i = 0; i < range_count; i++)
|
||||
if (addr <= mtrace_end[i] && addr >= mtrace_start[i] ) {
|
||||
Trace("Mem %c " FMT_PADDR "%d D " FMT_PADDR, type, addr, len, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_mem() {
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
pmem = malloc(CONFIG_MSIZE);
|
||||
assert(pmem);
|
||||
#endif
|
||||
#ifdef CONFIG_MTRACE
|
||||
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
|
||||
char *saveptr, *ptr;
|
||||
ptr = strtok_r(range, ",", &saveptr);
|
||||
for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX; ) {
|
||||
word_t start, end;
|
||||
Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2, "Config option MTRACE_RANGE has wrong format");
|
||||
mtrace_start[range_count] = start;
|
||||
mtrace_end[range_count] = end;
|
||||
|
||||
range_count++;
|
||||
ptr = strtok_r(NULL, ",", &saveptr);
|
||||
if (!ptr) break;
|
||||
}
|
||||
Trace("MTRACE ranges: ");
|
||||
for (int i = 0; i < range_count; i++) {
|
||||
Trace("[0x%x, 0x%x]", mtrace_start[i], mtrace_end[i]);
|
||||
}
|
||||
#endif
|
||||
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
|
||||
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
|
||||
}
|
||||
|
||||
word_t paddr_read(paddr_t addr, int len) {
|
||||
if (likely(in_pmem(addr))) return pmem_read(addr, len);
|
||||
IFDEF(CONFIG_DEVICE, return mmio_read(addr, len));
|
||||
word_t result = 0;
|
||||
if (likely(in_pmem(addr))) { result = pmem_read(addr, len); goto mtrace;}
|
||||
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace)
|
||||
out_of_bound(addr);
|
||||
return 0;
|
||||
|
||||
mtrace:
|
||||
IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void paddr_write(paddr_t addr, int len, word_t data) {
|
||||
IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, data));
|
||||
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
|
||||
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
|
||||
out_of_bound(addr);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <isa.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <utils.h>
|
||||
|
||||
void init_rand();
|
||||
void init_log(const char *log_file);
|
||||
|
@ -32,8 +33,6 @@ static void welcome() {
|
|||
Log("Build time: %s, %s", __TIME__, __DATE__);
|
||||
printf("Welcome to %s-NEMU!\n", ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
|
||||
printf("For help, type \"help\"\n");
|
||||
Log("Exercise: Please remove me in the source code and compile NEMU again.");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TARGET_AM
|
||||
|
@ -42,6 +41,7 @@ static void welcome() {
|
|||
void sdb_set_batch_mode();
|
||||
|
||||
static char *log_file = NULL;
|
||||
static char *elf_file = NULL;
|
||||
static char *diff_so_file = NULL;
|
||||
static char *img_file = NULL;
|
||||
static int difftest_port = 1234;
|
||||
|
@ -74,6 +74,7 @@ static int parse_args(int argc, char *argv[]) {
|
|||
{"log" , required_argument, NULL, 'l'},
|
||||
{"diff" , required_argument, NULL, 'd'},
|
||||
{"port" , required_argument, NULL, 'p'},
|
||||
{"elf" , required_argument, NULL, 'f'},
|
||||
{"help" , no_argument , NULL, 'h'},
|
||||
{0 , 0 , NULL, 0 },
|
||||
};
|
||||
|
@ -84,6 +85,7 @@ static int parse_args(int argc, char *argv[]) {
|
|||
case 'p': sscanf(optarg, "%d", &difftest_port); break;
|
||||
case 'l': log_file = optarg; break;
|
||||
case 'd': diff_so_file = optarg; break;
|
||||
case 'f': elf_file = optarg; break;
|
||||
case 1: img_file = optarg; return 0;
|
||||
default:
|
||||
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
|
||||
|
@ -91,6 +93,7 @@ static int parse_args(int argc, char *argv[]) {
|
|||
printf("\t-l,--log=FILE output log to FILE\n");
|
||||
printf("\t-d,--diff=REF_SO run DiffTest with reference REF_SO\n");
|
||||
printf("\t-p,--port=PORT run DiffTest with port PORT\n");
|
||||
printf("\t-f,--elf=FILE elf file with debug info\n");
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -128,6 +131,16 @@ void init_monitor(int argc, char *argv[]) {
|
|||
/* Initialize the simple debugger. */
|
||||
init_sdb();
|
||||
|
||||
// printf("elf_file: %s\n", elf_file);
|
||||
if(elf_file != NULL) {
|
||||
#ifdef CONFIG_FTRACE
|
||||
void init_elf(const char *path);
|
||||
init_elf(elf_file);
|
||||
#else
|
||||
Warning("Elf file provided, but ftrace not turned on. Ignoring elf file.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ISA_loongarch32r
|
||||
IFDEF(CONFIG_ITRACE, init_disasm(
|
||||
MUXDEF(CONFIG_ISA_x86, "i686",
|
||||
|
|
24
nemu/src/monitor/sdb/addrexp.l
Normal file
24
nemu/src/monitor/sdb/addrexp.l
Normal file
|
@ -0,0 +1,24 @@
|
|||
%{
|
||||
#include <isa.h>
|
||||
#include <addrexp.h>
|
||||
static bool success = false;
|
||||
void yyerror(word_t *result, const char *err);
|
||||
%}
|
||||
%option noyywrap
|
||||
|
||||
%%
|
||||
|
||||
0[xX][0-9a-fA-F]+ { yylval = strtoul(yytext, NULL, 16); return HEX_NUMBER; }
|
||||
[0-9]+ { yylval = strtoul(yytext, NULL, 10); return NUMBER; }
|
||||
$[asgprt$][0-9pa][0-9]? {
|
||||
yylval = isa_reg_str2val(yytext + 1, &success);
|
||||
if(!success) {
|
||||
yyerror(NULL, "Failed to convert reg to value");
|
||||
return YYerror;
|
||||
}
|
||||
return REGISTER;
|
||||
}
|
||||
[+\-*/<=()] { return *yytext; }
|
||||
[ \t] { }
|
||||
. { printf("Unexpected character: %s\n", yytext); return YYerror; }
|
||||
%%
|
60
nemu/src/monitor/sdb/addrexp.y
Normal file
60
nemu/src/monitor/sdb/addrexp.y
Normal file
|
@ -0,0 +1,60 @@
|
|||
%code requires {
|
||||
#include <common.h>
|
||||
#include <memory/vaddr.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
extern int yylex(void);
|
||||
}
|
||||
%{
|
||||
#include <common.h>
|
||||
#include <utils.h>
|
||||
#include <isa.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
void yyerror(word_t *result, const char *err) {
|
||||
Error("%s", err);
|
||||
}
|
||||
%}
|
||||
|
||||
%token NUMBER HEX_NUMBER
|
||||
%token REGISTER
|
||||
%locations
|
||||
%start input
|
||||
%define api.value.type { word_t }
|
||||
%parse-param { uint32_t *result }
|
||||
%left '-' '+'
|
||||
%left '*' '/'
|
||||
|
||||
%%
|
||||
input
|
||||
: expression { *result = $1; }
|
||||
;
|
||||
|
||||
expression
|
||||
: number { $$ = $1; }
|
||||
| expression '>' '=' expression { $$ = ($1 >= $4); }
|
||||
| expression '<' '=' expression { $$ = ($1 <= $4); }
|
||||
| expression '=' '=' expression { $$ = ($1 == $4); }
|
||||
| expression '!' '=' expression { $$ = ($1 == $4); }
|
||||
| expression '>' expression { $$ = ($1 > $3); }
|
||||
| expression '<' expression { $$ = ($1 < $3); }
|
||||
| expression '+' expression { $$ = $1 + $3; }
|
||||
| expression '-' expression { $$ = $1 - $3; }
|
||||
| expression '*' expression { $$ = $1 * $3; }
|
||||
| expression '/' expression {
|
||||
if($3 == 0) {
|
||||
fprintf(stderr, "Error: divide by zero at %u / %u\n", $1, $3);
|
||||
YYABORT;
|
||||
};
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| '-' number { $$ = -$2; }
|
||||
| '*' expression { $$ = vaddr_read($2, WORD_BYTES); }
|
||||
| '(' expression ')' { $$ = $2; }
|
||||
|
||||
number
|
||||
: REGISTER
|
||||
| NUMBER
|
||||
| HEX_NUMBER
|
||||
|
||||
%%
|
|
@ -1,125 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <isa.h>
|
||||
|
||||
/* We use the POSIX regex functions to process regular expressions.
|
||||
* Type 'man regex' for more information about POSIX regex functions.
|
||||
*/
|
||||
#include <regex.h>
|
||||
|
||||
enum {
|
||||
TK_NOTYPE = 256, TK_EQ,
|
||||
|
||||
/* TODO: Add more token types */
|
||||
|
||||
};
|
||||
|
||||
static struct rule {
|
||||
const char *regex;
|
||||
int token_type;
|
||||
} rules[] = {
|
||||
|
||||
/* TODO: Add more rules.
|
||||
* Pay attention to the precedence level of different rules.
|
||||
*/
|
||||
|
||||
{" +", TK_NOTYPE}, // spaces
|
||||
{"\\+", '+'}, // plus
|
||||
{"==", TK_EQ}, // equal
|
||||
};
|
||||
|
||||
#define NR_REGEX ARRLEN(rules)
|
||||
|
||||
static regex_t re[NR_REGEX] = {};
|
||||
|
||||
/* Rules are used for many times.
|
||||
* Therefore we compile them only once before any usage.
|
||||
*/
|
||||
void init_regex() {
|
||||
int i;
|
||||
char error_msg[128];
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < NR_REGEX; i ++) {
|
||||
ret = regcomp(&re[i], rules[i].regex, REG_EXTENDED);
|
||||
if (ret != 0) {
|
||||
regerror(ret, &re[i], error_msg, 128);
|
||||
panic("regex compilation failed: %s\n%s", error_msg, rules[i].regex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct token {
|
||||
int type;
|
||||
char str[32];
|
||||
} Token;
|
||||
|
||||
static Token tokens[32] __attribute__((used)) = {};
|
||||
static int nr_token __attribute__((used)) = 0;
|
||||
|
||||
static bool make_token(char *e) {
|
||||
int position = 0;
|
||||
int i;
|
||||
regmatch_t pmatch;
|
||||
|
||||
nr_token = 0;
|
||||
|
||||
while (e[position] != '\0') {
|
||||
/* Try all rules one by one. */
|
||||
for (i = 0; i < NR_REGEX; i ++) {
|
||||
if (regexec(&re[i], e + position, 1, &pmatch, 0) == 0 && pmatch.rm_so == 0) {
|
||||
char *substr_start = e + position;
|
||||
int substr_len = pmatch.rm_eo;
|
||||
|
||||
Log("match rules[%d] = \"%s\" at position %d with len %d: %.*s",
|
||||
i, rules[i].regex, position, substr_len, substr_len, substr_start);
|
||||
|
||||
position += substr_len;
|
||||
|
||||
/* TODO: Now a new token is recognized with rules[i]. Add codes
|
||||
* to record the token in the array `tokens'. For certain types
|
||||
* of tokens, some extra actions should be performed.
|
||||
*/
|
||||
|
||||
switch (rules[i].token_type) {
|
||||
default: TODO();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == NR_REGEX) {
|
||||
printf("no match at position %d\n%s\n%*.s^\n", position, e, position, "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
word_t expr(char *e, bool *success) {
|
||||
if (!make_token(e)) {
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Insert codes to evaluate the expression. */
|
||||
TODO();
|
||||
|
||||
return 0;
|
||||
}
|
2
nemu/src/monitor/sdb/filelist.mk
Normal file
2
nemu/src/monitor/sdb/filelist.mk
Normal file
|
@ -0,0 +1,2 @@
|
|||
SRCS-y += src/monitor/sdb/addrexp.tag.c src/monitor/sdb/addrexp.yy.c
|
||||
LFLAGS += -DYY_NO_UNPUT -DYY_NO_INPUT
|
|
@ -1,31 +1,77 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan
|
||||
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <isa.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include "sdb.h"
|
||||
#include "common.h"
|
||||
#include "sys/types.h"
|
||||
#include <addrexp.h>
|
||||
#include <addrexp_lex.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <errno.h>
|
||||
#include <isa.h>
|
||||
#include <memory/vaddr.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static int is_batch_mode = false;
|
||||
|
||||
// command handlers
|
||||
static int cmd_help(char *args);
|
||||
static int cmd_c(char *args);
|
||||
static int cmd_p(char *args);
|
||||
static int cmd_q(char *args);
|
||||
static int cmd_w(char *args);
|
||||
static int cmd_x(char *args);
|
||||
static int cmd_si(char *args);
|
||||
static int cmd_info(char *args);
|
||||
static int cmd_info_r(char *args);
|
||||
static int cmd_info_w(char *args);
|
||||
|
||||
static struct CommandTable {
|
||||
const char *name;
|
||||
const char *description;
|
||||
int (*handler)(char *);
|
||||
struct CommandTable *subcommand;
|
||||
int nr_subcommand;
|
||||
} cmd_info_table[] =
|
||||
{
|
||||
{"r", "List all registers and their contents", cmd_info_r, NULL, 0},
|
||||
{"w", "Status of specified watchpoints", cmd_info_w, NULL, 0},
|
||||
},
|
||||
cmd_table[] = {
|
||||
{"help", "Display information about all supported commands", cmd_help,
|
||||
NULL, 0},
|
||||
{"c", "Continue the execution of the program", cmd_c, NULL, 0},
|
||||
{"p", "Print expression result", cmd_p, NULL, 0},
|
||||
{"q", "Exit NEMU", cmd_q, NULL, 0},
|
||||
{"x", "Examine content of physical memory address", cmd_x, NULL, 0},
|
||||
{"w", "Break when expression is changed", cmd_w, NULL, 0},
|
||||
{"si", "Execute next [n] program line", cmd_si, NULL, 0},
|
||||
{"info", "Print information of registers or watchpoints", cmd_info,
|
||||
cmd_info_table, ARRLEN(cmd_info_table)},
|
||||
};
|
||||
|
||||
#define NR_CMD ARRLEN(cmd_table)
|
||||
|
||||
void init_regex();
|
||||
void init_wp_pool();
|
||||
|
||||
/* We use the `readline' library to provide more flexibility to read from stdin. */
|
||||
static char* rl_gets() {
|
||||
/* We use the `readline' library to provide more flexibility to read from stdin.
|
||||
*/
|
||||
static char *rl_gets() {
|
||||
static char *line_read = NULL;
|
||||
|
||||
if (line_read) {
|
||||
|
@ -33,7 +79,7 @@ static char* rl_gets() {
|
|||
line_read = NULL;
|
||||
}
|
||||
|
||||
line_read = readline("(nemu) ");
|
||||
line_read = readline("\e[1;34m(nemu)\e[0m ");
|
||||
|
||||
if (line_read && *line_read) {
|
||||
add_history(line_read);
|
||||
|
@ -42,32 +88,191 @@ static char* rl_gets() {
|
|||
return line_read;
|
||||
}
|
||||
|
||||
/* Extract Integer from a string. Can handle hex, binary and decimal numbers.
|
||||
* Print error if meet any error.
|
||||
* Return `UINTMAX_MAX` if the string is invalid or number exceed the limit of
|
||||
* uint.
|
||||
*/
|
||||
static word_t parse_uint(const char *arg, bool *success) {
|
||||
if (arg == NULL) {
|
||||
puts("Invalid uint argument.");
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
int base = 10;
|
||||
int token_length = strnlen(arg, 34);
|
||||
if (token_length > 2) {
|
||||
if (arg[0] == '0' && (arg[1] == 'b' || arg[1] == 'B')) {
|
||||
base = 2;
|
||||
arg = arg + 2;
|
||||
} else if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) {
|
||||
base = 16;
|
||||
arg = arg + 2;
|
||||
}
|
||||
}
|
||||
char *endptr;
|
||||
uintmax_t n = strtoumax(arg, &endptr, base);
|
||||
if (errno == ERANGE || n > WORD_T_MAX) {
|
||||
printf("%s exceed the limit of uint\n", arg);
|
||||
*success = false;
|
||||
return 0;
|
||||
} else if (arg == endptr) {
|
||||
puts("Invalid uint argument.");
|
||||
*success = false;
|
||||
return 0;
|
||||
} else if (n > WORD_T_MAX) {
|
||||
*success = false;
|
||||
return WORD_T_MAX;
|
||||
} else {
|
||||
*success = true;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
word_t parse_expr(const char *arg, bool *success) {
|
||||
if (arg == NULL) {
|
||||
puts("Invalid expr argument.");
|
||||
*success = false;
|
||||
return 0;
|
||||
} else {
|
||||
word_t res;
|
||||
yy_scan_string(arg);
|
||||
*success = !yyparse(&res);
|
||||
yylex_destroy();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_c(char *args) {
|
||||
cpu_exec(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_p(char *args) {
|
||||
char *arg = strtok(NULL, "");
|
||||
bool res = false;
|
||||
|
||||
word_t result = parse_expr(arg, &res);
|
||||
if (!res)
|
||||
goto wrong_usage;
|
||||
printf("%s: %u\n", arg, result);
|
||||
return 0;
|
||||
|
||||
wrong_usage:
|
||||
printf("Invalid argument for command p: %s\n", arg);
|
||||
printf("Usage: p [EXPR: <expr>]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_q(char *args) {
|
||||
nemu_state.state = NEMU_QUIT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cmd_help(char *args);
|
||||
/* Single stepping
|
||||
* <step>: execute <step> step
|
||||
*/
|
||||
static int cmd_si(char *args) {
|
||||
char *arg = strtok(NULL, " ");
|
||||
if (arg == NULL) {
|
||||
cpu_exec(1);
|
||||
} else {
|
||||
bool res = false;
|
||||
word_t n = parse_uint(arg, &res);
|
||||
if (!res)
|
||||
goto wrong_usage;
|
||||
cpu_exec(n);
|
||||
}
|
||||
return 0;
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
const char *description;
|
||||
int (*handler) (char *);
|
||||
} cmd_table [] = {
|
||||
{ "help", "Display information about all supported commands", cmd_help },
|
||||
{ "c", "Continue the execution of the program", cmd_c },
|
||||
{ "q", "Exit NEMU", cmd_q },
|
||||
wrong_usage:
|
||||
printf("Invalid argument for command si: %s\n", args);
|
||||
printf("Usage: si [N: uint]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Add more commands */
|
||||
static int cmd_info_r(char *args) {
|
||||
isa_reg_display();
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
static int cmd_info_w(char *args) {
|
||||
printf("Not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NR_CMD ARRLEN(cmd_table)
|
||||
static int cmd_w(char *args) {
|
||||
char *expr = strtok(NULL, "");
|
||||
wp_add(expr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_x(char *args) {
|
||||
char *arg = strtok(NULL, " ");
|
||||
bool res = false;
|
||||
word_t n = parse_uint(arg, &res);
|
||||
if (!res)
|
||||
goto wrong_usage;
|
||||
// No deliminter here, just pass all the remain argument to `parse_expr()`
|
||||
arg = strtok(NULL, "");
|
||||
word_t start_addr = parse_expr(arg, &res);
|
||||
if (!res)
|
||||
goto wrong_usage;
|
||||
start_addr = start_addr & ~(WORD_BYTES - 1);
|
||||
for (vaddr_t vaddr = start_addr; vaddr < start_addr + n; vaddr += WORD_BYTES) {
|
||||
word_t value = vaddr_read(vaddr, WORD_BYTES);
|
||||
printf("\e[1;34m" FMT_PADDR "\e[0m"
|
||||
" " FMT_WORD "\n",
|
||||
vaddr, value);
|
||||
}
|
||||
return 0;
|
||||
|
||||
wrong_usage:
|
||||
printf("Invalid argument for command x: %s\n", arg);
|
||||
printf("Usage: x [N: uint] [EXPR: <expr>]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_info(char *args) {
|
||||
char *arg = strtok(NULL, " ");
|
||||
int i;
|
||||
if (arg == NULL) {
|
||||
goto wrong_usage;
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < ARRLEN(cmd_info_table); i++) {
|
||||
if (strcmp(arg, cmd_info_table[i].name) == 0) {
|
||||
cmd_info_table[i].handler(args);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
wrong_usage:
|
||||
printf("Invalid argument for command info: %s\n", args);
|
||||
printf("Usage: info [r | w]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_help_print(char *args, struct CommandTable *cur_cmd_table,
|
||||
int cur_nr_cmd) {
|
||||
int i;
|
||||
char *arg = strtok(NULL, " ");
|
||||
if (arg == NULL) {
|
||||
return -1;
|
||||
} else {
|
||||
for (i = 0; i < cur_nr_cmd; i++) {
|
||||
if (strcmp(arg, cur_cmd_table[i].name) == 0) {
|
||||
printf("%s ", cur_cmd_table[i].name);
|
||||
if (cmd_help_print(arg, cur_cmd_table[i].subcommand,
|
||||
cur_cmd_table[i].nr_subcommand) == -1) {
|
||||
printf("-- %s\n", cur_cmd_table[i].description);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_help(char *args) {
|
||||
/* extract the first argument */
|
||||
|
@ -76,14 +281,23 @@ static int cmd_help(char *args) {
|
|||
|
||||
if (arg == NULL) {
|
||||
/* no argument given */
|
||||
for (i = 0; i < NR_CMD; i ++) {
|
||||
printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description);
|
||||
for (i = 0; i < NR_CMD; i++) {
|
||||
printf("%s -- %s\n", cmd_table[i].name, cmd_table[i].description);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < NR_CMD; i ++) {
|
||||
} else {
|
||||
for (i = 0; i < NR_CMD; i++) {
|
||||
if (strcmp(arg, cmd_table[i].name) == 0) {
|
||||
printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description);
|
||||
printf("%s ", cmd_table[i].name);
|
||||
if (cmd_help_print(args, cmd_table[i].subcommand,
|
||||
cmd_table[i].nr_subcommand) == -1) {
|
||||
printf("-- %s\n", cmd_table[i].description);
|
||||
// Print available subcommands
|
||||
for (int j = 0; j < cmd_table[i].nr_subcommand; j++) {
|
||||
struct CommandTable *sub_cmd_table = cmd_table[i].subcommand;
|
||||
printf(" > %s -- %s\n", sub_cmd_table[j].name,
|
||||
sub_cmd_table[j].description);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -92,9 +306,7 @@ static int cmd_help(char *args) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sdb_set_batch_mode() {
|
||||
is_batch_mode = true;
|
||||
}
|
||||
void sdb_set_batch_mode() { is_batch_mode = true; }
|
||||
|
||||
void sdb_mainloop() {
|
||||
if (is_batch_mode) {
|
||||
|
@ -102,12 +314,14 @@ void sdb_mainloop() {
|
|||
return;
|
||||
}
|
||||
|
||||
for (char *str; (str = rl_gets()) != NULL; ) {
|
||||
for (char *str; (str = rl_gets()) != NULL;) {
|
||||
char *str_end = str + strlen(str);
|
||||
|
||||
/* extract the first token as the command */
|
||||
char *cmd = strtok(str, " ");
|
||||
if (cmd == NULL) { continue; }
|
||||
if (cmd == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* treat the remaining string as the arguments,
|
||||
* which may need further parsing
|
||||
|
@ -123,20 +337,24 @@ void sdb_mainloop() {
|
|||
#endif
|
||||
|
||||
int i;
|
||||
for (i = 0; i < NR_CMD; i ++) {
|
||||
for (i = 0; i < NR_CMD; i++) {
|
||||
if (strcmp(cmd, cmd_table[i].name) == 0) {
|
||||
if (cmd_table[i].handler(args) < 0) { return; }
|
||||
if (cmd_table[i].handler(args) < 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == NR_CMD) { printf("Unknown command '%s'\n", cmd); }
|
||||
if (i == NR_CMD) {
|
||||
printf("Unknown command '%s'\n", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_sdb() {
|
||||
/* Compile the regular expressions. */
|
||||
init_regex();
|
||||
// /* Compile the regular expressions. */
|
||||
// init_regex();
|
||||
|
||||
/* Initialize the watchpoint pool. */
|
||||
init_wp_pool();
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <common.h>
|
||||
|
||||
word_t expr(char *e, bool *success);
|
||||
word_t parse_expr(const char *arg, bool *success);
|
||||
int wp_add(char * expr);
|
||||
int wp_remove_by_number(int number);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan
|
||||
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "sdb.h"
|
||||
#include <common.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NR_WP 32
|
||||
|
||||
typedef struct watchpoint {
|
||||
int NO;
|
||||
struct watchpoint *next;
|
||||
|
||||
/* TODO: Add more members if necessary */
|
||||
|
||||
word_t val;
|
||||
char *expr;
|
||||
} WP;
|
||||
|
||||
static WP wp_pool[NR_WP] = {};
|
||||
static WP *head = NULL, *free_ = NULL;
|
||||
static WP *head = NULL, *tail = NULL, *free_ = NULL;
|
||||
static int wp_count = 0;
|
||||
|
||||
void init_wp_pool() {
|
||||
int i;
|
||||
for (i = 0; i < NR_WP; i ++) {
|
||||
for (i = 0; i < NR_WP; i++) {
|
||||
wp_pool[i].NO = i;
|
||||
wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
|
||||
}
|
||||
|
@ -39,5 +41,110 @@ void init_wp_pool() {
|
|||
free_ = wp_pool;
|
||||
}
|
||||
|
||||
/* TODO: Implement the functionality of watchpoint */
|
||||
static WP *wp_new() {
|
||||
if (free_ == NULL) {
|
||||
Error("wp_pool: Watchpoint pool not initialized or is full.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WP *ret = free_;
|
||||
free_ = free_->next;
|
||||
|
||||
ret->NO = 0;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wp_delete(WP *wp) {
|
||||
Assert(wp, "Failed to delete watchpoint from pool.");
|
||||
wp->next = free_;
|
||||
free_ = wp;
|
||||
}
|
||||
|
||||
int wp_add(char * expr) {
|
||||
WP *wp = wp_new();
|
||||
if (wp == NULL) {
|
||||
Error("watchpoint: Failed to add watchpoint, pool is full.");
|
||||
goto failed_create;
|
||||
}
|
||||
|
||||
wp->NO = wp_count++;
|
||||
if (tail == NULL) {
|
||||
head = wp;
|
||||
tail = wp;
|
||||
} else {
|
||||
tail->next = wp;
|
||||
tail = wp;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
wp->val = parse_expr(expr, &success);
|
||||
if (!success) {
|
||||
Error("Failed to parse given expression `%s`", expr);
|
||||
goto failed_create;
|
||||
}
|
||||
|
||||
int len = strlen(expr);
|
||||
wp->expr = malloc((len + 1) * sizeof(char));
|
||||
if (wp->expr == NULL) {
|
||||
Error("Failed to allocate memory for expression");
|
||||
goto failed_create;
|
||||
}
|
||||
strncpy(wp->expr, expr, len + 1);
|
||||
wp->expr[len] = '\0';
|
||||
return 0;
|
||||
|
||||
failed_create:
|
||||
wp_delete(wp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int wp_remove_by_number(int number) {
|
||||
WP *target_prev;
|
||||
// Find previous node of target number
|
||||
for (target_prev = head; target_prev != NULL && target_prev->next->NO != number; target_prev = target_prev->next) ;
|
||||
if (target_prev == NULL) {
|
||||
Error("Watchpoint not found, you can check current watchpoints with `info w`");
|
||||
return 1;
|
||||
}
|
||||
WP *target = target_prev->next;
|
||||
target_prev->next = target->next;
|
||||
if (target == head) {
|
||||
head = target->next;
|
||||
} else if (target == tail) {
|
||||
tail = target_prev;
|
||||
}
|
||||
wp_delete(target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool wp_check_change(WP* wp) {
|
||||
bool success = false;
|
||||
word_t result;
|
||||
|
||||
result = parse_expr(wp->expr, &success);
|
||||
if (!success) {
|
||||
panic("Failed to evaluate expression `%s`", wp->expr);
|
||||
}
|
||||
if (result != wp->val) {
|
||||
wp->val = result;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if watchpoint value changed after execution
|
||||
*/
|
||||
bool wp_eval_all() {
|
||||
WP *wp;
|
||||
bool value_change = false;
|
||||
for (wp = head; wp != NULL; wp = wp->next) {
|
||||
int prev_val = wp->val;
|
||||
if (wp_check_change(wp)) {
|
||||
printf("Watchpoint %d: %s\n %u -> %u\n", wp->NO, wp->expr, prev_val, wp->val);
|
||||
value_change = true;
|
||||
}
|
||||
}
|
||||
return value_change;
|
||||
}
|
||||
|
|
124
nemu/src/utils/ftrace.c
Normal file
124
nemu/src/utils/ftrace.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include <assert.h>
|
||||
#include <common.h>
|
||||
#include <elf.h>
|
||||
#include <ftrace.h>
|
||||
#include <utils.h>
|
||||
|
||||
// Put this into another file
|
||||
#ifdef CONFIG_FTRACE
|
||||
static vaddr_t ftrace_stack[CONFIG_FTRACE_STACK_SIZE] = {0};
|
||||
static vaddr_t ftrace_stack_len = 0;
|
||||
func_t *func_table = NULL;
|
||||
int func_table_len = 0, func_table_size = 8;
|
||||
|
||||
static int cmp_func_t(const void *a, const void *b) {
|
||||
return ((func_t *)a)->start > ((func_t *)b)->start;
|
||||
}
|
||||
|
||||
static func_t *get_func(vaddr_t addr) {
|
||||
int l = 0, r = func_table_len - 1;
|
||||
while(l <= r) {
|
||||
int mid = (l + r) / 2;
|
||||
if(func_table[mid].start <= addr) l = mid + 1;
|
||||
else r = mid - 1;
|
||||
}
|
||||
return l == 0 ? NULL : &func_table[l - 1];
|
||||
}
|
||||
|
||||
void init_elf(const char *path) {
|
||||
FILE *elf_file = fopen(path, "rb");
|
||||
Elf32_Ehdr header;
|
||||
Elf32_Shdr section_header[200], *psh;
|
||||
|
||||
func_table = (func_t *)calloc(func_table_size, sizeof(func_t));
|
||||
assert(func_table);
|
||||
|
||||
FAILED_GOTO(failed_header, fread(&header, sizeof(Elf32_Ehdr), 1, elf_file) <= 0);
|
||||
FAILED_GOTO(failed_header, fseek(elf_file, header.e_shoff, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_header, fread(section_header, header.e_shentsize, header.e_shnum, elf_file) <= 0);
|
||||
|
||||
char *shstrtab = calloc(1, section_header[header.e_shstrndx].sh_size);
|
||||
FAILED_GOTO(failed_shstrtab, fseek(elf_file, section_header[header.e_shstrndx].sh_offset, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_shstrtab, fread(shstrtab, section_header[header.e_shstrndx].sh_size, 1, elf_file) <= 0);
|
||||
|
||||
Elf32_Shdr *symtab = NULL, *strtab = NULL;
|
||||
for(int i = 0; i < header.e_shnum; i++) {
|
||||
psh = section_header + i;
|
||||
if (psh->sh_type == SHT_SYMTAB) {
|
||||
symtab = psh;
|
||||
} else if (psh->sh_type == SHT_STRTAB && strncmp(shstrtab + psh->sh_name, ".strtab", 8) == 0) {
|
||||
strtab = psh;
|
||||
}
|
||||
}
|
||||
|
||||
int sym_length = symtab->sh_size / sizeof(Elf32_Sym);
|
||||
Elf32_Sym *sym = calloc(sym_length, sizeof(Elf32_Sym));
|
||||
assert(sym);
|
||||
FAILED_GOTO(failed_funcname, fseek(elf_file, symtab->sh_offset, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_funcname, fread(sym, sizeof(Elf32_Sym), sym_length, elf_file) <= 0);
|
||||
|
||||
for(int j = 0; j < sym_length; j++) {
|
||||
if(ELF32_ST_TYPE(sym[j].st_info) != STT_FUNC) continue;
|
||||
// Only read function type symbol
|
||||
func_t *f = &func_table[func_table_len];
|
||||
char *func = (char *)malloc(30);
|
||||
FAILED_GOTO(failed_funcname, fseek(elf_file, strtab->sh_offset + sym[j].st_name, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_funcname, fgets(func, 30, elf_file) <= 0);
|
||||
f->start = sym[j].st_value;
|
||||
f->len = sym[j].st_size;
|
||||
f->name = func;
|
||||
++func_table_len;
|
||||
if(func_table_len >= func_table_size) {
|
||||
Assert(func_table_size * 2 > func_table_size, "Function table exceed memory limit");
|
||||
func_table_size *= 2;
|
||||
func_table = realloc(func_table, func_table_size * sizeof(func_t));
|
||||
Assert(func_table, "Function table exceed memory limit");
|
||||
}
|
||||
}
|
||||
qsort(func_table, func_table_len, sizeof(func_t), cmp_func_t);
|
||||
goto success;
|
||||
|
||||
success:
|
||||
free(sym);
|
||||
free(shstrtab);
|
||||
return;
|
||||
|
||||
failed_funcname:
|
||||
free(sym);
|
||||
failed_shstrtab:
|
||||
free(shstrtab);
|
||||
failed_header:
|
||||
for(int i = 0; i < func_table_len; i++) {
|
||||
func_t *f = &func_table[i];
|
||||
if(f->name) { free(f->name); }
|
||||
}
|
||||
free(func_table);
|
||||
Error("Failed reading elf file");
|
||||
return;
|
||||
}
|
||||
|
||||
void ftrace_call(vaddr_t pc, vaddr_t addr) {
|
||||
func_t *f = get_func(addr);
|
||||
Assert(ftrace_stack_len < CONFIG_FTRACE_STACK_SIZE,
|
||||
"Ftrace stack exceed size limit, consider turn off ftrace or increase "
|
||||
"FTRACE_STACK_SIZE.");
|
||||
ftrace_stack[ftrace_stack_len] = pc + 4;
|
||||
Trace("%*s0x%x call 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr,
|
||||
f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start);
|
||||
ftrace_stack_len++;
|
||||
}
|
||||
|
||||
void ftrace_return(vaddr_t pc, vaddr_t addr) {
|
||||
--ftrace_stack_len;
|
||||
for (; addr != ftrace_stack[ftrace_stack_len] && ftrace_stack_len >= 0;
|
||||
ftrace_stack_len--) {
|
||||
vaddr_t tco_addr = ftrace_stack[ftrace_stack_len];
|
||||
func_t *f = get_func(tco_addr);
|
||||
Trace("%*s0x%x ret 0x%x <%s+0x%x> (TCO)", ftrace_stack_len, "", pc, tco_addr,
|
||||
f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start);
|
||||
}
|
||||
func_t *f = get_func(addr);
|
||||
Trace("%*s0x%x ret 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr,
|
||||
f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start);
|
||||
}
|
||||
#endif
|
|
@ -14,6 +14,7 @@
|
|||
***************************************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
#include <utils.h>
|
||||
|
||||
extern uint64_t g_nr_guest_inst;
|
||||
|
||||
|
@ -35,3 +36,18 @@ bool log_enable() {
|
|||
(g_nr_guest_inst <= CONFIG_TRACE_END), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
IFDEF(CONFIG_ITRACE, char logbuf[CONFIG_ITRACE_BUFFER][128]);
|
||||
IFDEF(CONFIG_ITRACE, int logbuf_rear);
|
||||
|
||||
#ifdef CONFIG_ITRACE
|
||||
void log_itrace_print() {
|
||||
puts("ITRACE buffer:");
|
||||
for (int i = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER; i != logbuf_rear; i = (i + 1) % CONFIG_ITRACE_BUFFER) {
|
||||
if (logbuf[i][0] == '\0') continue;
|
||||
puts(logbuf[i]);
|
||||
}
|
||||
puts("Current command:");
|
||||
puts(logbuf[logbuf_rear]);
|
||||
}
|
||||
#endif
|
||||
|
|
10
nemu/tests/Makefile
Normal file
10
nemu/tests/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
TEST_SRCS += tests/expr_test.c
|
||||
YACC = bison
|
||||
|
||||
$(OBJ_DIR)/%: %.c $(TEST_OBJS) app
|
||||
@mkdir -p $(dir $@)
|
||||
@echo + CC $<
|
||||
@$(CC) $(CFLAGS) -o $@.o -c $<
|
||||
@echo + LD $@
|
||||
@$(LD) $(LIBS) $(LDFLAGS) -o $@ $(TEST_OBJS) $@.o
|
||||
@$@
|
244
nemu/tests/expr_test.c
Normal file
244
nemu/tests/expr_test.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
#include "macro.h"
|
||||
#include "sys/types.h"
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <check.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <addrexp.h>
|
||||
#include <addrexp_lex.h>
|
||||
#include <isa.h>
|
||||
#include <reg.h>
|
||||
|
||||
char buf[65536] = {}, ref_buf[65536] = {};
|
||||
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
|
||||
const int buf_start_pos = 0;
|
||||
char *buf_ptr = buf + buf_start_pos, *ref_buf_ptr = ref_buf;
|
||||
static char *code_format = "#include <stdio.h>\n"
|
||||
"#include <stdint.h>\n"
|
||||
"int main() { "
|
||||
" uint32_t result = %s; "
|
||||
" printf(\"%%u\", result); "
|
||||
" return 0; "
|
||||
"}";
|
||||
|
||||
void gen(char c) {
|
||||
*(buf_ptr++) = c;
|
||||
*(ref_buf_ptr++) = c;
|
||||
}
|
||||
|
||||
void gen_num(void) {
|
||||
uint32_t num = rand();
|
||||
int len = 0, ref_len = 0;
|
||||
switch (rand() % 3) {
|
||||
case 0:
|
||||
len = snprintf(buf_ptr, 100, "%u", num);
|
||||
ref_len = snprintf(ref_buf_ptr, 100, "%uU", num);
|
||||
break;
|
||||
case 1:
|
||||
len = snprintf(buf_ptr, 100, "0x%x", num);
|
||||
ref_len = snprintf(ref_buf_ptr, 100, "%uU", num);
|
||||
break;
|
||||
case 2:
|
||||
len = snprintf(buf_ptr, 100, "%d", num);
|
||||
ref_len = snprintf(ref_buf_ptr, 100, "%d", num);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
buf_ptr += len;
|
||||
ref_buf_ptr += ref_len;
|
||||
}
|
||||
|
||||
void gen_rand_op(void) {
|
||||
switch (rand() % 4) {
|
||||
case 0:
|
||||
gen('+');
|
||||
break;
|
||||
case 1:
|
||||
gen('-');
|
||||
break;
|
||||
case 2:
|
||||
gen('*');
|
||||
break;
|
||||
case 3:
|
||||
gen('/');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gen_rand_expr(void) {
|
||||
int choice = rand() % 3;
|
||||
if (buf_ptr - buf > 2000) {
|
||||
choice = 0;
|
||||
}
|
||||
switch (choice) {
|
||||
case 0:
|
||||
gen_num();
|
||||
break;
|
||||
case 1:
|
||||
gen('(');
|
||||
gen_rand_expr();
|
||||
gen(')');
|
||||
break;
|
||||
default:
|
||||
gen_rand_expr();
|
||||
gen(' ');
|
||||
gen_rand_op();
|
||||
gen(' ');
|
||||
gen_rand_expr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(test_expr_random_100) {
|
||||
srand(time(0) + _i * 100);
|
||||
gen_rand_expr();
|
||||
|
||||
sprintf(code_buf, code_format, ref_buf);
|
||||
|
||||
FILE *fp = fopen("/tmp/.code.c", "w");
|
||||
ck_assert(fp != NULL);
|
||||
fputs(code_buf, fp);
|
||||
fclose(fp);
|
||||
|
||||
int ret =
|
||||
system("gcc /tmp/.code.c -Werror=div-by-zero -o /tmp/.expr 2>/dev/null");
|
||||
if (ret == 256) {
|
||||
// Probably devide by zero. Skip
|
||||
goto clean_up;
|
||||
}
|
||||
ck_assert_msg(!ret, "system ret: %d, error: %s", ret, strerror(ret));
|
||||
|
||||
fp = popen("/tmp/.expr", "r");
|
||||
ck_assert(fp != NULL);
|
||||
|
||||
uint32_t reference;
|
||||
ret = fscanf(fp, "%u", &reference);
|
||||
ck_assert(ret == 1);
|
||||
pclose(fp);
|
||||
// fprintf(stderr, "\n\tbuf = %s\n\taddr = %u, reference = %u", buf, addr,
|
||||
// reference);
|
||||
|
||||
yy_scan_string(buf + buf_start_pos);
|
||||
uint32_t addr;
|
||||
ck_assert(!yyparse(&addr));
|
||||
yylex_destroy();
|
||||
|
||||
ck_assert_msg(addr == reference,
|
||||
"\n\tbuf = %s\n\t(addr = %u) != (reference = %u)\n", buf, addr,
|
||||
reference);
|
||||
|
||||
clean_up:
|
||||
while (buf_ptr != buf + buf_start_pos) {
|
||||
*(--buf_ptr) = '\0';
|
||||
}
|
||||
while (ref_buf_ptr != ref_buf) {
|
||||
*(--ref_buf_ptr) = '\0';
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
struct {
|
||||
const char *expr;
|
||||
uint32_t reference;
|
||||
} exprs[] = {
|
||||
{"-1", 0xFFFFFFFFU},
|
||||
{"-0x1", 0xFFFFFFFFU},
|
||||
{"0--1", 0x1},
|
||||
{"0--0x1", 0x1},
|
||||
}, reg_exprs[] = {
|
||||
{"$ra", 0x1},
|
||||
{"0x2 + 4*-$a7", 0xFFFFFFBEU},
|
||||
{"0x1831/$gp + 13", 2077U},
|
||||
{"$$0 == 123", 0},
|
||||
{"$$0 == 0", 1},
|
||||
};
|
||||
START_TEST(test_expr_negative_operand) {
|
||||
yy_scan_string(exprs[_i].expr);
|
||||
uint32_t addr;
|
||||
ck_assert(!yyparse(&addr));
|
||||
yylex_destroy();
|
||||
|
||||
ck_assert_msg(addr == exprs[_i].reference,
|
||||
"\n\texpr = %s\n\t(addr = %u) != (reference = %u)\n", exprs[_i].expr,
|
||||
addr, exprs[_i].reference);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
extern const char *regs[];
|
||||
START_TEST(test_expr_plain_register) {
|
||||
int i, j, result;
|
||||
char buf[30] = {};
|
||||
uint32_t value;
|
||||
// NOTE: need to fix this if want to support more arch
|
||||
buf[0] = '$';
|
||||
for (i = 0; i < 32; i++) {
|
||||
ck_assert(strncpy(buf + 1, regs[i], 10) != NULL);
|
||||
gpr(i) = i;
|
||||
yy_scan_string(buf);
|
||||
result = yyparse(&value);
|
||||
yylex_destroy();
|
||||
ck_assert_msg(result == 0, "expr = %s\n", buf);
|
||||
|
||||
ck_assert(value == i);
|
||||
for (j = 1; j < 10; j++) {
|
||||
buf[j] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_expr_register) {
|
||||
int i;
|
||||
uint32_t value;
|
||||
for (i = 0; i < 32; i++) {
|
||||
gpr(i) = i;
|
||||
}
|
||||
|
||||
yy_scan_string(reg_exprs[_i].expr);
|
||||
ck_assert(!yyparse(&value));
|
||||
yylex_destroy();
|
||||
|
||||
ck_assert_msg(value == reg_exprs[_i].reference,
|
||||
"\n\texpr = %s\n\t(addr = %u) != (reference = %u)\n", reg_exprs[_i].expr,
|
||||
value, reg_exprs[_i].reference);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *expr_suite(void) {
|
||||
Suite *s;
|
||||
TCase *tc_core;
|
||||
|
||||
s = suite_create("Expr test");
|
||||
tc_core = tcase_create("Core");
|
||||
|
||||
tcase_add_loop_test(tc_core, test_expr_random_100, 0, 20);
|
||||
tcase_add_loop_test(tc_core, test_expr_negative_operand, 0,
|
||||
sizeof(exprs) / sizeof(exprs[0]));
|
||||
tcase_add_loop_test(tc_core, test_expr_register, 0,
|
||||
sizeof(reg_exprs) / sizeof(reg_exprs[0]));
|
||||
tcase_add_test(tc_core, test_expr_plain_register);
|
||||
suite_add_tcase(s, tc_core);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int number_failed;
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
|
||||
s = expr_suite();
|
||||
sr = srunner_create(s);
|
||||
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
1
npc/.envrc
Normal file
1
npc/.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
27
npc/.gitignore
vendored
27
npc/.gitignore
vendored
|
@ -1,12 +1,17 @@
|
|||
*.*
|
||||
*
|
||||
!*/
|
||||
!Makefile
|
||||
!*.mk
|
||||
!*.[cSh]
|
||||
!*.v
|
||||
!*.cc
|
||||
!*.cpp
|
||||
!.gitignore
|
||||
!README.md
|
||||
build/
|
||||
**/project/
|
||||
**/target/
|
||||
|
||||
*.class
|
||||
*.log
|
||||
.cache/
|
||||
**/.bsp/
|
||||
.bloop/
|
||||
.metals/
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
.vscode/
|
||||
.direnv/
|
||||
compile_commands.json
|
||||
|
|
101
npc/CMakeLists.txt
Normal file
101
npc/CMakeLists.txt
Normal file
|
@ -0,0 +1,101 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(flow)
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
cmake_policy(SET CMP0144 NEW)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "configure(npc)"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(SDL2_image REQUIRED)
|
||||
|
||||
find_package(verilator REQUIRED)
|
||||
|
||||
find_library(NVBOARD_LIBRARY NAMES nvboard)
|
||||
find_path(NVBOARD_INCLUDE_DIR NAMES nvboard.h)
|
||||
|
||||
set(TOPMODULES "Flow")
|
||||
|
||||
foreach(TOPMODULE IN LISTS TOPMODULES)
|
||||
|
||||
# FIXME: all scala source file are tracked here, cause all files to rebuild
|
||||
# after a source update.
|
||||
set(SCALA_CORE "${CMAKE_CURRENT_SOURCE_DIR}/core")
|
||||
set(CHISEL_MODULE_CLASS "${CMAKE_PROJECT_NAME}.${TOPMODULE}")
|
||||
file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala")
|
||||
file(GLOB_RECURSE SCALA_CORE_TEST_SOURCES "${SCALA_CORE}/src/test/scala/*.scala")
|
||||
|
||||
# Configure time verilog source generation for verilator
|
||||
execute_process(
|
||||
COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog"
|
||||
WORKING_DIRECTORY ${SCALA_CORE}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v
|
||||
COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog"
|
||||
WORKING_DIRECTORY ${SCALA_CORE}
|
||||
DEPENDS ${SCALA_CORE_SOURCES}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
ChiselBuild_${TOPMODULE}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v
|
||||
)
|
||||
|
||||
# -- Build NVBoard executable
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp
|
||||
COMMAND auto_pin_bind ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc
|
||||
)
|
||||
|
||||
unset(SOURCES)
|
||||
file(GLOB_RECURSE SOURCES csrc_nvboard/${TOPMODULE}/*.cpp)
|
||||
add_executable(V${TOPMODULE}_nvboard ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp)
|
||||
|
||||
verilate(V${TOPMODULE}_nvboard TRACE THREADS
|
||||
TOP_MODULE ${TOPMODULE}
|
||||
PREFIX V${TOPMODULE}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v)
|
||||
|
||||
add_dependencies(V${TOPMODULE}_nvboard ChiselBuild_${TOPMODULE})
|
||||
target_include_directories(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS})
|
||||
target_link_libraries(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_LIBRARY} SDL2::SDL2 SDL2_image::SDL2_image)
|
||||
|
||||
install(TARGETS V${TOPMODULE}_nvboard)
|
||||
|
||||
# -- Build Verilator executable and add to test
|
||||
|
||||
unset(SOURCES)
|
||||
file(GLOB_RECURSE SOURCES csrc/${TOPMODULE}/*.cpp)
|
||||
add_executable(V${TOPMODULE} ${SOURCES})
|
||||
|
||||
verilate(V${TOPMODULE} TRACE COVERAGE THREADS
|
||||
TOP_MODULE ${TOPMODULE}
|
||||
PREFIX V${TOPMODULE}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v)
|
||||
|
||||
add_dependencies(V${TOPMODULE} ChiselBuild_${TOPMODULE})
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE})
|
||||
|
||||
# -- Add build tracking
|
||||
add_custom_command(
|
||||
TARGET V${TOPMODULE}_nvboard PRE_BUILD
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}_nvboard"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
TARGET V${TOPMODULE} PRE_BUILD
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
endforeach()
|
|
@ -1,8 +0,0 @@
|
|||
all:
|
||||
@echo "Write this Makefile by your self."
|
||||
|
||||
sim:
|
||||
$(call git_commit, "sim RTL") # DO NOT REMOVE THIS LINE!!!
|
||||
@echo "Write this Makefile by your self."
|
||||
|
||||
include ../Makefile
|
3
npc/constr/Flow.nxdc
Normal file
3
npc/constr/Flow.nxdc
Normal file
|
@ -0,0 +1,3 @@
|
|||
top=Flow
|
||||
|
||||
io_clock(LD0)
|
12
npc/constr/Keyboard.nxdc
Normal file
12
npc/constr/Keyboard.nxdc
Normal file
|
@ -0,0 +1,12 @@
|
|||
top=Keyboard
|
||||
|
||||
io_ps2_clk PS2_CLK
|
||||
io_ps2_data PS2_DAT
|
||||
io_segs_0 (SEG0A, SEG0B, SEG0C, SEG0D, SEG0E, SEG0F, SEG0G, DEC0P)
|
||||
io_segs_1 (SEG1A, SEG1B, SEG1C, SEG1D, SEG1E, SEG1F, SEG1G, DEC1P)
|
||||
io_segs_2 (SEG2A, SEG2B, SEG2C, SEG2D, SEG2E, SEG2F, SEG2G, DEC2P)
|
||||
io_segs_3 (SEG3A, SEG3B, SEG3C, SEG3D, SEG3E, SEG3F, SEG3G, DEC3P)
|
||||
io_segs_4 (SEG4A, SEG4B, SEG4C, SEG4D, SEG4E, SEG4F, SEG4G, DEC4P)
|
||||
io_segs_5 (SEG5A, SEG5B, SEG5C, SEG5D, SEG5E, SEG5F, SEG5G, DEC5P)
|
||||
io_segs_6 (SEG6A, SEG6B, SEG6C, SEG6D, SEG6E, SEG6F, SEG6G, DEC6P)
|
||||
io_segs_7 (SEG7A, SEG7B, SEG7C, SEG7D, SEG7E, SEG7F, SEG7G, DEC7P)
|
5
npc/constr/Switch.nxdc
Normal file
5
npc/constr/Switch.nxdc
Normal file
|
@ -0,0 +1,5 @@
|
|||
top=Switch
|
||||
|
||||
io_sw_0 (SW0)
|
||||
io_sw_1 (SW1)
|
||||
io_out (LD0)
|
13
npc/core/.gitignore
vendored
Normal file
13
npc/core/.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/scala
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=scala
|
||||
|
||||
### Scala ###
|
||||
*.class
|
||||
*.log
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/scala
|
||||
|
||||
test_run_dir/
|
2
npc/core/.scalafmt.conf
Normal file
2
npc/core/.scalafmt.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
version = "3.7.15"
|
||||
runner.dialect = scala213
|
23
npc/core/build.sbt
Normal file
23
npc/core/build.sbt
Normal file
|
@ -0,0 +1,23 @@
|
|||
ThisBuild / scalaVersion := "2.13.12"
|
||||
ThisBuild / version := "0.1.0"
|
||||
|
||||
|
||||
val chiselVersion = "6.2.0"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
name := "flow",
|
||||
libraryDependencies ++= Seq(
|
||||
"org.chipsalliance" %% "chisel" % chiselVersion,
|
||||
"edu.berkeley.cs" %% "chiseltest" % "6.0.0" % "test",
|
||||
"com.chuusai" %% "shapeless" % "2.3.3"
|
||||
),
|
||||
scalacOptions ++= Seq(
|
||||
"-language:reflectiveCalls",
|
||||
"-deprecation",
|
||||
"-feature",
|
||||
"-Xcheckinit",
|
||||
"-Ymacro-annotations",
|
||||
),
|
||||
addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full),
|
||||
)
|
63
npc/core/src/main/scala/ALU.scala
Normal file
63
npc/core/src/main/scala/ALU.scala
Normal file
|
@ -0,0 +1,63 @@
|
|||
package flow.components
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import shapeless.{HNil, ::}
|
||||
|
||||
class ALUControlInterface extends Bundle {
|
||||
object OpSelect extends ChiselEnum {
|
||||
val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpEq, aOpNop = Value
|
||||
}
|
||||
object SrcSelect extends ChiselEnum {
|
||||
val aSrcRs1, aSrcImm = Value
|
||||
}
|
||||
val op = Input(OpSelect())
|
||||
val src = Input(SrcSelect())
|
||||
|
||||
type CtrlTypes = OpSelect.Type :: SrcSelect.Type :: HNil
|
||||
def ctrlBindPorts: CtrlTypes = {
|
||||
op :: src :: HNil
|
||||
}
|
||||
}
|
||||
|
||||
class ALU[T <: UInt](tpe: T) extends Module {
|
||||
val control = IO(new ALUControlInterface)
|
||||
val in = IO(new Bundle {
|
||||
val a = Input(Vec(control.SrcSelect.all.length, tpe))
|
||||
val b = Input(tpe)
|
||||
})
|
||||
val out = IO(new Bundle {
|
||||
val result = Output(tpe)
|
||||
})
|
||||
|
||||
val a = in.a(control.src.asUInt)
|
||||
|
||||
// val adder_b = (Fill(tpe.getWidth, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub
|
||||
val add = a + in.b
|
||||
val sub = a - in.b
|
||||
val and = a & in.b
|
||||
val not = ~a
|
||||
val or = a | in.b
|
||||
val xor = a ^ in.b
|
||||
val slt = a < in.b
|
||||
val eq = a === in.b
|
||||
|
||||
import control.OpSelect._
|
||||
|
||||
out.result := MuxLookup(control.op, 0.U)(Seq(
|
||||
aOpAdd -> add,
|
||||
aOpSub -> sub,
|
||||
aOpNot -> not,
|
||||
aOpAnd -> and,
|
||||
aOpOr -> or,
|
||||
aOpXor -> xor,
|
||||
aOpSlt -> slt,
|
||||
aOpEq -> eq
|
||||
))
|
||||
}
|
||||
|
||||
object ALU {
|
||||
def apply[T <: UInt](tpe: T): ALU[T] = {
|
||||
Module(new ALU(tpe))
|
||||
}
|
||||
}
|
99
npc/core/src/main/scala/Keyboard.scala
Normal file
99
npc/core/src/main/scala/Keyboard.scala
Normal file
|
@ -0,0 +1,99 @@
|
|||
package npc.util
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util.{Counter, Decoupled, Queue, Reverse, MuxLookup}
|
||||
|
||||
class PS2Port extends Bundle {
|
||||
val clk = Input(Bool())
|
||||
val data = Input(UInt(1.W))
|
||||
}
|
||||
|
||||
object PS2Port {
|
||||
def apply(): PS2Port = {
|
||||
new PS2Port
|
||||
}
|
||||
}
|
||||
|
||||
class KeyboardController extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val ps2 = PS2Port()
|
||||
val out = Decoupled(UInt(8.W))
|
||||
})
|
||||
// valid only on the clock negedge of ps2_clk
|
||||
val ps2_clk_valid = RegNext(io.ps2.clk, false.B) & ~io.ps2.clk
|
||||
val cycle_counter = Counter(11)
|
||||
val concated_data = RegInit(0.U(8.W))
|
||||
|
||||
val queue_in = Wire(Flipped(Decoupled(UInt(8.W))))
|
||||
val queue = Queue(queue_in, entries = 8)
|
||||
val received = RegInit(Bool(), false.B)
|
||||
val pushed = RegNext(queue_in.valid && queue_in.ready, false.B)
|
||||
queue_in.valid := false.B
|
||||
queue_in.bits := Reverse(concated_data)
|
||||
io.out <> queue
|
||||
|
||||
when(cycle_counter.value === 0.U) {
|
||||
concated_data := 0.U
|
||||
received := false.B
|
||||
}
|
||||
|
||||
when(ps2_clk_valid) {
|
||||
when(cycle_counter.value < 9.U && cycle_counter.value >= 1.U) {
|
||||
concated_data := (concated_data << 1) | io.ps2.data
|
||||
}.elsewhen(cycle_counter.value === 9.U) {
|
||||
received := true.B
|
||||
}
|
||||
cycle_counter.inc()
|
||||
}
|
||||
|
||||
when(!pushed && received) {
|
||||
queue_in.valid := true.B
|
||||
}.elsewhen(pushed && received) {
|
||||
queue_in.valid := false.B
|
||||
received := false.B
|
||||
}
|
||||
}
|
||||
|
||||
class KeyboardSegController extends Module {
|
||||
val io = IO(new Bundle{
|
||||
val keycode = Flipped(Decoupled(UInt(8.W)))
|
||||
val segs = Vec(8, UInt(8.W))
|
||||
})
|
||||
io.keycode.ready := false.B
|
||||
when(io.keycode.valid) {
|
||||
io.keycode.ready := true.B
|
||||
}
|
||||
|
||||
// 0x1C.U -> 0x41.U, ...
|
||||
val keycode_to_ascii = Seq(
|
||||
0x1C.U, 0x32.U, 0x21.U, 0x23.U, 0x24.U, 0x2B.U,
|
||||
0x34.U, 0x33.U, 0x43.U, 0x3B.U, 0x42.U, 0x4B.U,
|
||||
0x3A.U, 0x31.U, 0x44.U, 0x4D.U, 0x15.U, 0x2D.U,
|
||||
0x1B.U, 0x2C.U, 0x3C.U, 0x2A.U, 0x1D.U, 0x22.U,
|
||||
0x35.U, 0x1A.U, 0x45.U, 0x16.U, 0x1E.U, 0x26.U,
|
||||
0x25.U, 0x2E.U, 0x36.U, 0x3D.U, 0x3E.U, 0x46.U,
|
||||
).zip(((0x41 to 0x5A) ++ (0x30 to 0x39)).map(_.U))
|
||||
|
||||
val keycode = RegInit(0.U(8.W))
|
||||
val counter = Counter(0xFF)
|
||||
val release_state = RegInit(Bool(), false.B)
|
||||
when(io.keycode.ready && io.keycode.valid) {
|
||||
when(io.keycode.bits === 0xF0.U) {
|
||||
release_state := true.B
|
||||
}.elsewhen(!release_state) {
|
||||
counter.inc()
|
||||
keycode := io.keycode.bits
|
||||
}.otherwise{
|
||||
// Release code on io.keycode.bits
|
||||
release_state := false.B
|
||||
}
|
||||
}
|
||||
|
||||
val keycode_digits = VecInit(keycode(3,0)) ++ VecInit(keycode(7,4))
|
||||
val ascii = MuxLookup(keycode, 0.U)(keycode_to_ascii)
|
||||
|
||||
val seg_contoller = Module(new SegControllerGenerator(8, UInt(8.W)))
|
||||
|
||||
seg_contoller.io.in_segs := VecInit(Seq(keycode, ascii, counter.value, 0.U))
|
||||
io.segs := seg_contoller.io.segs
|
||||
}
|
129
npc/core/src/main/scala/Main.scala
Normal file
129
npc/core/src/main/scala/Main.scala
Normal file
|
@ -0,0 +1,129 @@
|
|||
package flow
|
||||
|
||||
import scala.reflect.runtime.universe._
|
||||
import chisel3._
|
||||
import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse}
|
||||
import chisel3.util.{SRAM}
|
||||
import chisel3.util.experimental.decode.{decoder, TruthTable}
|
||||
import chisel3.stage.ChiselOption
|
||||
import chisel3.util.log2Ceil
|
||||
import chisel3.util.BitPat
|
||||
import chisel3.util.Enum
|
||||
import chisel3.experimental.prefix
|
||||
import shapeless.{HNil, ::}
|
||||
import shapeless.HList
|
||||
import shapeless.ops.coproduct.Prepend
|
||||
import chisel3.util.{ BinaryMemoryFile, HexMemoryFile }
|
||||
|
||||
object RV32Inst {
|
||||
private val bp = BitPat
|
||||
val addi = this.bp("b???????_?????_?????_000_?????_00100_11")
|
||||
val inv = this.bp("b???????_?????_?????_???_?????_?????_??")
|
||||
}
|
||||
|
||||
class PcControl(width: Int) extends Bundle {
|
||||
object SrcSelect extends ChiselEnum {
|
||||
val pPC, pExeResult = Value
|
||||
}
|
||||
val srcSelect = Output(SrcSelect())
|
||||
}
|
||||
|
||||
import flow.components.{RegControl, PcControlInterface, ALUControlInterface}
|
||||
class Control(width: Int) extends Module {
|
||||
val inst = IO(Input(UInt(width.W)))
|
||||
|
||||
val reg = IO(Flipped(new RegControl))
|
||||
val pc = IO(Flipped(new PcControlInterface))
|
||||
val alu = IO(Flipped(new ALUControlInterface))
|
||||
|
||||
// TODO: Add .ctrlTypes together instead of writing them by hand.
|
||||
type T =
|
||||
Bool :: reg.WriteSelect.Type :: pc.SrcSelect.Type :: alu.OpSelect.Type :: alu.SrcSelect.Type :: HNil
|
||||
val dst: T = reg.ctrlBindPorts ++ pc.ctrlBindPorts ++ alu.ctrlBindPorts
|
||||
|
||||
val dstList = dst.toList
|
||||
val reversePrefixSum = dstList.scanLeft(0)(_ + _.getWidth).reverse
|
||||
val slices = reversePrefixSum.zip(reversePrefixSum.tail)
|
||||
|
||||
import reg.WriteSelect._
|
||||
import pc.SrcSelect._
|
||||
import alu.OpSelect._
|
||||
import alu.SrcSelect._
|
||||
import RV32Inst._
|
||||
val ControlMapping: Array[(BitPat, T)] = Array(
|
||||
// Regs :: PC :: Exe
|
||||
// writeEnable :: writeSelect :: srcSelect ::
|
||||
(addi, true.B :: rAluOut :: pStaticNpc :: aOpAdd :: aSrcImm :: HNil),
|
||||
)
|
||||
val default = BitPat.dontCare(dstList.map(_.getWidth).reduce(_ + _))
|
||||
|
||||
def toBits(t: T): BitPat = {
|
||||
val list: List[Data] = t.toList
|
||||
list.map(x => BitPat(x.litValue.toInt.U(x.getWidth.W))).reduceLeft(_ ## _)
|
||||
}
|
||||
val out = decoder(
|
||||
inst,
|
||||
TruthTable(ControlMapping.map(it => (it._1 -> toBits(it._2))), default))
|
||||
val srcList = slices.map(s => out(s._1 - 1, s._2))
|
||||
|
||||
srcList
|
||||
.zip(dstList.reverse)
|
||||
.foreach({ case (src, dst) =>
|
||||
dst := src.asTypeOf(dst)
|
||||
})
|
||||
}
|
||||
|
||||
import flow.components.{RegisterFile, RegFileInterface, ProgramCounter, ALU}
|
||||
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||
class Flow extends Module {
|
||||
val dataType = UInt(32.W)
|
||||
|
||||
val ram = SRAM(
|
||||
size = 1024,
|
||||
tpe = dataType,
|
||||
numReadPorts = 2,
|
||||
numWritePorts = 1,
|
||||
numReadwritePorts = 0,
|
||||
memoryFile = HexMemoryFile("./resource/addi.txt")
|
||||
)
|
||||
val control = Module(new Control(32))
|
||||
val reg = RegisterFile(32, dataType, 2, 2)
|
||||
val pc = Module(new ProgramCounter(dataType))
|
||||
val alu = Module(new ALU(dataType))
|
||||
|
||||
ram.readPorts(0).enable := true.B
|
||||
ram.readPorts(0).address := pc.out - 0x80000000L.U
|
||||
val inst = ram.readPorts(0).data
|
||||
|
||||
import control.pc.SrcSelect._
|
||||
|
||||
pc.in.pcSrcs(pStaticNpc.litValue.toInt) := pc.out + 4.U
|
||||
pc.in.pcSrcs(pBranchResult.litValue.toInt) := alu.out.result
|
||||
|
||||
control.inst := inst
|
||||
reg.control <> control.reg
|
||||
pc.control <> control.pc
|
||||
alu.control <> control.alu
|
||||
|
||||
import control.reg.WriteSelect._
|
||||
reg.in.writeData(rAluOut.litValue.toInt) := alu.out.result
|
||||
// TODO: Read address in load command goes here
|
||||
ram.readPorts(1).enable := false.B
|
||||
ram.readPorts(1).address := 0.U
|
||||
reg.in.writeData(rMemOut.litValue.toInt) := ram.readPorts(1).data
|
||||
reg.in.writeAddr := inst(11, 7)
|
||||
reg.in.rs(0) := inst(19, 15)
|
||||
reg.in.rs(1) := inst(24, 20)
|
||||
|
||||
// TODO: Memory write goes here
|
||||
ram.writePorts(0).address := 1.U
|
||||
ram.writePorts(0).data := 1.U
|
||||
ram.writePorts(0).enable := false.B
|
||||
|
||||
import control.alu.SrcSelect._
|
||||
alu.in.a(aSrcRs1.litValue.toInt) := reg.out.src(0)
|
||||
alu.in.a(aSrcImm.litValue.toInt) := inst(31, 20)
|
||||
alu.in.b := reg.out.src(1)
|
||||
|
||||
dontTouch(control.out)
|
||||
}
|
39
npc/core/src/main/scala/ProgramCounter.scala
Normal file
39
npc/core/src/main/scala/ProgramCounter.scala
Normal file
|
@ -0,0 +1,39 @@
|
|||
package flow.components
|
||||
import chisel3._
|
||||
import chisel3.util.{Valid, log2Ceil}
|
||||
import chisel3.util.MuxLookup
|
||||
import shapeless.{HNil, ::}
|
||||
|
||||
class PcControlInterface extends Bundle {
|
||||
object SrcSelect extends ChiselEnum {
|
||||
val pStaticNpc, pBranchResult = Value
|
||||
}
|
||||
|
||||
val srcSelect = Input(SrcSelect())
|
||||
|
||||
type CtrlTypes = SrcSelect.Type :: HNil
|
||||
def ctrlBindPorts: CtrlTypes = {
|
||||
srcSelect :: HNil
|
||||
}
|
||||
}
|
||||
|
||||
class ProgramCounter[T <: Data](tpe: T) extends Module {
|
||||
|
||||
val control = IO(new PcControlInterface)
|
||||
val in = IO(new Bundle {
|
||||
val pcSrcs = Input(Vec(control.SrcSelect.all.length, tpe))
|
||||
})
|
||||
val out = IO(Output(tpe))
|
||||
|
||||
private val pc = RegInit(0x80000000L.U)
|
||||
|
||||
pc := in.pcSrcs(control.srcSelect.asUInt)
|
||||
out := pc
|
||||
}
|
||||
|
||||
object ProgramCounter {
|
||||
def apply[T <: Data](tpe: T): ProgramCounter[T] = {
|
||||
val pc = Module(new ProgramCounter(tpe))
|
||||
pc
|
||||
}
|
||||
}
|
86
npc/core/src/main/scala/RegisterFile.scala
Normal file
86
npc/core/src/main/scala/RegisterFile.scala
Normal file
|
@ -0,0 +1,86 @@
|
|||
package flow.components
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util.log2Ceil
|
||||
import chisel3.util.UIntToOH
|
||||
import chisel3.util.MuxLookup
|
||||
import shapeless.{ HNil, :: }
|
||||
|
||||
class RegControl extends Bundle {
|
||||
object WriteSelect extends ChiselEnum {
|
||||
val rAluOut, rMemOut = Value
|
||||
}
|
||||
|
||||
val writeEnable = Input(Bool())
|
||||
val writeSelect = Input(WriteSelect())
|
||||
|
||||
type CtrlTypes = Bool :: WriteSelect.Type :: HNil
|
||||
def ctrlBindPorts: CtrlTypes = {
|
||||
writeEnable :: writeSelect :: HNil
|
||||
}
|
||||
}
|
||||
|
||||
class RegFileData[T <: Data](size:Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle {
|
||||
val write = new Bundle {
|
||||
val addr = Input(UInt(size.W))
|
||||
val data = Vec(numWritePorts, Input(tpe))
|
||||
}
|
||||
val read = Vec(numReadPorts, new Bundle {
|
||||
val rs = Input(UInt(size.W))
|
||||
val src = Output(tpe)
|
||||
})
|
||||
}
|
||||
|
||||
class RegFileInterface[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle {
|
||||
val control = new RegControl
|
||||
// val data = new RegFileData(size, tpe, numReadPorts, numWritePorts)
|
||||
val in = new Bundle {
|
||||
val writeAddr = Input(UInt(size.W))
|
||||
val writeData = Input(Vec(numWritePorts, tpe))
|
||||
val rs = Input(Vec(numReadPorts, UInt(size.W)))
|
||||
}
|
||||
val out = new Bundle {
|
||||
val src = Output(Vec(numReadPorts, tpe))
|
||||
}
|
||||
}
|
||||
|
||||
class RegisterFileCore[T <: Data](size: Int, tpe: T, numReadPorts: Int) extends Module {
|
||||
require(numReadPorts >= 0)
|
||||
val writePort = IO(new Bundle {
|
||||
val enable = Input(Bool())
|
||||
val addr = Input(UInt(log2Ceil(size).W))
|
||||
val data = Input(tpe)
|
||||
})
|
||||
val readPorts = IO(Vec(numReadPorts, new Bundle {
|
||||
val addr = Input(UInt(log2Ceil(size).W))
|
||||
val data = Output(tpe)
|
||||
}))
|
||||
|
||||
val regFile = RegInit(VecInit(Seq.fill(size)(0.U(tpe.getWidth.W))))
|
||||
val writeAddrOH = UIntToOH(writePort.addr)
|
||||
for ((reg, i) <- regFile.zipWithIndex.tail) {
|
||||
reg := Mux(writeAddrOH(i) && writePort.enable, writePort.data, reg)
|
||||
}
|
||||
regFile(0) := 0.U
|
||||
|
||||
for (readPort <- readPorts) {
|
||||
readPort.data := regFile(readPort.addr)
|
||||
}
|
||||
dontTouch(regFile)
|
||||
}
|
||||
|
||||
object RegisterFile {
|
||||
def apply[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int): RegFileInterface[T] = {
|
||||
val core = Module(new RegisterFileCore(size, tpe, numReadPorts))
|
||||
val _out = Wire(new RegFileInterface(size, tpe, numReadPorts, numWritePorts))
|
||||
val clock = core.clock
|
||||
for (i <- 0 until numReadPorts) {
|
||||
core.readPorts(i).addr := _out.in.rs(i)
|
||||
_out.out.src(i) := core.readPorts(i).data
|
||||
}
|
||||
core.writePort.addr := _out.in.writeAddr
|
||||
core.writePort.data := _out.in.writeData(_out.control.writeSelect.asUInt)
|
||||
core.writePort.enable := _out.control.writeEnable
|
||||
_out
|
||||
}
|
||||
}
|
24
npc/core/src/main/scala/SegControllerGenerator.scala
Normal file
24
npc/core/src/main/scala/SegControllerGenerator.scala
Normal file
|
@ -0,0 +1,24 @@
|
|||
package npc.util
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import chisel3.util.log2Ceil
|
||||
|
||||
class SegControllerGenerator[T <: Data](seg_count: Int, t: T) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val in_segs = Input(Vec(seg_count / ((t.getWidth + 3) / 4), t))
|
||||
val segs = Output(Vec(seg_count, UInt(8.W)))
|
||||
})
|
||||
val digit_to_seg = ((0 until 16).map(_.U)).zip(Seq(
|
||||
"b00000011".U, "b10011111".U, "b00100101".U, "b00001101".U,
|
||||
"b10011001".U, "b01001001".U, "b01000001".U, "b00011111".U,
|
||||
"b00000001".U, "b00001001".U, "b00010001".U, "b11000001".U,
|
||||
"b01100011".U, "b10000101".U, "b01100001".U, "b01110001".U,
|
||||
))
|
||||
val vec = io.in_segs.asTypeOf(Vec(seg_count, UInt(4.W)))
|
||||
|
||||
val segs = VecInit(Seq.fill(seg_count)(0.U(8.W)))
|
||||
segs := vec.map(MuxLookup(_, 0xFF.U)(digit_to_seg))
|
||||
|
||||
io.segs := segs
|
||||
}
|
62
npc/core/src/test/scala/Keyboard.scala
Normal file
62
npc/core/src/test/scala/Keyboard.scala
Normal file
|
@ -0,0 +1,62 @@
|
|||
package npc.keyboard
|
||||
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.freespec.AnyFreeSpec
|
||||
import chiseltest.simulator.WriteVcdAnnotation
|
||||
|
||||
import npc.util._
|
||||
|
||||
class KeyboardControllerSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||
def transfer(keycode: Int, clock: Clock, ps2: PS2Port) : Unit = {
|
||||
require(keycode >= 0 && keycode < 0xFF)
|
||||
var cycle = 0
|
||||
var keycode_remain = keycode << 1 // Shift 1 to do nothing at cycle 0
|
||||
var keycode_collect = 0
|
||||
|
||||
ps2.data.poke(1)
|
||||
ps2.clk.poke(true)
|
||||
clock.step(1)
|
||||
for (cycle <- 0 until 9) {
|
||||
val last_digit = keycode_remain & 1
|
||||
ps2.clk.poke(true)
|
||||
ps2.data.poke(last_digit)
|
||||
clock.step(32)
|
||||
keycode_collect = keycode_collect | (last_digit << cycle)
|
||||
keycode_remain = keycode_remain >> 1
|
||||
ps2.clk.poke(false)
|
||||
clock.step(32)
|
||||
}
|
||||
for (_ <- 9 until 11) {
|
||||
ps2.clk.poke(true)
|
||||
clock.step(32)
|
||||
ps2.clk.poke(false)
|
||||
clock.step(32)
|
||||
}
|
||||
assert(keycode_collect >> 1 == keycode)
|
||||
clock.step(32)
|
||||
}
|
||||
"Simple test" in {
|
||||
test(new KeyboardController).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
||||
val data = Array(0xE4, 0xD4, 0xC4, 0xA9)
|
||||
data.foreach(d => {
|
||||
transfer(d, c.clock, c.io.ps2)
|
||||
c.io.out.valid.expect(1.U)
|
||||
c.io.out.bits.expect(d)
|
||||
c.io.out.ready.poke(1)
|
||||
c.clock.step(1)
|
||||
c.io.out.ready.poke(0)
|
||||
})
|
||||
data.foreach(d => {
|
||||
transfer(d, c.clock, c.io.ps2)
|
||||
})
|
||||
data.foreach(d => {
|
||||
c.io.out.valid.expect(1.U)
|
||||
c.io.out.bits.expect(d)
|
||||
c.io.out.ready.poke(1)
|
||||
c.clock.step(1)
|
||||
c.io.out.ready.poke(0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
47
npc/core/src/test/scala/Main.scala
Normal file
47
npc/core/src/test/scala/Main.scala
Normal file
|
@ -0,0 +1,47 @@
|
|||
package flow
|
||||
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.freespec.AnyFreeSpec
|
||||
import chiseltest.simulator.WriteVcdAnnotation
|
||||
|
||||
import flow.Flow
|
||||
|
||||
class RV32CPUSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||
"MemoryFile" - {
|
||||
"correctly load" in {
|
||||
import chisel3.util.{SRAM, SRAMInterface, HexMemoryFile}
|
||||
class UserMem extends Module {
|
||||
val io = IO(new SRAMInterface(1024, UInt(32.W), 1, 1, 0))
|
||||
val memoryFile = HexMemoryFile("../resource/addi.txt")
|
||||
io :<>= SRAM(
|
||||
size = 1024,
|
||||
tpe = UInt(32.W),
|
||||
numReadPorts = 1,
|
||||
numWritePorts = 1,
|
||||
numReadwritePorts = 0,
|
||||
memoryFile = memoryFile
|
||||
)
|
||||
|
||||
val read = io.readPorts(0).data
|
||||
printf(cf"memoryFile=$memoryFile, readPort=$read%x\n")
|
||||
}
|
||||
test(new UserMem).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
||||
c.io.readPorts(0).enable.poke(true.B)
|
||||
c.io.writePorts(0).enable.poke(false.B)
|
||||
c.io.writePorts(0).address.poke(0.U)
|
||||
c.io.writePorts(0).data.poke(0.U)
|
||||
for (i <- 0 until 32) {
|
||||
c.io.readPorts(0).address.poke(i.U)
|
||||
c.clock.step(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"should compile" in {
|
||||
test(new Flow) { c =>
|
||||
c.clock.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
81
npc/core/src/test/scala/RegisterFile.scala
Normal file
81
npc/core/src/test/scala/RegisterFile.scala
Normal file
|
@ -0,0 +1,81 @@
|
|||
package flow
|
||||
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.freespec.AnyFreeSpec
|
||||
import chiseltest.simulator.WriteVcdAnnotation
|
||||
|
||||
import flow.components._
|
||||
class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||
"RegisterFileCore" - {
|
||||
"register 0 is always 0" in {
|
||||
test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
|
||||
c.readPorts(0).addr.poke(0)
|
||||
c.readPorts(1).addr.poke(0)
|
||||
c.writePort.enable.poke(true)
|
||||
c.writePort.addr.poke(0)
|
||||
c.writePort.data.poke(0x1234)
|
||||
|
||||
c.readPorts(0).data.expect(0)
|
||||
c.readPorts(1).data.expect(0)
|
||||
c.clock.step(2)
|
||||
c.readPorts(0).data.expect(0)
|
||||
c.readPorts(1).data.expect(0)
|
||||
}
|
||||
}
|
||||
"register other than 0 can be written" in {
|
||||
test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
|
||||
import scala.util.Random
|
||||
val r = new Random()
|
||||
for (i <- 1 until 32) {
|
||||
val v = r.nextLong() & 0xFFFFFFFFL
|
||||
c.readPorts(0).addr.poke(i)
|
||||
c.writePort.enable.poke(true)
|
||||
c.writePort.addr.poke(i)
|
||||
c.writePort.data.poke(v)
|
||||
|
||||
c.clock.step(1)
|
||||
c.readPorts(0).data.expect(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"RegisterInterface" - {
|
||||
class Top extends Module {
|
||||
val io = IO(new RegFileInterface(32, UInt(32.W), 2, 2))
|
||||
val rf = RegisterFile(32, UInt(32.W), 2, 2)
|
||||
io :<>= rf
|
||||
}
|
||||
"write" in {
|
||||
test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
||||
import c.io.control.WriteSelect._
|
||||
val writePort = rAluOut.litValue.toInt
|
||||
c.io.control.writeEnable.poke(true)
|
||||
c.io.control.writeSelect.poke(rAluOut)
|
||||
c.io.in.writeAddr.poke(5)
|
||||
c.io.in.writeData(writePort).poke(0xcdef)
|
||||
c.io.in.rs(0).poke(5)
|
||||
c.clock.step(1)
|
||||
c.io.out.src(0).expect(0xcdef)
|
||||
}
|
||||
}
|
||||
"no data is written when not enabled" in {
|
||||
test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
||||
import c.io.control.WriteSelect._
|
||||
val writePort = rAluOut.litValue.toInt
|
||||
c.io.control.writeEnable.poke(true)
|
||||
c.io.control.writeSelect.poke(rAluOut)
|
||||
c.io.in.writeAddr.poke(5)
|
||||
c.io.in.writeData(writePort).poke(0xcdef)
|
||||
c.io.in.rs(0).poke(5)
|
||||
c.clock.step(1)
|
||||
|
||||
c.io.control.writeEnable.poke(false)
|
||||
c.io.in.writeData(writePort).poke(0x1234)
|
||||
c.clock.step(1)
|
||||
|
||||
c.io.out.src(0).expect(0xcdef)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
npc/csrc/Flow/main.cpp
Normal file
43
npc/csrc/Flow/main.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
#include <VFlow.h>
|
||||
#define MAX_SIM_TIME 100
|
||||
#define VERILATOR_TRACE
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int sim_time = 0;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
VFlow *top = new VFlow;
|
||||
|
||||
Verilated::traceEverOn(true);
|
||||
VerilatedVcdC *m_trace = new VerilatedVcdC;
|
||||
#ifdef VERILATOR_TRACE
|
||||
top->trace(m_trace, 5);
|
||||
m_trace->open("waveform.vcd");
|
||||
#endif
|
||||
for (sim_time = 0; sim_time < 10; sim_time++) {
|
||||
top->eval();
|
||||
top->clock = !top->clock;
|
||||
top->reset = 1;
|
||||
#ifdef VERILATOR_TRACE
|
||||
m_trace->dump(sim_time);
|
||||
#endif
|
||||
}
|
||||
top->reset = 0;
|
||||
for (sim_time = 10; sim_time < MAX_SIM_TIME; sim_time++) {
|
||||
top->eval();
|
||||
top->clock = !top->clock;
|
||||
#ifdef VERILATOR_TRACE
|
||||
m_trace->dump(sim_time);
|
||||
#endif
|
||||
}
|
||||
#ifdef VERILATOR_TRACE
|
||||
m_trace->close();
|
||||
#endif
|
||||
delete top;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
12
npc/csrc/Keyboard/main.cpp
Normal file
12
npc/csrc/Keyboard/main.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int sim_time = 0;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
36
npc/csrc/Switch/main.cpp
Normal file
36
npc/csrc/Switch/main.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
#include <VSwitch.h>
|
||||
|
||||
const int MAX_SIM_TIME=100;
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
int sim_time = 0;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
VSwitch *top = new VSwitch;
|
||||
|
||||
Verilated::traceEverOn(true);
|
||||
VerilatedVcdC *m_trace = new VerilatedVcdC;
|
||||
#ifdef VERILATOR_TRACE
|
||||
top->trace(m_trace, 5);
|
||||
m_trace->open("waveform.vcd");
|
||||
#endif
|
||||
for (sim_time = 0; sim_time < MAX_SIM_TIME; sim_time++) {
|
||||
top->io_sw_0 = rand() % 2;
|
||||
top->io_sw_1 = rand() % 2;
|
||||
top->eval();
|
||||
printf("sw0 = %d, sw1 = %d, ledr = %d\n", top->io_sw_0, top->io_sw_1, top->io_out);
|
||||
assert(top->io_out == (top->io_sw_0 ^ top->io_sw_1));
|
||||
#ifdef VERILATOR_TRACE
|
||||
m_trace->dump(sim_time);
|
||||
#endif
|
||||
}
|
||||
#ifdef VERILATOR_TRACE
|
||||
m_trace->close();
|
||||
#endif
|
||||
delete top;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello, ysyx!\n");
|
||||
return 0;
|
||||
}
|
12
npc/csrc_nvboard/Flow/main.cpp
Normal file
12
npc/csrc_nvboard/Flow/main.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
// #include <nvboard.h>
|
||||
#include <VFlow.h>
|
||||
|
||||
const int MAX_SIM_TIME=100;
|
||||
|
||||
// void nvboard_bind_all_pins(VFLow* top);
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
return 0;
|
||||
}
|
59
npc/csrc_nvboard/Keyboard/main.cpp
Normal file
59
npc/csrc_nvboard/Keyboard/main.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <nvboard.h>
|
||||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
|
||||
#ifndef VERILATOR_TOPMODULE
|
||||
#define VERILATOR_TOPMODULE VKeyboard
|
||||
#endif
|
||||
|
||||
#define CLASS_SYSTEM_HEADER_NAME(name) CLASS_SYSTEM_HEADER_NAME_IMPL(name)
|
||||
#define CLASS_SYSTEM_HEADER_NAME_IMPL(name) <name.h>
|
||||
#include CLASS_SYSTEM_HEADER_NAME(VERILATOR_TOPMODULE)
|
||||
#undef CLASS_SYSTEM_HEADER_NAME
|
||||
#undef CLASS_SYSTEM_HEADER_NAME_IMPL
|
||||
|
||||
int keycode = 0;
|
||||
|
||||
template <class F> void cycle(VERILATOR_TOPMODULE *top, F &&f) {
|
||||
top->clock = 0;
|
||||
top->eval();
|
||||
top->clock = 1;
|
||||
top->eval();
|
||||
f();
|
||||
}
|
||||
|
||||
void nvboard_bind_all_pins(VERILATOR_TOPMODULE *top);
|
||||
|
||||
static void single_cycle(VERILATOR_TOPMODULE *top) {
|
||||
top->clock = 0;
|
||||
top->eval();
|
||||
top->clock = 1;
|
||||
top->eval();
|
||||
}
|
||||
|
||||
static void reset(VERILATOR_TOPMODULE *top, int n) {
|
||||
top->reset = 1;
|
||||
while (n-- > 0)
|
||||
single_cycle(top);
|
||||
top->reset = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
VERILATOR_TOPMODULE *top = new VERILATOR_TOPMODULE;
|
||||
|
||||
nvboard_bind_all_pins(top);
|
||||
nvboard_init();
|
||||
reset(top, 10);
|
||||
while (true) {
|
||||
nvboard_update();
|
||||
cycle(top, [&] {
|
||||
if (keycode != top->io_ps2_data){
|
||||
keycode = top->io_ps2_data;
|
||||
printf("%d\n", keycode);
|
||||
}
|
||||
});
|
||||
}
|
||||
delete top;
|
||||
}
|
23
npc/csrc_nvboard/Switch/main.cpp
Normal file
23
npc/csrc_nvboard/Switch/main.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
#include <nvboard.h>
|
||||
#include <VSwitch.h>
|
||||
|
||||
const int MAX_SIM_TIME=100;
|
||||
|
||||
void nvboard_bind_all_pins(VSwitch* top);
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
VSwitch *top = new VSwitch;
|
||||
|
||||
nvboard_bind_all_pins(top);
|
||||
nvboard_init();
|
||||
while (true) {
|
||||
nvboard_update();
|
||||
top->eval();
|
||||
}
|
||||
delete top;
|
||||
}
|
99
npc/flake.lock
generated
Normal file
99
npc/flake.lock
generated
Normal file
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709961763,
|
||||
"narHash": "sha256-6H95HGJHhEZtyYA3rIQpvamMKAGoa8Yh2rFV29QnuGw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3030f185ba6a4bf4f18b87f345f104e6a6961f34",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-circt162": {
|
||||
"locked": {
|
||||
"lastModified": 1705645507,
|
||||
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nur-xin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1707020873,
|
||||
"narHash": "sha256-+dNltc7tjgTIyle/I/5siQ5IvPwu+R5Uf6e24CmjLNk=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "8142717e7154dbaadee0679f0224fe75cebb1735",
|
||||
"revCount": 147,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-circt162": "nixpkgs-circt162",
|
||||
"nur-xin": "nur-xin"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
116
npc/flake.nix
Normal file
116
npc/flake.nix
Normal file
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
nixpkgs-circt162.url = "github:NixOS/nixpkgs/7995cae3ad60e3d6931283d650d7f43d31aaa5c7";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nur-xin = {
|
||||
url = "git+https://git.xinyang.life/xin/nur.git";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, ... }@inputs: with inputs;
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; config.allowUnfree = true; }//
|
||||
{ nur.xin = nur-xin.legacyPackages.${system}; };
|
||||
in
|
||||
{
|
||||
devShells.default = with pkgs; mkShell {
|
||||
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
|
||||
packages = [
|
||||
clang-tools
|
||||
# rnix-lsp
|
||||
coursier
|
||||
espresso
|
||||
|
||||
gdb
|
||||
jre
|
||||
|
||||
gtkwave
|
||||
];
|
||||
|
||||
inputsFrom = [ self.packages.${system}.default ];
|
||||
};
|
||||
packages.default = with pkgs; clangStdenv.mkDerivation {
|
||||
name = "npc";
|
||||
version = "0.0.1";
|
||||
src = ./.;
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
sbt
|
||||
nur.xin.nvboard
|
||||
nixpkgs-circt162.legacyPackages.${system}.circt
|
||||
yosys
|
||||
];
|
||||
buildInputs = [
|
||||
verilator
|
||||
nur.xin.nvboard
|
||||
];
|
||||
|
||||
NEMU_HOME="/home/xin/repo/ysyx-workbench/nemu";
|
||||
};
|
||||
|
||||
# This version (1.43.0) of circt does not exist in nixpkgs
|
||||
# and Chisel 5.1.0 specifically build against it, so here we are.
|
||||
# Ref: https://github.com/NixOS/nixpkgs/blob/b6465c8/pkgs/development/compilers/circt/default.nix
|
||||
packages.circt =
|
||||
with pkgs;
|
||||
let
|
||||
pythonEnv = python3.withPackages (ps: [ ps.psutil ]);
|
||||
in
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "circt";
|
||||
version = "1.43.0";
|
||||
src = fetchFromGitHub {
|
||||
owner = "llvm";
|
||||
repo = "circt";
|
||||
rev = "firtool-${version}";
|
||||
sha256 = "sha256-RkjigboswLkLgLkgOGahQLIygCkC3Q9rbVw3LqIzREY=";
|
||||
fetchSubmodules = true;
|
||||
};
|
||||
|
||||
requiredSystemFeatures = [ "big-parallel" ];
|
||||
|
||||
nativeBuildInputs = [ cmake ninja git pythonEnv ];
|
||||
|
||||
cmakeDir = "../llvm/llvm";
|
||||
cmakeFlags = [
|
||||
"-DLLVM_ENABLE_BINDINGS=OFF"
|
||||
"-DLLVM_ENABLE_OCAMLDOC=OFF"
|
||||
"-DLLVM_BUILD_EXAMPLES=OFF"
|
||||
"-DLLVM_OPTIMIZED_TABLEGEN=ON"
|
||||
"-DLLVM_ENABLE_PROJECTS=mlir"
|
||||
"-DLLVM_EXTERNAL_PROJECTS=circt"
|
||||
"-DLLVM_EXTERNAL_CIRCT_SOURCE_DIR=.."
|
||||
"-DCIRCT_LLHD_SIM_ENABLED=OFF"
|
||||
];
|
||||
|
||||
LIT_FILTER_OUT = if stdenv.cc.isClang then "CIRCT :: Target/ExportSystemC/.*\.mlir" else null;
|
||||
|
||||
preConfigure = ''
|
||||
find ./test -name '*.mlir' -exec sed -i 's|/usr/bin/env|${coreutils}/bin/env|g' {} \;
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
mv bin/{{fir,hls}tool,circt-{as,dis,lsp-server,opt,reduce,translate}} $out/bin
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
checkTarget = "check-circt check-circt-integration";
|
||||
|
||||
meta = {
|
||||
description = "Circuit IR compilers and tools";
|
||||
homepage = "https://circt.org/";
|
||||
license = lib.licenses.asl20;
|
||||
maintainers = with lib.maintainers; [ sharzy ];
|
||||
platforms = lib.platforms.all;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
10
npc/resource/addi.txt
Normal file
10
npc/resource/addi.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
||||
00114113
|
|
@ -1,2 +0,0 @@
|
|||
module example();
|
||||
endmodule
|
Loading…
Add table
Reference in a new issue