mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-11 01:11:42 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e62cd8162 | ||
|
|
8b45d04288 | ||
|
|
c94c7a9b85 | ||
|
|
ee6a7fe78d | ||
|
|
d3a71803ed | ||
|
|
1e5eed8f21 | ||
|
|
697b3b6503 | ||
|
|
7812cc1818 | ||
|
|
499c964986 | ||
|
|
49fac42e69 | ||
|
|
2b746cd26c | ||
|
|
dafb57010c | ||
|
|
cab7096e0f | ||
|
|
a3d6392e1c | ||
|
|
b4221bcaaf | ||
|
|
feab2746da | ||
|
|
eccd72d17f | ||
|
|
d3228ea52d | ||
|
|
bff8a1413f | ||
|
|
d6f216928c | ||
|
|
92099bec6f | ||
|
|
1b148ab9cb | ||
|
|
d3e7ced3b4 | ||
|
|
9cf118a72f | ||
|
|
cc81fd1015 | ||
|
|
da45ad792b | ||
|
|
8feff4afa3 | ||
|
|
104e4bd66d | ||
|
|
5f891de18a | ||
|
|
83b43e8405 | ||
|
|
682fc36ac7 | ||
|
|
d7fd2ccba8 | ||
|
|
66e01e02cc | ||
|
|
76cf49834a | ||
|
|
f8f1729cbe | ||
|
|
181570e50d | ||
|
|
878419da0e | ||
|
|
fbaf7d8118 | ||
|
|
345a7cb89f | ||
|
|
2650062d70 | ||
|
|
2b0c91e3c3 | ||
|
|
15bb0e0593 | ||
|
|
2e472e8401 | ||
|
|
53af7cbbcc | ||
|
|
bafa58534a | ||
|
|
495803ea63 | ||
|
|
7f09b67df9 | ||
|
|
8ddd630850 | ||
|
|
5f9804fb65 | ||
|
|
e142c3be5a | ||
|
|
6e367916da | ||
|
|
c4863ef672 | ||
|
|
ad978f3daf | ||
|
|
fbdd42beb6 | ||
|
|
a349770472 | ||
|
|
08c00d186a | ||
|
|
4c3786b067 | ||
|
|
a8f3e353cd | ||
|
|
98dc6faefb | ||
|
|
41157ad555 | ||
|
|
43cfbd629c | ||
|
|
3e9ce82ccb | ||
|
|
71d5a59c19 | ||
|
|
509d749663 | ||
|
|
bf9caa706c | ||
|
|
8bac0decbe | ||
|
|
4e73783cc1 | ||
|
|
257a6db658 | ||
|
|
e02938c23f | ||
|
|
f0fe40d5da | ||
|
|
990fd4e21c | ||
|
|
6769031bfb | ||
|
|
013b4f2645 | ||
|
|
75821d404b | ||
|
|
0311d1ca56 | ||
|
|
6a7898396a | ||
|
|
a4dbeb45d1 | ||
|
|
d13715d8bb | ||
|
|
03bfe5a3ab | ||
|
|
9b32ef7faa | ||
|
|
c05d7b2070 | ||
|
|
239a902a77 | ||
|
|
b7da32113f | ||
|
|
cbc3acada1 | ||
|
|
75e17ca213 | ||
|
|
0d376ddb24 | ||
|
|
cff8b55310 | ||
|
|
acff6a93ad | ||
|
|
fdea53cad4 | ||
|
|
ca03794534 | ||
|
|
4c646c539e | ||
|
|
7c74821b78 | ||
|
|
019ceea8d6 | ||
|
|
33a406701e | ||
|
|
9bfa1fe7ce | ||
|
|
21c24b31ad | ||
|
|
98b3c8ef7b | ||
|
|
f514327594 | ||
|
|
4c3b7b636f | ||
|
|
2c867d37e6 | ||
|
|
901cfd7e52 | ||
|
|
7565591cf8 | ||
|
|
6502327ad2 | ||
|
|
d5cba61203 | ||
|
|
3ae339ae14 | ||
|
|
26d63dd04a | ||
|
|
f9d54ebbb0 | ||
|
|
1508f6b488 | ||
|
|
146bc3764d | ||
|
|
4cfa728413 | ||
|
|
600964d722 | ||
|
|
241f0e9a36 | ||
|
|
462afe89f8 | ||
|
|
7e237528b4 | ||
|
|
076d73fafb | ||
|
|
9ab140b289 | ||
|
|
4418470316 | ||
|
|
fda7c79b51 | ||
|
|
4713fb37cc | ||
|
|
84b5222332 | ||
|
|
f11ad490cd | ||
|
|
4b2b00a834 | ||
|
|
608556e0a9 | ||
|
|
f2ca7a973c | ||
|
|
be869f9772 | ||
|
|
5a4d333734 | ||
|
|
81692a076c | ||
|
|
b6350b3c0f | ||
|
|
0734768955 | ||
|
|
4aa3b27de2 | ||
|
|
89b3e5a20b | ||
|
|
65a3d38a2a | ||
|
|
aa9c641083 | ||
|
|
b178d3d51a | ||
|
|
32bfb2ed08 | ||
|
|
7f7cc868c4 | ||
|
|
334101d599 | ||
|
|
65e6d0a397 | ||
|
|
fff03a3d56 | ||
|
|
bbbd621130 | ||
|
|
fc50ad03ae | ||
|
|
b7a1fe926a | ||
|
|
c4588ee4f4 | ||
|
|
21d5bf4183 | ||
|
|
e38b7e586d | ||
|
|
e01d5c1866 | ||
|
|
4e96e39ab2 | ||
|
|
9fce98f7d7 | ||
|
|
91c0844f19 | ||
|
|
b872687145 | ||
|
|
8914915b31 | ||
|
|
188171b49d | ||
|
|
4befb14e47 | ||
|
|
42118b22e4 | ||
|
|
8af10a6816 | ||
|
|
6dd3fdca68 | ||
|
|
56a848b59d | ||
|
|
ac06c41145 | ||
|
|
267b6e0f21 | ||
|
|
164775e4a7 | ||
|
|
c2004f6ad5 | ||
|
|
832a2ada10 | ||
|
|
383d2db303 | ||
|
|
358985e8c1 | ||
|
|
41b6147ca7 | ||
|
|
6868f1bf1d | ||
|
|
4d43b2ce1f | ||
|
|
c41666fee6 | ||
|
|
768a4724af | ||
|
|
2ed64ef858 | ||
|
|
b269647a9f | ||
|
|
db97949965 | ||
|
|
81a67475dd | ||
|
|
92211c78ec | ||
|
|
1359f36703 | ||
|
|
ae9c3ae728 | ||
|
|
d61664e724 | ||
|
|
ec21b9f44c | ||
|
|
6822628135 | ||
|
|
0a6147c177 | ||
|
|
9b521dd87b | ||
|
|
e4fee670ad | ||
|
|
3a6113846f | ||
|
|
a0c7b3bf6a | ||
|
|
11003eb5f1 | ||
|
|
dadf0d4228 | ||
|
|
4fede70705 | ||
|
|
b984bb52e9 | ||
|
|
b6bdd06c4e | ||
|
|
c57130a4bf | ||
|
|
7a9a99f62c | ||
|
|
8156a7b760 | ||
|
|
ff5c8acd9a | ||
|
|
6584f6e691 | ||
|
|
662c1f7b66 | ||
|
|
4b70e4e891 | ||
|
|
2e6531a036 | ||
|
|
a79a9f0fbf | ||
|
|
326616f936 | ||
|
|
d213010a72 | ||
|
|
8b80201d16 | ||
|
|
c23d842a90 | ||
|
|
8b93f57293 | ||
|
|
a0f46b4dac | ||
|
|
d4f9caee65 | ||
|
|
5e48762c48 | ||
|
|
0ba4f49e04 | ||
|
|
cc8cf2539f | ||
|
|
663e341584 | ||
|
|
b4f6912d68 | ||
|
|
9f6a1548d1 | ||
|
|
2e8ac93a42 | ||
|
|
41b0a55af3 | ||
|
|
a6d4fd7c3e | ||
|
|
99d711497e | ||
|
|
518666b18a | ||
|
|
6d6c058d25 | ||
|
|
48e7bdc3b4 | ||
|
|
c46abdf02e | ||
|
|
0cbac7df02 | ||
|
|
9355fc2228 | ||
|
|
08b48cec4c | ||
|
|
0480285fa7 | ||
|
|
7770327d3c | ||
|
|
e57e77cb11 | ||
|
|
4c73d18494 | ||
|
|
1918c912c5 | ||
|
|
e6912d4514 | ||
|
|
12dbcb1b40 | ||
|
|
45a4f1a366 | ||
|
|
a51a52263a | ||
|
|
b395886327 | ||
|
|
95215dec1d | ||
|
|
b697623c13 | ||
|
|
d965cc8f13 | ||
|
|
00de20af93 | ||
|
|
8097ae3ae5 | ||
|
|
a63d20c0d1 | ||
|
|
5c05e80c48 | ||
|
|
f9b5a8a3a6 | ||
|
|
5db4443529 | ||
|
|
2f27d00d60 | ||
|
|
c03099fa51 | ||
|
|
ba3b00cd05 | ||
|
|
9ccab8b676 | ||
|
|
188bda9259 | ||
|
|
d749af17db | ||
|
|
539cd5cc15 | ||
|
|
1ad25e180c | ||
|
|
5220b1483e | ||
|
|
6869bbb971 | ||
|
|
458e4f6ca5 | ||
|
|
e9bcabf693 | ||
|
|
a1adfbba22 | ||
|
|
1d8dc20148 | ||
|
|
7f9346e5ec | ||
|
|
ad16c4a67a | ||
|
|
21c985b3da | ||
|
|
cb01795df6 | ||
|
|
ec87c304fa | ||
|
|
8eb2ff3eab | ||
|
|
de24f56cba | ||
|
|
90b0b19bf5 | ||
|
|
142ae1be99 | ||
|
|
e57c241424 | ||
|
|
1888b2934b | ||
|
|
3af6f1bf59 | ||
|
|
f088cfc31c | ||
|
|
3eff1d2efb | ||
|
|
88c347fdaa | ||
|
|
8f69189429 | ||
|
|
95ed00c0d2 | ||
|
|
463c52afe6 | ||
|
|
e39a4d979d | ||
|
|
6092f2bcff | ||
|
|
7bafe50098 | ||
|
|
fe50e29827 | ||
|
|
d862eeaf79 | ||
|
|
f08e7c66b3 | ||
|
|
7d1d5d1e68 | ||
|
|
f333f28cea | ||
|
|
a370a0eb5a | ||
|
|
5018755374 | ||
|
|
3d4db007a9 | ||
|
|
706a5850a1 | ||
|
|
0a9a6b58c2 | ||
|
|
0d588e0c0a | ||
|
|
9b74e87507 | ||
|
|
6b15519c9d | ||
|
|
e655b3c096 | ||
|
|
f3f1e4adcb | ||
|
|
516c2c6eba | ||
|
|
131e353b9b | ||
|
|
6d1a3a420c | ||
|
|
7b1a58aa47 | ||
|
|
ef1f05848e | ||
|
|
89718ab50a | ||
|
|
21cf7c99bf | ||
|
|
dabc688b26 | ||
|
|
ae179fef67 | ||
|
|
ec055dafcc | ||
|
|
8a71af4be1 | ||
|
|
c47afd5c76 | ||
|
|
f037be9248 | ||
|
|
48fa446eeb | ||
|
|
3fd666c583 | ||
|
|
9eb14aea6f | ||
|
|
3db5740bd3 | ||
|
|
3c226ed0ca | ||
|
|
191393445e | ||
|
|
621301990a | ||
|
|
d40b890d83 | ||
|
|
1891477e12 | ||
|
|
86207ff3a3 | ||
|
|
72956e4ba0 | ||
|
|
1256987e9c | ||
|
|
517dd3efc6 | ||
|
|
9176ed7418 | ||
|
|
4f4ec10cdf | ||
|
|
14db9f1ead | ||
|
|
81be3393dc | ||
|
|
d15439a292 | ||
|
|
7514b29e31 | ||
|
|
0afef3389a | ||
|
|
2dadc1e899 | ||
|
|
b07423749a | ||
|
|
1120921a1b | ||
|
|
9a826fd416 | ||
|
|
edd062c76f | ||
|
|
2429999b3c | ||
|
|
8cb9a4a9c9 | ||
|
|
a2bd8a46f5 | ||
|
|
1dcaf2d2c1 | ||
|
|
e7f4d8cd2b | ||
|
|
0ad3a7d8da | ||
|
|
92bf0c6669 | ||
|
|
e536ff34a8 | ||
|
|
519423fa68 | ||
|
|
3f31de661d | ||
|
|
7c57dfa7bc | ||
|
|
3b7e0d440b | ||
|
|
1e97bd6a8b | ||
|
|
4b43bbf853 | ||
|
|
b2a240b335 | ||
|
|
709afef820 | ||
|
|
6b70091f6c | ||
|
|
7a71b7e98f | ||
|
|
7b9d8e9232 | ||
|
|
de219e37e8 | ||
|
|
052f486793 | ||
|
|
0b3f87c97d | ||
|
|
35b5a4cf0a | ||
|
|
669fb4a433 | ||
|
|
418666dd20 | ||
|
|
e44cf2e956 | ||
|
|
a421550477 | ||
|
|
1474f1001d | ||
|
|
3d2f8e0633 | ||
|
|
dcbce15b24 | ||
|
|
08c75e6e55 | ||
|
|
018e07945a | ||
|
|
0355ef08ed | ||
|
|
c95a27d66a | ||
|
|
a46ab04e47 | ||
|
|
b8f6aeb52c | ||
|
|
d46f7a3445 | ||
|
|
4524f9d188 | ||
|
|
67d1647d6e | ||
|
|
619415d7dc | ||
|
|
2daf9f5908 | ||
|
|
68fe9514bf | ||
|
|
67a9b0ec1a | ||
|
|
0d02303de6 | ||
|
|
91d4fb70ec | ||
|
|
90af756e3c | ||
|
|
e1e11cf75e | ||
|
|
8f60efcb20 | ||
|
|
5ff724427a | ||
|
|
c60f91e5d5 | ||
|
|
b6919cd118 | ||
|
|
1294fdb679 | ||
|
|
d4b67a92d2 | ||
|
|
b442ef4624 | ||
|
|
4da6316d1d | ||
|
|
27bc5bc2bf | ||
|
|
3051af6e21 | ||
|
|
489ac87a1c | ||
|
|
ecb8d30b69 | ||
|
|
adacb0be02 | ||
|
|
29cdd17113 | ||
|
|
5866a1b9f1 | ||
|
|
5e8277b290 | ||
|
|
a1bd8e63eb | ||
|
|
265ba002e6 | ||
|
|
88879890fb | ||
|
|
af3e42515c | ||
|
|
8ed3b44f0b | ||
|
|
9c53d97491 | ||
|
|
6415c3a853 | ||
|
|
09aa6346c7 | ||
|
|
98ea150bce | ||
|
|
d1847c9cd3 | ||
|
|
9c9d7d4bf3 | ||
|
|
48454fe53a | ||
|
|
6d17f38be4 | ||
|
|
9819f2f967 | ||
|
|
3088c4942c | ||
|
|
353272a1db | ||
|
|
f42258bf9f | ||
|
|
6bd57e790e | ||
|
|
7ea6cf76e4 | ||
|
|
50dd52bb47 | ||
|
|
baccd50410 | ||
|
|
e3323e248f | ||
|
|
1622ac00a5 | ||
|
|
03462690b1 | ||
|
|
69e5025e7a | ||
|
|
aa9abd7f68 | ||
|
|
cc792b71fe | ||
|
|
98ccd3c31f | ||
|
|
98bd18757b | ||
|
|
4fe7c7d82d | ||
|
|
4e36ce7ad5 | ||
|
|
ba862a2508 | ||
|
|
fc425940b6 | ||
|
|
c756ae6ea3 | ||
|
|
22e71d1d21 | ||
|
|
feff5bf56c | ||
|
|
bcb7713415 | ||
|
|
9b1648f6b2 | ||
|
|
f1df1db489 | ||
|
|
94764b7fd7 | ||
|
|
fbc921ade9 | ||
|
|
6bff023264 | ||
|
|
ac005568be | ||
|
|
299f25b8d1 | ||
|
|
0d73fb47d6 | ||
|
|
c0d96da45a | ||
|
|
0f50ac2810 | ||
|
|
1c169602dc | ||
|
|
9e8255d213 | ||
|
|
9151cf66fc | ||
|
|
494068fd9d | ||
|
|
bd65032a88 | ||
|
|
d973a52e99 | ||
|
|
726ca11ea3 | ||
|
|
3049510000 | ||
|
|
84cd3ccd46 | ||
|
|
927b9f16aa | ||
|
|
0b739bfd36 | ||
|
|
b49dd6a4ca | ||
|
|
c0e8b64b68 | ||
|
|
bcfcbd6735 | ||
|
|
92424dc97d | ||
|
|
e73ec4cac9 | ||
|
|
480343bb98 | ||
|
|
477e4c6f12 | ||
|
|
40b8728b1f | ||
|
|
2db3a09162 | ||
|
|
ed43ab72b2 | ||
|
|
f1b7eb0589 | ||
|
|
148eac9346 | ||
|
|
5a58ebdad6 | ||
|
|
45667df0f1 | ||
|
|
817317c5b3 | ||
|
|
f3cc8ff52f | ||
|
|
6986881a94 | ||
|
|
4e4c50be19 | ||
|
|
f757d496ce | ||
|
|
ef62807b77 | ||
|
|
7c17727d1a | ||
|
|
22f2d060d1 | ||
|
|
faf195eba7 | ||
|
|
6d22c9e368 | ||
|
|
97cd14960f | ||
|
|
543111c151 | ||
|
|
66b60d67d1 | ||
|
|
3c99afc0c0 | ||
|
|
acc4597407 | ||
|
|
19593e157f | ||
|
|
0c917f3803 | ||
|
|
86db200a23 | ||
|
|
2781365ac3 | ||
|
|
a238a7e754 | ||
|
|
299d211ab1 | ||
|
|
fc2278486e | ||
|
|
f7d5a87667 | ||
|
|
3e2934529e | ||
|
|
ff9afca894 | ||
|
|
3f002928ed | ||
|
|
b124e8a8f0 | ||
|
|
0f965050b1 | ||
|
|
b9cd02ddee | ||
|
|
b7198a2334 | ||
|
|
8967e05524 | ||
|
|
1b1e7f8f2c | ||
|
|
00eb27681e | ||
|
|
9ad4b27681 | ||
|
|
060eaba2ea | ||
|
|
d75a495fc1 | ||
|
|
f593b12416 | ||
|
|
2f3385776d | ||
|
|
fe8afe05de | ||
|
|
3545360033 | ||
|
|
bd9f52cf8c | ||
|
|
3d3513e365 | ||
|
|
5c61c3acbd | ||
|
|
6a0f2eaf1a | ||
|
|
9422ea5905 | ||
|
|
582fc8f846 | ||
|
|
73893352f7 | ||
|
|
47c9ec1f80 | ||
|
|
b482344691 | ||
|
|
cbdedc9f9c | ||
|
|
12a1585ee2 | ||
|
|
4644bb4494 | ||
|
|
a54b551e4d | ||
|
|
30724164be | ||
|
|
517e0cc454 | ||
|
|
2c489cdadd | ||
|
|
28a956111d | ||
|
|
7115ed9ab5 | ||
|
|
566184f669 | ||
|
|
8b5fbf511f | ||
|
|
c6a6972a75 | ||
|
|
59713ea9b1 | ||
|
|
4e1e3e02bb | ||
|
|
a26e1ae006 | ||
|
|
160ddb4457 | ||
|
|
8dda1836ac | ||
|
|
18884d6aa2 | ||
|
|
1e9c07c803 | ||
|
|
2c463d0322 | ||
|
|
2c3963c24e | ||
|
|
3d57bf7914 | ||
|
|
9fa501cc3a | ||
|
|
c66e3471e0 | ||
|
|
17924254a1 | ||
|
|
27fe06917e | ||
|
|
164ef7b678 | ||
|
|
2ad30215df | ||
|
|
d4ae964be4 | ||
|
|
228105e6de | ||
|
|
6c5e8ed49e | ||
|
|
019287a648 | ||
|
|
719dac2dc1 | ||
|
|
abf2ef5832 | ||
|
|
953a50d827 | ||
|
|
7c116300bc | ||
|
|
cbfd7ed270 | ||
|
|
78d926b31d | ||
|
|
a4d03c263f | ||
|
|
5283135a49 | ||
|
|
2c9cf460f3 | ||
|
|
2bcb236dd6 | ||
|
|
77ff400bb1 | ||
|
|
c87166f9c5 | ||
|
|
6827540f11 | ||
|
|
0615773904 | ||
|
|
c73e19bdf2 | ||
|
|
c0cac55065 | ||
|
|
e45e82bd19 | ||
|
|
26a7ac35ca | ||
|
|
9748b37532 | ||
|
|
0feacdc6a5 | ||
|
|
be2495b253 | ||
|
|
24762209aa | ||
|
|
74ec42e889 | ||
|
|
fa76d1fb16 | ||
|
|
c437bc2d25 | ||
|
|
86ec0d1226 | ||
|
|
12c771e5c9 | ||
|
|
451d562186 | ||
|
|
aa5efe67ef | ||
|
|
1749d4bd9b | ||
|
|
d21820dab7 | ||
|
|
51474d86e7 | ||
|
|
7fc641c787 | ||
|
|
1059725734 | ||
|
|
6396c8c9ac | ||
|
|
57647bf62b | ||
|
|
5176bfead1 | ||
|
|
91281a8247 | ||
|
|
c46beaff32 | ||
|
|
b3c49a4636 | ||
|
|
7ae217bc79 | ||
|
|
5d37682c6b | ||
|
|
d70cb368de | ||
|
|
4fcfa471a4 | ||
|
|
01da5ed20d | ||
|
|
433f230c9c | ||
|
|
91e49ab940 | ||
|
|
e464f45605 | ||
|
|
e062350552 | ||
|
|
74d6e885f6 | ||
|
|
ec34c02e4f | ||
|
|
0aa84312c5 | ||
|
|
17a654cfc4 | ||
|
|
027a3db94c | ||
|
|
38a7c74f28 | ||
|
|
3147c3c996 | ||
|
|
d6605625bc | ||
|
|
e534e56002 | ||
|
|
cf9c02e571 | ||
|
|
0483193439 | ||
|
|
6112bcaced | ||
|
|
64ae531ead | ||
|
|
e90c318c0e | ||
|
|
a4551216e9 | ||
|
|
2e38fa5fc6 | ||
|
|
e2b96c8bab | ||
|
|
4c3c07eb38 | ||
|
|
3e7ca5baec | ||
|
|
c74700f35d | ||
|
|
368578d736 | ||
|
|
65d9640b20 | ||
|
|
836f3fc976 | ||
|
|
5636e2b0f6 | ||
|
|
37bc375c64 | ||
|
|
50467b7e6d | ||
|
|
dc37e934e6 | ||
|
|
21e5daebfc | ||
|
|
8f579b1993 | ||
|
|
ed336af513 | ||
|
|
03186eb4d3 | ||
|
|
972495df89 | ||
|
|
3366b1dc6c | ||
|
|
2c86419dd8 | ||
|
|
0e30732950 | ||
|
|
0fb5569c6b | ||
|
|
f289cdd08a | ||
|
|
f0598aaeb3 | ||
|
|
1a498d64c9 | ||
|
|
c2f58d1c79 | ||
|
|
3d826f5b26 | ||
|
|
2bb95a13cb | ||
|
|
1de21e178c | ||
|
|
cde0e1603d | ||
|
|
6fe063815c | ||
|
|
b527a33b85 | ||
|
|
29a9c53a62 | ||
|
|
56fe0d8269 | ||
|
|
dc28723d52 | ||
|
|
36af497fdf | ||
|
|
d5c094e9e8 | ||
|
|
6adc70cbc8 | ||
|
|
2e385844d0 | ||
|
|
7e48079a46 | ||
|
|
f9eb9304f0 | ||
|
|
c3eb8bc49e | ||
|
|
8759a7d3e8 | ||
|
|
a785ce924b | ||
|
|
938b1647b0 | ||
|
|
6abe6bfb19 | ||
|
|
d22fae0cae | ||
|
|
4effa2b6d2 | ||
|
|
e6dfd5ee74 | ||
|
|
a5966490c9 | ||
|
|
f5f75cdeef | ||
|
|
a6209af97b | ||
|
|
93e24926ae | ||
|
|
6f3997dc38 | ||
|
|
b380834c0e | ||
|
|
9e551be17a | ||
|
|
d77c6f0788 | ||
|
|
a1df486779 | ||
|
|
cdedb9b0f5 | ||
|
|
9ff41ed45a | ||
|
|
56aa5dac0d | ||
|
|
ebde92c891 | ||
|
|
7dc55eeb54 | ||
|
|
ec4e0050e7 | ||
|
|
306d23f38b | ||
|
|
fa3dfa38cd | ||
|
|
a0601f1c79 | ||
|
|
19b56bc118 | ||
|
|
2f12a72cad | ||
|
|
ed0fe5599f | ||
|
|
081408e961 | ||
|
|
56d6488b3d | ||
|
|
85f1fb6b7f | ||
|
|
34d6d465c4 | ||
|
|
fcef806553 | ||
|
|
61258a7063 | ||
|
|
b1d216b8af | ||
|
|
c53023e6c8 | ||
|
|
637aa19a72 | ||
|
|
2cf4d8cac8 | ||
|
|
0071e8a7d4 | ||
|
|
d546f147c3 | ||
|
|
b03a942bf4 | ||
|
|
23416eae32 | ||
|
|
2ade0e39de | ||
|
|
62930f8da8 | ||
|
|
be1f424398 | ||
|
|
003afbbb58 | ||
|
|
3010c8a8c9 | ||
|
|
4a935893d2 | ||
|
|
32096b8e85 | ||
|
|
3142bd3aef | ||
|
|
9985c693bd | ||
|
|
81e15695c8 | ||
|
|
f486867292 | ||
|
|
ffa7040b6f | ||
|
|
247a269054 | ||
|
|
50b2a8f3ab | ||
|
|
f1e36f2775 | ||
|
|
997fda03fe | ||
|
|
c6ecbe81b2 | ||
|
|
9c9ef927d7 | ||
|
|
029ae18514 | ||
|
|
dcfce18d7f | ||
|
|
295c729ecf | ||
|
|
43e0dd770d | ||
|
|
6e9c08b491 | ||
|
|
1808e3f50c | ||
|
|
8f39e06900 | ||
|
|
7742b49289 | ||
|
|
4750a7f224 | ||
|
|
ff78815e90 | ||
|
|
00a5c6864e | ||
|
|
a38572199d | ||
|
|
bcd501edf6 | ||
|
|
8d1ad79fdb | ||
|
|
b2db7f16f6 | ||
|
|
080b53a652 | ||
|
|
2b9fcab30f | ||
|
|
5565d2def4 | ||
|
|
9aa05bcbe3 | ||
|
|
e0434ca82b | ||
|
|
9c5ecf52ce | ||
|
|
6d890244c1 | ||
|
|
f7657dca4f | ||
|
|
eda2918f58 | ||
|
|
d75c13107c | ||
|
|
1a5984be70 | ||
|
|
e1711eb28a | ||
|
|
1a564fa93e | ||
|
|
6118facaf2 | ||
|
|
d52a3b9dfc | ||
|
|
38495197d2 | ||
|
|
dd6a448bc4 | ||
|
|
1cea9ad1d9 | ||
|
|
14c9dc04fd | ||
|
|
9e983e720f | ||
|
|
b2dd52c0a4 | ||
|
|
9a3d949fc2 | ||
|
|
00819b70c0 | ||
|
|
cd83a939e8 |
No files matched your search
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report a bug *not* relating to game compatibility
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: Game Issue Report
|
||||
about: Report an issue running a specific game in ares
|
||||
title: "[system] Game"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Before submitting an issue, please use the search to make sure an issue doesn't already exist, you should also make sure your rom is not a bad dump, by comparing against the hashes in the No-Intro (Cartridges) or Redump (CD-ROM) databases.
|
||||
|
||||
**Describe the issue**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Rom Information**
|
||||
Specify the impacted rom filename and any associated hashes (sha256 preferred)
|
||||
|
||||
```
|
||||
file: Some Game (REGION).ext
|
||||
sha256: <hash>
|
||||
```
|
||||
+105
-16
@@ -13,17 +13,43 @@ jobs:
|
||||
- ares
|
||||
platform:
|
||||
- name: windows
|
||||
os: windows-latest
|
||||
compiler: g++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: mingw64
|
||||
msys-env: x86_64
|
||||
- name: windows-clang
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
windres: windres
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
msys-env: clang-x86_64
|
||||
install: mingw-w64-clang-x86_64-clang
|
||||
- name: windows-arm64
|
||||
os: windows-latest
|
||||
compiler: clang++ --target=aarch64-w64-windows-gnu --sysroot=/clangarm64 -resource-dir=/clangarm64/lib/clang/$(basename "$(clang++ -print-resource-dir)")
|
||||
windres: windres --target=aarch64-w64-windows-gnu
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-aarch64-clang
|
||||
- name: windows-msvc-x64
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
windres: llvm-rc
|
||||
shell: bash
|
||||
msvc-arch: x64
|
||||
- name: windows-msvc-arm64
|
||||
os: windows-latest
|
||||
compiler: clang++ --target=aarch64-w64-windows-msvc
|
||||
windres: llvm-rc
|
||||
shell: bash
|
||||
msvc-arch: x64_arm64
|
||||
- name: windows-cl-x64
|
||||
os: windows-latest
|
||||
compiler: cl
|
||||
windres: rc
|
||||
shell: bash
|
||||
msvc-arch: x64
|
||||
- name: windows-cl-arm64
|
||||
os: windows-latest
|
||||
compiler: cl
|
||||
windres: rc
|
||||
shell: bash
|
||||
msvc-arch: x64_arm64
|
||||
- name: macos
|
||||
os: macos-latest
|
||||
compiler: clang++
|
||||
@@ -43,15 +69,74 @@ jobs:
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: make mingw-w64-${{ matrix.platform.msys-env }}-toolchain
|
||||
install: make ${{ matrix.platform.install }}
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install libsdl2-dev libgtksourceview2.0-dev libgtk2.0-dev libao-dev libopenal-dev
|
||||
- uses: actions/checkout@v2
|
||||
sudo apt-get install libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && github.event_name != 'pull_request'
|
||||
uses: devbotsxyz/import-signing-certificate@2ac4f44d28045073d23153256efbb4c4b2d8aa22 # Don't use rolling branch for security reasons
|
||||
with:
|
||||
certificate-data: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
certificate-passphrase: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
keychain-name: ares-macos-keychain
|
||||
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
- name: "macOS: recover cache"
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: moltenvk
|
||||
with:
|
||||
path: thirdparty/MoltenVK/MoltenVK
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('thirdparty/MoltenVK/HEAD') }}
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install make ninja
|
||||
echo "MAKE=gmake" >> $GITHUB_ENV
|
||||
pushd thirdparty/MoltenVK
|
||||
./build-moltenvk.sh
|
||||
popd
|
||||
- name: Set up MSVC environment
|
||||
if: matrix.platform.msvc-arch != ''
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: ${{ matrix.platform.msvc-arch }}
|
||||
- name: Make
|
||||
run: make -j4 -C desktop-ui build=optimized local=false lto=true compiler=${{ matrix.platform.compiler }}
|
||||
if: runner.os != 'macOS'
|
||||
run: ${MAKE:-make} -j4 -C desktop-ui build=optimized local=false compiler="${{ matrix.platform.compiler }}" windres="${{ matrix.platform.windres }}"
|
||||
- name: "macOS: Make universal app"
|
||||
if: runner.os == 'macOS'
|
||||
run: scripts/macos-make-universal.sh
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_KEYCHAIN_NAME: ares-macos-keychain
|
||||
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
- name: "Windows: sign"
|
||||
if: runner.os == 'Windows' && github.event_name != 'pull_request'
|
||||
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
|
||||
with:
|
||||
certificate: '${{ secrets.WIN_CERTIFICATE }}'
|
||||
password: '${{ secrets.WIN_PASSWORD }}'
|
||||
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
|
||||
certificatename: '${{ secrets.WIN_CERTNAME }}'
|
||||
folder: 'desktop-ui/out'
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
- name: "macOS: notarize"
|
||||
if: runner.os == 'macOS' && github.event_name != 'pull_request'
|
||||
run: |
|
||||
ditto -c -k --keepParent desktop-ui/out/ares.app /tmp/ares.zip
|
||||
xcrun notarytool submit /tmp/ares.zip --apple-id "$MACOS_NOTARIZATION_USERNAME" --password "$MACOS_NOTARIZATION_PASSWORD" --team-id "$MACOS_NOTARIZATION_TEAMID" --wait
|
||||
xcrun stapler staple desktop-ui/out/ares.app
|
||||
env:
|
||||
MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
|
||||
MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
|
||||
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
@@ -87,16 +172,16 @@ jobs:
|
||||
# Hack: Workaround for GitHub artifacts losing attributes.
|
||||
chmod +x ${bindir}/ares-macos/ares.app/Contents/MacOS/ares
|
||||
|
||||
for os in windows macos
|
||||
for package in windows windows-msvc-arm64 macos
|
||||
do
|
||||
mkdir "${os}"
|
||||
cd "${os}"
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
|
||||
# Package ares.
|
||||
outdir=ares${suffix}
|
||||
mkdir ${outdir}
|
||||
cp -ar ${bindir}/ares-${os}/* ${outdir}
|
||||
zip -r ../ares-${os}.zip ${outdir}
|
||||
cp -ar ${bindir}/ares-${package}/* ${outdir}
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
|
||||
cd -
|
||||
done
|
||||
@@ -183,6 +268,10 @@ jobs:
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows.zip', asset_name: 'ares-windows.zip', asset_content_type: 'application/zip' }
|
||||
- name: Upload ares-windows-msvc-arm64
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows-msvc-arm64.zip', asset_name: 'ares-windows-msvc-arm64.zip', asset_content_type: 'application/zip' }
|
||||
- name: Upload ares-macos
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
name: 'Split Subtrees'
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
jobs:
|
||||
packages_split:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package:
|
||||
- nall
|
||||
- hiro
|
||||
- ruby
|
||||
- libco
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- if: "!startsWith(github.ref, 'refs/tags/')"
|
||||
uses: "symplify/[email protected]"
|
||||
with:
|
||||
package_directory: '${{ matrix.package }}'
|
||||
repository_organization: 'ares-emulator'
|
||||
repository_name: '${{ matrix.package }}'
|
||||
user_name: "Luke Usher"
|
||||
user_email: "[email protected]"
|
||||
@@ -1,2 +1,9 @@
|
||||
*.moc
|
||||
*.user
|
||||
.vs/
|
||||
obj/
|
||||
out/
|
||||
obj-amd64/
|
||||
obj-arm64/
|
||||
out-amd64/
|
||||
out-arm64/
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
all: desktop
|
||||
targets = all clean install uninstall verbose
|
||||
|
||||
desktop:
|
||||
$(MAKE) -C desktop-ui
|
||||
$(targets):
|
||||
@$(MAKE) -C desktop-ui $@
|
||||
|
||||
.PHONY: all desktop
|
||||
.PHONY: $(targets)
|
||||
@@ -45,38 +45,6 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
MAME
|
||||
Copyright (c) 1997-2021 MAMEdev and contributors
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
libchdr
|
||||
|
||||
@@ -145,4 +113,326 @@ Gailly and Mark Adler; it does not include third-party code.
|
||||
If you redistribute modified sources, we would appreciate that you include in
|
||||
the file ChangeLog history information documenting your changes. Please read
|
||||
the FAQ for more information on the distribution of modified source versions.
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2021 Yann Collet
|
||||
|
||||
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at:
|
||||
- xxHash homepage: https://www.xxhash.com
|
||||
- xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
MoltenVK
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
OpenGL API and Extension Registry
|
||||
https://github.com/KhronosGroup/OpenGL-Registry
|
||||
|
||||
Copyright 2013-2020 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
"Materials"), to deal in the Materials without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
permit persons to whom the Materials are furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Materials.
|
||||
|
||||
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
EGL API and Extension Registry
|
||||
https://github.com/KhronosGroup/EGL-Registry
|
||||
|
||||
Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
"Materials"), to deal in the Materials without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
permit persons to whom the Materials are furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Materials.
|
||||
|
||||
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
TZXFile
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 MrReeMachine
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
[](https://github.com/higan-emu/ares/blob/master/LICENSE)
|
||||
|
||||
@@ -16,3 +16,136 @@ Nightly Builds
|
||||
|
||||
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/higan-emu/ares/releases/tag/nightly).
|
||||
Only the latest nightly build is kept.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
### *nix building
|
||||
|
||||
###### Minimum required packages:
|
||||
```
|
||||
g++ make pkg-config libgtk-3-dev libcanberra-gtk-module libgl-dev libasound2-dev
|
||||
```
|
||||
###### Additional Audio Drivers
|
||||
ares supports additional audio drivers besides the ALSA drivers included above. Installing these additional packages will allow them to be selected in Settings > Drivers:
|
||||
`libao-dev libopenal-dev'
|
||||
|
||||
###### GTK2 & GTK3
|
||||
By default, GTK3 is used, but support for GTK2 is available. You will need to install the additional package `libgtk2.0-dev` as well as specifying the command line option `hiro=gtk2` at compile time.
|
||||
|
||||
###### SDL2 for input
|
||||
If you would like to use SDL for input, you will need to install the following the `libsdl2-dev` and `libsdl2-0.0` packages and perform a clean build of ares. You should then be able to select SDL for input in the Settings > Drivers menu.
|
||||
|
||||
##### Building with clang
|
||||
|
||||
clang++ is now the preferred compiler for ares. If it is detected, the build will default to building with clang. It is necessary to install both the `clang` and `lld` packages. If you would like to manually specify a compiler, you can use the following option: `compiler=[g++|clang++]`
|
||||
|
||||
--------------
|
||||
|
||||
### Windows building
|
||||
|
||||
To build on Windows, using MSYS2 is recommended which can be download [here](https://www.msys2.org/). Follow the instructions
|
||||
on this page to install and setup an appropriate MINGW64 environment. Running the command:
|
||||
```
|
||||
pacman -S --needed base-devel mingw-w64-x86_64-toolchain
|
||||
```
|
||||
from the MSYS2 MSYS terminal should setup everything you need to compile ares. Note that in order to compile, you will want to be in a MINGW64 terminal window after install and setup is complete.
|
||||
|
||||
##### Building with clang
|
||||
|
||||
clang is available through Visual Studio (or Build Tools for Visual Studio) through its installer and can be used to build ares. You will still need to supply GNU make in this instance. MSYS2 also offers a clang environment. You will want to make sure you select the clangw64 option during installation of MSYS2 which should provide and additional CLANG64 pre-configured environment. Install the clang toolchain package from the MSYS2 terminal:
|
||||
```
|
||||
pacman -S mingw-w64-clang-x86_64-toolchain
|
||||
```
|
||||
Once complete, open a CLANG64 terminal window and proceed with building ares.
|
||||
|
||||
###### Debug Symbols
|
||||
When building with clang, by default symbols will be generated for debug builds using an MSVC compatible format (CodeView) for use with Windows debugging tools. In order to generate GDB compatible symbols, specify the following option: `symformat=gdb`
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
Check out the source code by running this command:
|
||||
|
||||
```
|
||||
git clone https://github.com/ares-emulator/ares.git
|
||||
```
|
||||
|
||||
From the root of the project directory run:
|
||||
|
||||
```
|
||||
make -j4
|
||||
```
|
||||
|
||||
`-j#` indicates number of parallel build processes, and shouldn't be set higher than N-1 cores on your processor. Specifying this option can significantly decrease the time to build this project. There are multiple build types available and it defaults to an 'optimized' build. Build types can be specified using: `build=[debug|stable|release|minified|optimized]`
|
||||
|
||||
Build options can be found in the following two make files: nall/GNUmakefile desktop-ui/GNUmakefile
|
||||
|
||||
To start compilation from the beginning, run the following prior to compiling:
|
||||
|
||||
```
|
||||
make clean
|
||||
```
|
||||
|
||||
#### Building specific cores
|
||||
If you would like to build a subset of cores, you can specify the `cores="core1 core2"` option. Currently available cores:
|
||||
```
|
||||
a26 fc sfc n64 sg ms md ps1 pce ng msx cv gb gba ws ngp spec
|
||||
```
|
||||
|
||||
Build Output
|
||||
------------
|
||||
|
||||
There is a single binary produced at the end of compilation which can be found in `desktop-ui/out`. On OS's besides Linux, the `Database` & `Shader` directories are copied over here as well. On Linux, running `make install` after compilation will copy these directories and binary into suitable locations (see desktop-ui/GNUmakefile for details). Alternatively, these directories can be copied from `ares/Shaders/*` and `mia/Database/*`.
|
||||
|
||||
|
||||
Command-line options
|
||||
--------------------
|
||||
|
||||
When started from the command-line, ares accepts a few options.
|
||||
|
||||
```
|
||||
Usage: ./ares [options] game(s)
|
||||
|
||||
--help Displays available options and exit
|
||||
--fullscreen Start in full screen mode
|
||||
--system system Specify the system name
|
||||
--shader shader Specify GLSL shader name to load (requires OpenGL driver)
|
||||
--setting name=value Specify a value for a setting
|
||||
--dump-all-settings Show a list of all existing settings and exit
|
||||
--no-file-prompt Do not prompt to load (optional) additional roms (eg: 64DD)
|
||||
```
|
||||
|
||||
The --system option is useful when the system type cannot be auto-detected.
|
||||
--fullscreen will only have an effect if a game is also passed in argument.
|
||||
|
||||
Example:
|
||||
`ares --system MSX examples.rom --fullscreen`
|
||||
|
||||
Specifying multiple games allows for multi-cart support. For example, to load
|
||||
the Super GameBoy BIOS and a game in one command (to avoid a file prompt), you
|
||||
can do:
|
||||
|
||||
`ares "Super GameBoy.sfc" "Super Mario Land.gb"`
|
||||
|
||||
The --no-file-prompt option is useful if you wish to launch a game from CLI
|
||||
without being prompted to load additional roms. For example, some Nintendo 64
|
||||
games optionally support 64DD expansion disks, so this option can be used to
|
||||
suppress the "64DD Disk" file dialog, and assume any secondary content is
|
||||
disconnected.
|
||||
|
||||
High-level Components
|
||||
---------------------
|
||||
|
||||
* __ares__: emulator cores and component implementations
|
||||
* __desktop-ui__: main GUI implementation for this project
|
||||
* __hiro__: cross-platform GUI toolkit that utilizes native APIs on supported platforms
|
||||
* __nall__: Near's alternative to the C++ standard library
|
||||
* __ruby__: interface between a hiro application and platform-specific APIs for emulator video, audio, and input
|
||||
* __mia__: internal ROM database and ROM/image loader
|
||||
* __libco__: cooperative multithreading library
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Please join our discord to chat with other ares developers: https://discord.com/invite/gz2quhk2kv
|
||||
+13
-3
@@ -1,7 +1,5 @@
|
||||
ifeq ($(platform),windows)
|
||||
options += -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||
options += -Wl,-enable-auto-import
|
||||
options += -Wl,-enable-runtime-pseudo-reloc
|
||||
options += $(call lib,uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32)
|
||||
else ifeq ($(platform),macos)
|
||||
else ifneq ($(filter $(platform),linux bsd),)
|
||||
options += -Wl,-export-dynamic
|
||||
@@ -15,6 +13,10 @@ ares.objects := ares ares-fixed-allocator
|
||||
$(object.path)/ares.o: $(ares.path)/ares/ares.cpp
|
||||
$(object.path)/ares-fixed-allocator.o: $(ares.path)/ares/memory/fixed-allocator.cpp
|
||||
|
||||
ifeq ($(platform),macos)
|
||||
ares.dylibs :=
|
||||
endif
|
||||
|
||||
ifeq ($(vulkan),true)
|
||||
flags += -DVULKAN
|
||||
endif
|
||||
@@ -75,6 +77,10 @@ ifneq ($(filter $(cores),cv),)
|
||||
include $(ares.path)/cv/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),myvision),)
|
||||
include $(ares.path)/myvision/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),gb),)
|
||||
include $(ares.path)/gb/GNUmakefile
|
||||
endif
|
||||
@@ -95,6 +101,10 @@ ifneq ($(filter $(cores),ngp),)
|
||||
include $(ares.path)/ngp/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),spec),)
|
||||
include $(ares.path)/spec/GNUmakefile
|
||||
endif
|
||||
|
||||
include $(ares.path)/component/GNUmakefile
|
||||
|
||||
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,16 +1,16 @@
|
||||
#version 150
|
||||
|
||||
in vec4 position;
|
||||
in vec2 texCoord;
|
||||
|
||||
out Vertex {
|
||||
vec2 vTexCoord;
|
||||
};
|
||||
|
||||
uniform vec4 targetSize;
|
||||
uniform vec4 sourceSize[];
|
||||
|
||||
void main() {
|
||||
gl_Position = position;
|
||||
vTexCoord = texCoord;
|
||||
#version 150
|
||||
|
||||
in vec4 position;
|
||||
in vec2 texCoord;
|
||||
|
||||
out Vertex {
|
||||
vec2 vTexCoord;
|
||||
};
|
||||
|
||||
uniform vec4 targetSize;
|
||||
uniform vec4 sourceSize[];
|
||||
|
||||
void main() {
|
||||
gl_Position = position;
|
||||
vTexCoord = texCoord;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
input
|
||||
filter: nearest
|
||||
|
||||
program
|
||||
filter: nearest
|
||||
vertex: lottes.vs
|
||||
fragment: lottes.fs
|
||||
|
||||
output
|
||||
height: 0
|
||||
width: 0
|
||||
input
|
||||
filter: nearest
|
||||
|
||||
program
|
||||
filter: nearest
|
||||
vertex: lottes.vs
|
||||
fragment: lottes.fs
|
||||
|
||||
output
|
||||
height: 0
|
||||
width: 0
|
||||
filter: linear
|
||||
@@ -32,18 +32,18 @@ out vec4 fragColor;
|
||||
#ifdef LuminanceLUT
|
||||
#define LUT_SizeLum 16.0
|
||||
|
||||
// Code taken from RetroArch's LUT shader
|
||||
// Code taken from RetroArch's LUT shader
|
||||
float luminancelut(vec4 org)
|
||||
{
|
||||
vec4 imgColorLum = org;
|
||||
float redLum = ( imgColorLum.r * (LUT_SizeLum - 1.0) + 0.4999 ) / (LUT_SizeLum * LUT_SizeLum);
|
||||
float greenLum = ( imgColorLum.g * (LUT_SizeLum - 1.0) + 0.4999 ) / LUT_SizeLum;
|
||||
float blue1Lum = (floor( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
|
||||
float blue2Lum = (ceil( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
|
||||
float mixerLum = clamp(max((imgColorLum.b - blue1Lum) / (blue2Lum - blue1Lum), 0.0), 0.0, 32.0);
|
||||
float color1Lum = texture(pixmap[1], vec2( blue1Lum, greenLum )).x;
|
||||
float color2Lum = texture(pixmap[1], vec2( blue2Lum, greenLum )).x;
|
||||
return mix(color1Lum, color2Lum, mixerLum);
|
||||
vec4 imgColorLum = org;
|
||||
float redLum = ( imgColorLum.r * (LUT_SizeLum - 1.0) + 0.4999 ) / (LUT_SizeLum * LUT_SizeLum);
|
||||
float greenLum = ( imgColorLum.g * (LUT_SizeLum - 1.0) + 0.4999 ) / LUT_SizeLum;
|
||||
float blue1Lum = (floor( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
|
||||
float blue2Lum = (ceil( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
|
||||
float mixerLum = clamp(max((imgColorLum.b - blue1Lum) / (blue2Lum - blue1Lum), 0.0), 0.0, 32.0);
|
||||
float color1Lum = texture(pixmap[1], vec2( blue1Lum, greenLum )).x;
|
||||
float color2Lum = texture(pixmap[1], vec2( blue2Lum, greenLum )).x;
|
||||
return mix(color1Lum, color2Lum, mixerLum);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -52,48 +52,48 @@ float luminancelut(vec4 org)
|
||||
|
||||
vec4 TrinitronD50(vec4 org)
|
||||
{
|
||||
vec4 imgColorTrinitron = org;
|
||||
float redTrinitron = ( imgColorTrinitron.r * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / (LUT_SizeTrinitron * LUT_SizeTrinitron);
|
||||
float greenTrinitron = ( imgColorTrinitron.g * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / LUT_SizeTrinitron;
|
||||
float blue1Trinitron = (floor( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
|
||||
float blue2Trinitron = (ceil( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
|
||||
float mixerTrinitron = clamp(max((imgColorTrinitron.b - blue1Trinitron) / (blue2Trinitron - blue1Trinitron), 0.0), 0.0, 32.0);
|
||||
vec4 color1Trinitron = texture(pixmap[2], vec2( blue1Trinitron, greenTrinitron ));
|
||||
vec4 color2Trinitron = texture(pixmap[2], vec2( blue2Trinitron, greenTrinitron ));
|
||||
vec4 fragColorTrinitron = mix(color1Trinitron, color2Trinitron, mixerTrinitron);
|
||||
return vec4(pow(fragColorTrinitron.rgb,vec3(GammaCorrection,GammaCorrection,GammaCorrection)),1.0);
|
||||
vec4 imgColorTrinitron = org;
|
||||
float redTrinitron = ( imgColorTrinitron.r * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / (LUT_SizeTrinitron * LUT_SizeTrinitron);
|
||||
float greenTrinitron = ( imgColorTrinitron.g * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / LUT_SizeTrinitron;
|
||||
float blue1Trinitron = (floor( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
|
||||
float blue2Trinitron = (ceil( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
|
||||
float mixerTrinitron = clamp(max((imgColorTrinitron.b - blue1Trinitron) / (blue2Trinitron - blue1Trinitron), 0.0), 0.0, 32.0);
|
||||
vec4 color1Trinitron = texture(pixmap[2], vec2( blue1Trinitron, greenTrinitron ));
|
||||
vec4 color2Trinitron = texture(pixmap[2], vec2( blue2Trinitron, greenTrinitron ));
|
||||
vec4 fragColorTrinitron = mix(color1Trinitron, color2Trinitron, mixerTrinitron);
|
||||
return vec4(pow(fragColorTrinitron.rgb,vec3(GammaCorrection,GammaCorrection,GammaCorrection)),1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
|
||||
//Source Image
|
||||
vec4 org = texture(source[0], texCoord);
|
||||
vec4 org = texture(source[0], texCoord);
|
||||
|
||||
#ifdef LuminanceLUT
|
||||
// Use a 3DLUT instead of an equation so that it can use any arbitrary mess you can come up with.
|
||||
float luminance = luminancelut(org);
|
||||
float luminance = luminancelut(org);
|
||||
#elif defined LuminanceDawnbringer
|
||||
// Dawnbringer's brightness equation from Dawnbringer's Toolbox scripts for Grafx2
|
||||
float luminance = sqrt(org.r*org.r*0.0676 + org.g*org.g*0.3025 + org.b*org.b*0.0361) * 1.5690256395005606;
|
||||
float luminance = sqrt(org.r*org.r*0.0676 + org.g*org.g*0.3025 + org.b*org.b*0.0361) * 1.5690256395005606;
|
||||
#else
|
||||
// Plain, standard, fine; slightly faster
|
||||
float luminance = ((0.299*org.r) + (0.587*org.g) + (0.114*org.b));
|
||||
float luminance = ((0.299*org.r) + (0.587*org.g) + (0.114*org.b));
|
||||
#endif
|
||||
|
||||
// Don't let it exceed 1.0
|
||||
luminance = clamp(luminance, 0.0, 1.0);
|
||||
luminance = clamp(luminance, 0.0, 1.0);
|
||||
|
||||
// Scanline Mapping, based on the Phosphor LUT shader's method of tiling a texture over the screen
|
||||
vec2 LUTeffectiveCoord = vec2(luminance,fract((texCoord.y*targetSize.y)/4.0));
|
||||
vec2 LUTeffectiveCoord = vec2(luminance,fract((texCoord.y*targetSize.y)/4.0));
|
||||
|
||||
// Scanline Layer
|
||||
vec4 screen = texture(pixmap[0], LUTeffectiveCoord);
|
||||
vec4 screen = texture(pixmap[0], LUTeffectiveCoord);
|
||||
|
||||
// Output multiplying the scanlines into the original image, with control over opacity
|
||||
#ifdef TrinitronColors
|
||||
org = TrinitronD50(org);
|
||||
org = TrinitronD50(org);
|
||||
#endif
|
||||
fragColor = ((screen*ScanlinesOpacity)+(1.0 - ScanlinesOpacity)) * (org);
|
||||
fragColor = ((screen*ScanlinesOpacity)+(1.0 - ScanlinesOpacity)) * (org);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
input
|
||||
filter: nearest
|
||||
|
||||
program
|
||||
filter: nearest
|
||||
height: 100%
|
||||
fragment: pal-r57shell.fs
|
||||
|
||||
output
|
||||
height: 0
|
||||
input
|
||||
filter: nearest
|
||||
|
||||
program
|
||||
filter: nearest
|
||||
height: 100%
|
||||
fragment: pal-r57shell.fs
|
||||
|
||||
output
|
||||
height: 0
|
||||
filter: linear
|
||||
@@ -1,368 +1,368 @@
|
||||
#version 150
|
||||
|
||||
// NES PAL composite signal simulation for RetroArch
|
||||
// shader by r57shell
|
||||
// thanks to feos & HardWareMan & NewRisingSun
|
||||
|
||||
// also TV subpixels and scanlines
|
||||
|
||||
// LICENSE: PUBLIC DOMAIN
|
||||
|
||||
// NOTE: for nice TV subpixels and scanlines I recommend to
|
||||
// disable this features here and apply CRT-specialized shader.
|
||||
|
||||
// Quality considerations
|
||||
|
||||
// there are three main options:
|
||||
// USE_RAW (R), USE_DELAY_LINE (D), USE_COLORIMETRY (C)
|
||||
// here is table of quality in decreasing order:
|
||||
// RDC, RD, RC, DC, D, C
|
||||
|
||||
// compatibility macros
|
||||
#define float2 vec2
|
||||
#define float3 vec3
|
||||
#define float4 vec4
|
||||
#define frac(c) fract(c)
|
||||
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||
#define fmod(x,y) mod(x,y)
|
||||
#define mul(x,y) (y*x)
|
||||
#define float2x2 mat2
|
||||
#define float3x3 mat3
|
||||
#define float4x4 mat4
|
||||
#define bool2 bvec2
|
||||
#define bool3 bvec3
|
||||
#define bool4 bvec4
|
||||
#define static
|
||||
|
||||
uniform sampler2D source[];
|
||||
uniform vec4 sourceSize[];
|
||||
uniform vec4 outputSize;
|
||||
uniform int phase;
|
||||
|
||||
in Vertex {
|
||||
vec2 texCoord;
|
||||
};
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// TWEAKS start
|
||||
|
||||
// use delay line technique
|
||||
// without delay line technique, color would interleave
|
||||
// to avoid this, set HueRotation to zero.
|
||||
#define USE_DELAY_LINE
|
||||
|
||||
// use this if you need to swap even/odd V sign.
|
||||
// sign of V changes each scanline
|
||||
// so if some scanline is positive, then next is negative
|
||||
// and if you want to match picture
|
||||
// to actual running PAL NES on TV
|
||||
// you may want to have this option, to change signs
|
||||
// if they don't match
|
||||
//#define SWAP_VSIGN
|
||||
|
||||
// rough simulation of scanlines
|
||||
// better if you use additional shader instead
|
||||
// if you still use it, make sure that SizeY
|
||||
// is at least twice lower than output height
|
||||
#define USE_SCANLINES // FIXME: scanlines are broken and I'm too lazy to fix it right now
|
||||
|
||||
// to change gamma of virtual TV from 2.2 to something else
|
||||
#define USE_GAMMA
|
||||
|
||||
// use sampled version. it's much more slower version of shader.
|
||||
// because it is computing x4 more values. NOT RECOMMENDED.
|
||||
//#define USE_SAMPLED
|
||||
|
||||
#ifndef PARAMETER_UNIFORM
|
||||
// NTSC standard gamma = 2.2
|
||||
// PAL standard gamma = 2.8
|
||||
// according to many sources, very unlikely gamma of TV is 2.8
|
||||
// most likely gamma of PAL TV is in range 2.4-2.5
|
||||
const float Gamma_static = 2.8; // gamma of virtual TV
|
||||
|
||||
const float Brightness_static = 0.25;
|
||||
const float Contrast_static = 1.1;
|
||||
const float Saturation_static = 1.1;
|
||||
|
||||
const int
|
||||
Ywidth_static = 12,
|
||||
Uwidth_static = 23,
|
||||
Vwidth_static = 23;
|
||||
|
||||
#define Brightness Brightness_static
|
||||
#define Gamma Gamma_static
|
||||
|
||||
#define Ywidth Ywidth_static
|
||||
#define Uwidth Uwidth_static
|
||||
#define Vwidth Vwidth_static
|
||||
|
||||
#define SCANLINE_MUL (sw.x*dark_scanline+sw.y)
|
||||
|
||||
int Mwidth = int(max(float(Ywidth), max(float(Uwidth), float(Vwidth))));
|
||||
|
||||
// correct one is -2.5
|
||||
// works only with USE_RAW
|
||||
const float HueShift = -2.5;
|
||||
|
||||
// rotation of hue due to luma level.
|
||||
const float HueRotation = 2.;
|
||||
|
||||
// touch this only if you know what you doing
|
||||
const float Phase_Y = 2.; // fmod(341*10,12)
|
||||
const float Phase_One = 0.; // alternating phases.
|
||||
const float Phase_Two = 8.;
|
||||
|
||||
// screen size, scanlines = y*2; y one field, and y other field.
|
||||
const int SizeX = 256;
|
||||
const int SizeY = 240;
|
||||
|
||||
// count of pixels of virtual TV.
|
||||
// value close to 1000 produce small artifacts
|
||||
const int TV_Pixels = 400;
|
||||
|
||||
const float dark_scanline = 0.5; // half
|
||||
#endif
|
||||
|
||||
// this is using following matrixes.
|
||||
// it provides more scientific approach
|
||||
// by conversion into linear XYZ space
|
||||
// and back to sRGB.
|
||||
// it's using Gamma setting too.
|
||||
// define USE_GAMMA is not required.
|
||||
#define USE_COLORIMETRY
|
||||
|
||||
const float3x3 RGB_to_XYZ =
|
||||
mat3(
|
||||
0.4306190, 0.3415419, 0.1783091,
|
||||
0.2220379, 0.7066384, 0.0713236,
|
||||
0.0201853, 0.1295504, 0.9390944
|
||||
);
|
||||
|
||||
const float3x3 XYZ_to_sRGB =
|
||||
mat3(
|
||||
3.2406, -1.5372, -0.4986,
|
||||
-0.9689, 1.8758, 0.0415,
|
||||
0.0557, -0.2040, 1.0570
|
||||
);
|
||||
|
||||
// TWEAKS end
|
||||
|
||||
const float YUV_u = 0.492;
|
||||
const float YUV_v = 0.877;
|
||||
|
||||
const mat3 RGB_to_YUV =
|
||||
mat3(
|
||||
float3( 0.299, 0.587, 0.114), //Y
|
||||
float3(-0.299,-0.587, 0.886)*YUV_u, //B-Y
|
||||
float3( 0.701,-0.587,-0.114)*YUV_v //R-Y
|
||||
);
|
||||
|
||||
#ifdef USE_DELAY_LINE
|
||||
const float comb_line = 1.;
|
||||
#else
|
||||
const float comb_line = 2.;
|
||||
#endif
|
||||
|
||||
static const float Voltage_0 = 0.518;
|
||||
static const float Voltage_1 = 1.962;
|
||||
static const float DeltaV = (Voltage_1-Voltage_0);
|
||||
|
||||
float RGB_y = Contrast_static/Ywidth_static/DeltaV;
|
||||
float RGB_u = comb_line*Contrast_static*Saturation_static/YUV_u/Uwidth_static/DeltaV;
|
||||
float RGB_v = comb_line*Contrast_static*Saturation_static/YUV_v/Vwidth_static/DeltaV;
|
||||
|
||||
mat3 YUV_to_RGB =
|
||||
mat3(
|
||||
float3(1., 1., 1.)*RGB_y,
|
||||
float3(0., -0.114/0.587, 1.)*RGB_u,
|
||||
float3(1., -0.299/0.587, 0.)*RGB_v
|
||||
);
|
||||
|
||||
const float pi = 3.1415926535897932384626433832795;
|
||||
|
||||
float sinn(float x)
|
||||
{
|
||||
return sin(/*fmod(x,24)*/x*(pi*2./24.));
|
||||
}
|
||||
|
||||
float coss(float x)
|
||||
{
|
||||
return cos(/*fmod(x,24)*/x*(pi*2./24.));
|
||||
}
|
||||
|
||||
float3 monitor(sampler2D tex, float2 p)
|
||||
{
|
||||
float2 size = sourceSize[0].xy;//float2(SizeX,SizeY);
|
||||
// align vertical coord to center of texel
|
||||
float2 uv = float2(
|
||||
|
||||
p.x,
|
||||
|
||||
(floor(p.y*sourceSize[0].y)+0.5)/sourceSize[0].y);
|
||||
#ifdef USE_DELAY_LINE
|
||||
float2 sh = (sourceSize[0].xy/sourceSize[0].xy/size)*float2(14./10.,-1.0);
|
||||
#endif
|
||||
float2 pc = uv*sourceSize[0].xy/sourceSize[0].xy*size*float2(10.,1.);
|
||||
float alpha = dot(floor(float2(pc.x,pc.y)),float2(2.,Phase_Y*2.));
|
||||
alpha += Phase_One*2.;
|
||||
|
||||
// 1/size.x of screen in uv coords = sourceSize[0].x/sourceSize[0].x/size.x;
|
||||
// then 1/10*size.x of screen:
|
||||
float ustep = sourceSize[0].x/sourceSize[0].x/size.x/10.;
|
||||
|
||||
float border = sourceSize[0].x/sourceSize[0].x;
|
||||
float ss = 2.0;
|
||||
#ifdef SWAP_VSIGN
|
||||
#define PAL_SWITCH(A) A < 1.
|
||||
#else
|
||||
#define PAL_SWITCH(A) A > 1.
|
||||
#endif
|
||||
if (PAL_SWITCH(fmod(uv.y*sourceSize[0].y/sourceSize[0].y*size.y,2.0)))
|
||||
{
|
||||
// cos(pi-alpha) = -cos(alpha)
|
||||
// sin(pi-alpha) = sin(alpha)
|
||||
// pi - alpha
|
||||
alpha = -alpha+12012.0;
|
||||
ss = -2.0;
|
||||
}
|
||||
|
||||
float ysum = 0., usum = 0., vsum = 0.;
|
||||
for (int i=0; i<Mwidth; ++i)
|
||||
{
|
||||
float4 res = texture(tex, uv);
|
||||
float3 yuv = mul(RGB_to_YUV, res.xyz);
|
||||
float a1 = alpha+(HueShift+2.5)*2.-yuv.x*ss*HueRotation;
|
||||
float sig = yuv.x+dot(yuv.yz,sign(float2(sinn(a1),coss(a1))));
|
||||
#ifdef USE_DELAY_LINE
|
||||
float4 res1 = texture(tex, uv+sh);
|
||||
float3 yuv1 = mul(RGB_to_YUV, res1.xyz);
|
||||
float a2 = (HueShift+2.5)*2.+12012.0-alpha+yuv.x*ss*HueRotation;
|
||||
float sig1 = yuv1.x+dot(yuv1.yz,sign(float2(sinn(a2),coss(a2))));
|
||||
#endif
|
||||
if (i < Ywidth)
|
||||
ysum += sig;
|
||||
|
||||
#ifdef USE_DELAY_LINE
|
||||
if (i < Uwidth)
|
||||
usum += (sig+sig1)*sinn(alpha);
|
||||
if (i < Vwidth)
|
||||
vsum += (sig-sig1)*coss(alpha);
|
||||
#else
|
||||
if (i < Uwidth)
|
||||
usum += sig*sinn(alpha);
|
||||
if (i < Vwidth)
|
||||
vsum += sig*coss(alpha);
|
||||
#endif
|
||||
alpha -= ss;
|
||||
uv.x -= ustep;
|
||||
}
|
||||
|
||||
float3 rgb = mul(float3(ysum+Brightness*Ywidth_static,usum,vsum), YUV_to_RGB);
|
||||
#if defined(USE_GAMMA) && !defined(USE_COLORIMETRY)
|
||||
float3 rgb1 = saturate(rgb);
|
||||
rgb = pow(rgb1, Gamma/2.2);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COLORIMETRY
|
||||
float3 rgb1 = saturate(rgb);
|
||||
rgb = pow(rgb1, float3(Gamma, Gamma, Gamma));
|
||||
#endif
|
||||
|
||||
#if (defined(USE_SCANLINES))
|
||||
float2 q = (p*sourceSize[0].xy/sourceSize[0].xy)*float2(TV_Pixels*3.,size.y*2.);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCANLINES
|
||||
float scanlines = size.y * outputSize.z;
|
||||
float top = fmod(q.y-0.5*scanlines*2.,2.);
|
||||
float bottom = top+frac(scanlines)*2.;
|
||||
float2 sw = saturate(min(float2(1.,2.),float2(bottom, bottom))
|
||||
-max(float2(0.,1.),float2(top)))
|
||||
+saturate(min(float2(3.,4.),float2(bottom, bottom))
|
||||
-max(float2(2.,3.),float2(top)))
|
||||
+floor(scanlines);
|
||||
|
||||
rgb = rgb*SCANLINE_MUL/(sw.x+sw.y);
|
||||
|
||||
/*
|
||||
//old stupid method
|
||||
float z =
|
||||
#ifdef ANIMATE_SCANLINE
|
||||
fmod(phase,2.0)+
|
||||
#endif
|
||||
0.5;
|
||||
|
||||
if (abs(fmod(q.y+0.5,2)-z)<0.5)
|
||||
rgb *= dark_scanline;
|
||||
*/
|
||||
#endif
|
||||
|
||||
// size of pixel screen in texture coords:
|
||||
//float output_pixel_size = sourceSize[0].x/(outputSize.x*sourceSize[0].x);
|
||||
|
||||
// correctness check
|
||||
//if (fmod(p.x*output_pixel_size,2.0) < 1.0)
|
||||
// rgb = float3(0.,0.,0.);
|
||||
|
||||
#ifdef USE_COLORIMETRY
|
||||
float3 xyz1 = mul(RGB_to_XYZ,rgb);
|
||||
float3 srgb = saturate(mul(XYZ_to_sRGB,xyz1));
|
||||
float3 a1 = 12.92*srgb;
|
||||
float3 a2 = 1.055*pow(srgb,float3(1./2.4))-0.055;
|
||||
float3 ssrgb;
|
||||
ssrgb.x = (srgb.x<0.0031308?a1.x:a2.x);
|
||||
ssrgb.y = (srgb.y<0.0031308?a1.y:a2.y);
|
||||
ssrgb.z = (srgb.z<0.0031308?a1.z:a2.z);
|
||||
return ssrgb;
|
||||
#else
|
||||
return rgb;
|
||||
#endif
|
||||
}
|
||||
|
||||
// pos (left corner, sample size)
|
||||
float4 monitor_sample(sampler2D tex, float2 p, float2 sample_)
|
||||
{
|
||||
// linear interpolation was...
|
||||
// now other thing.
|
||||
// http://imgur.com/m8Z8trV
|
||||
// AT LAST IT WORKS!!!!
|
||||
// going to check in retroarch...
|
||||
float2 size = sourceSize[0].xy;
|
||||
float2 next = float2(.25,1.)/size;
|
||||
float2 f = frac(float2(4.,1.)*size*p);
|
||||
sample_ *= float2(4.,1.)*size;
|
||||
float2 l;
|
||||
float2 r;
|
||||
if (f.x+sample_.x < 1.)
|
||||
{
|
||||
l.x = f.x+sample_.x;
|
||||
r.x = 0.;
|
||||
}
|
||||
else
|
||||
{
|
||||
l.x = 1.-f.x;
|
||||
r.x = min(1.,f.x+sample_.x-1.);
|
||||
}
|
||||
if (f.y+sample_.y < 1.)
|
||||
{
|
||||
l.y = f.y+sample_.y;
|
||||
r.y = 0.;
|
||||
}
|
||||
else
|
||||
{
|
||||
l.y = 1.-f.y;
|
||||
r.y = min(1.,f.y+sample_.y-1.);
|
||||
}
|
||||
float3 top = mix(monitor(tex, p), monitor(tex, p+float2(next.x,0.)), r.x/(l.x+r.x));
|
||||
float3 bottom = mix(monitor(tex, p+float2(0.,next.y)), monitor(tex, p+next), r.x/(l.x+r.x));
|
||||
return float4(mix(top,bottom, r.y/(l.y+r.y)),1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
#ifdef USE_SAMPLED
|
||||
fragColor = vec4(monitor_sample(source[0], texCoord, outputSize.zw).rgb, 1.0);
|
||||
#else
|
||||
fragColor = float4(monitor(source[0], texCoord), 1.);
|
||||
#endif
|
||||
#version 150
|
||||
|
||||
// NES PAL composite signal simulation for RetroArch
|
||||
// shader by r57shell
|
||||
// thanks to feos & HardWareMan & NewRisingSun
|
||||
|
||||
// also TV subpixels and scanlines
|
||||
|
||||
// LICENSE: PUBLIC DOMAIN
|
||||
|
||||
// NOTE: for nice TV subpixels and scanlines I recommend to
|
||||
// disable this features here and apply CRT-specialized shader.
|
||||
|
||||
// Quality considerations
|
||||
|
||||
// there are three main options:
|
||||
// USE_RAW (R), USE_DELAY_LINE (D), USE_COLORIMETRY (C)
|
||||
// here is table of quality in decreasing order:
|
||||
// RDC, RD, RC, DC, D, C
|
||||
|
||||
// compatibility macros
|
||||
#define float2 vec2
|
||||
#define float3 vec3
|
||||
#define float4 vec4
|
||||
#define frac(c) fract(c)
|
||||
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||
#define fmod(x,y) mod(x,y)
|
||||
#define mul(x,y) (y*x)
|
||||
#define float2x2 mat2
|
||||
#define float3x3 mat3
|
||||
#define float4x4 mat4
|
||||
#define bool2 bvec2
|
||||
#define bool3 bvec3
|
||||
#define bool4 bvec4
|
||||
#define static
|
||||
|
||||
uniform sampler2D source[];
|
||||
uniform vec4 sourceSize[];
|
||||
uniform vec4 outputSize;
|
||||
uniform int phase;
|
||||
|
||||
in Vertex {
|
||||
vec2 texCoord;
|
||||
};
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// TWEAKS start
|
||||
|
||||
// use delay line technique
|
||||
// without delay line technique, color would interleave
|
||||
// to avoid this, set HueRotation to zero.
|
||||
#define USE_DELAY_LINE
|
||||
|
||||
// use this if you need to swap even/odd V sign.
|
||||
// sign of V changes each scanline
|
||||
// so if some scanline is positive, then next is negative
|
||||
// and if you want to match picture
|
||||
// to actual running PAL NES on TV
|
||||
// you may want to have this option, to change signs
|
||||
// if they don't match
|
||||
//#define SWAP_VSIGN
|
||||
|
||||
// rough simulation of scanlines
|
||||
// better if you use additional shader instead
|
||||
// if you still use it, make sure that SizeY
|
||||
// is at least twice lower than output height
|
||||
#define USE_SCANLINES // FIXME: scanlines are broken and I'm too lazy to fix it right now
|
||||
|
||||
// to change gamma of virtual TV from 2.2 to something else
|
||||
#define USE_GAMMA
|
||||
|
||||
// use sampled version. it's much more slower version of shader.
|
||||
// because it is computing x4 more values. NOT RECOMMENDED.
|
||||
//#define USE_SAMPLED
|
||||
|
||||
#ifndef PARAMETER_UNIFORM
|
||||
// NTSC standard gamma = 2.2
|
||||
// PAL standard gamma = 2.8
|
||||
// according to many sources, very unlikely gamma of TV is 2.8
|
||||
// most likely gamma of PAL TV is in range 2.4-2.5
|
||||
const float Gamma_static = 2.8; // gamma of virtual TV
|
||||
|
||||
const float Brightness_static = 0.25;
|
||||
const float Contrast_static = 1.1;
|
||||
const float Saturation_static = 1.1;
|
||||
|
||||
const int
|
||||
Ywidth_static = 12,
|
||||
Uwidth_static = 23,
|
||||
Vwidth_static = 23;
|
||||
|
||||
#define Brightness Brightness_static
|
||||
#define Gamma Gamma_static
|
||||
|
||||
#define Ywidth Ywidth_static
|
||||
#define Uwidth Uwidth_static
|
||||
#define Vwidth Vwidth_static
|
||||
|
||||
#define SCANLINE_MUL (sw.x*dark_scanline+sw.y)
|
||||
|
||||
int Mwidth = int(max(float(Ywidth), max(float(Uwidth), float(Vwidth))));
|
||||
|
||||
// correct one is -2.5
|
||||
// works only with USE_RAW
|
||||
const float HueShift = -2.5;
|
||||
|
||||
// rotation of hue due to luma level.
|
||||
const float HueRotation = 2.;
|
||||
|
||||
// touch this only if you know what you doing
|
||||
const float Phase_Y = 2.; // fmod(341*10,12)
|
||||
const float Phase_One = 0.; // alternating phases.
|
||||
const float Phase_Two = 8.;
|
||||
|
||||
// screen size, scanlines = y*2; y one field, and y other field.
|
||||
const int SizeX = 256;
|
||||
const int SizeY = 240;
|
||||
|
||||
// count of pixels of virtual TV.
|
||||
// value close to 1000 produce small artifacts
|
||||
const int TV_Pixels = 400;
|
||||
|
||||
const float dark_scanline = 0.5; // half
|
||||
#endif
|
||||
|
||||
// this is using following matrixes.
|
||||
// it provides more scientific approach
|
||||
// by conversion into linear XYZ space
|
||||
// and back to sRGB.
|
||||
// it's using Gamma setting too.
|
||||
// define USE_GAMMA is not required.
|
||||
#define USE_COLORIMETRY
|
||||
|
||||
const float3x3 RGB_to_XYZ =
|
||||
mat3(
|
||||
0.4306190, 0.3415419, 0.1783091,
|
||||
0.2220379, 0.7066384, 0.0713236,
|
||||
0.0201853, 0.1295504, 0.9390944
|
||||
);
|
||||
|
||||
const float3x3 XYZ_to_sRGB =
|
||||
mat3(
|
||||
3.2406, -1.5372, -0.4986,
|
||||
-0.9689, 1.8758, 0.0415,
|
||||
0.0557, -0.2040, 1.0570
|
||||
);
|
||||
|
||||
// TWEAKS end
|
||||
|
||||
const float YUV_u = 0.492;
|
||||
const float YUV_v = 0.877;
|
||||
|
||||
const mat3 RGB_to_YUV =
|
||||
mat3(
|
||||
float3( 0.299, 0.587, 0.114), //Y
|
||||
float3(-0.299,-0.587, 0.886)*YUV_u, //B-Y
|
||||
float3( 0.701,-0.587,-0.114)*YUV_v //R-Y
|
||||
);
|
||||
|
||||
#ifdef USE_DELAY_LINE
|
||||
const float comb_line = 1.;
|
||||
#else
|
||||
const float comb_line = 2.;
|
||||
#endif
|
||||
|
||||
static const float Voltage_0 = 0.518;
|
||||
static const float Voltage_1 = 1.962;
|
||||
static const float DeltaV = (Voltage_1-Voltage_0);
|
||||
|
||||
float RGB_y = Contrast_static/Ywidth_static/DeltaV;
|
||||
float RGB_u = comb_line*Contrast_static*Saturation_static/YUV_u/Uwidth_static/DeltaV;
|
||||
float RGB_v = comb_line*Contrast_static*Saturation_static/YUV_v/Vwidth_static/DeltaV;
|
||||
|
||||
mat3 YUV_to_RGB =
|
||||
mat3(
|
||||
float3(1., 1., 1.)*RGB_y,
|
||||
float3(0., -0.114/0.587, 1.)*RGB_u,
|
||||
float3(1., -0.299/0.587, 0.)*RGB_v
|
||||
);
|
||||
|
||||
const float pi = 3.1415926535897932384626433832795;
|
||||
|
||||
float sinn(float x)
|
||||
{
|
||||
return sin(/*fmod(x,24)*/x*(pi*2./24.));
|
||||
}
|
||||
|
||||
float coss(float x)
|
||||
{
|
||||
return cos(/*fmod(x,24)*/x*(pi*2./24.));
|
||||
}
|
||||
|
||||
float3 monitor(sampler2D tex, float2 p)
|
||||
{
|
||||
float2 size = sourceSize[0].xy;//float2(SizeX,SizeY);
|
||||
// align vertical coord to center of texel
|
||||
float2 uv = float2(
|
||||
|
||||
p.x,
|
||||
|
||||
(floor(p.y*sourceSize[0].y)+0.5)/sourceSize[0].y);
|
||||
#ifdef USE_DELAY_LINE
|
||||
float2 sh = (sourceSize[0].xy/sourceSize[0].xy/size)*float2(14./10.,-1.0);
|
||||
#endif
|
||||
float2 pc = uv*sourceSize[0].xy/sourceSize[0].xy*size*float2(10.,1.);
|
||||
float alpha = dot(floor(float2(pc.x,pc.y)),float2(2.,Phase_Y*2.));
|
||||
alpha += Phase_One*2.;
|
||||
|
||||
// 1/size.x of screen in uv coords = sourceSize[0].x/sourceSize[0].x/size.x;
|
||||
// then 1/10*size.x of screen:
|
||||
float ustep = sourceSize[0].x/sourceSize[0].x/size.x/10.;
|
||||
|
||||
float border = sourceSize[0].x/sourceSize[0].x;
|
||||
float ss = 2.0;
|
||||
#ifdef SWAP_VSIGN
|
||||
#define PAL_SWITCH(A) A < 1.
|
||||
#else
|
||||
#define PAL_SWITCH(A) A > 1.
|
||||
#endif
|
||||
if (PAL_SWITCH(fmod(uv.y*sourceSize[0].y/sourceSize[0].y*size.y,2.0)))
|
||||
{
|
||||
// cos(pi-alpha) = -cos(alpha)
|
||||
// sin(pi-alpha) = sin(alpha)
|
||||
// pi - alpha
|
||||
alpha = -alpha+12012.0;
|
||||
ss = -2.0;
|
||||
}
|
||||
|
||||
float ysum = 0., usum = 0., vsum = 0.;
|
||||
for (int i=0; i<Mwidth; ++i)
|
||||
{
|
||||
float4 res = texture(tex, uv);
|
||||
float3 yuv = mul(RGB_to_YUV, res.xyz);
|
||||
float a1 = alpha+(HueShift+2.5)*2.-yuv.x*ss*HueRotation;
|
||||
float sig = yuv.x+dot(yuv.yz,sign(float2(sinn(a1),coss(a1))));
|
||||
#ifdef USE_DELAY_LINE
|
||||
float4 res1 = texture(tex, uv+sh);
|
||||
float3 yuv1 = mul(RGB_to_YUV, res1.xyz);
|
||||
float a2 = (HueShift+2.5)*2.+12012.0-alpha+yuv.x*ss*HueRotation;
|
||||
float sig1 = yuv1.x+dot(yuv1.yz,sign(float2(sinn(a2),coss(a2))));
|
||||
#endif
|
||||
if (i < Ywidth)
|
||||
ysum += sig;
|
||||
|
||||
#ifdef USE_DELAY_LINE
|
||||
if (i < Uwidth)
|
||||
usum += (sig+sig1)*sinn(alpha);
|
||||
if (i < Vwidth)
|
||||
vsum += (sig-sig1)*coss(alpha);
|
||||
#else
|
||||
if (i < Uwidth)
|
||||
usum += sig*sinn(alpha);
|
||||
if (i < Vwidth)
|
||||
vsum += sig*coss(alpha);
|
||||
#endif
|
||||
alpha -= ss;
|
||||
uv.x -= ustep;
|
||||
}
|
||||
|
||||
float3 rgb = mul(float3(ysum+Brightness*Ywidth_static,usum,vsum), YUV_to_RGB);
|
||||
#if defined(USE_GAMMA) && !defined(USE_COLORIMETRY)
|
||||
float3 rgb1 = saturate(rgb);
|
||||
rgb = pow(rgb1, Gamma/2.2);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COLORIMETRY
|
||||
float3 rgb1 = saturate(rgb);
|
||||
rgb = pow(rgb1, float3(Gamma, Gamma, Gamma));
|
||||
#endif
|
||||
|
||||
#if (defined(USE_SCANLINES))
|
||||
float2 q = (p*sourceSize[0].xy/sourceSize[0].xy)*float2(TV_Pixels*3.,size.y*2.);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCANLINES
|
||||
float scanlines = size.y * outputSize.z;
|
||||
float top = fmod(q.y-0.5*scanlines*2.,2.);
|
||||
float bottom = top+frac(scanlines)*2.;
|
||||
float2 sw = saturate(min(float2(1.,2.),float2(bottom, bottom))
|
||||
-max(float2(0.,1.),float2(top)))
|
||||
+saturate(min(float2(3.,4.),float2(bottom, bottom))
|
||||
-max(float2(2.,3.),float2(top)))
|
||||
+floor(scanlines);
|
||||
|
||||
rgb = rgb*SCANLINE_MUL/(sw.x+sw.y);
|
||||
|
||||
/*
|
||||
//old stupid method
|
||||
float z =
|
||||
#ifdef ANIMATE_SCANLINE
|
||||
fmod(phase,2.0)+
|
||||
#endif
|
||||
0.5;
|
||||
|
||||
if (abs(fmod(q.y+0.5,2)-z)<0.5)
|
||||
rgb *= dark_scanline;
|
||||
*/
|
||||
#endif
|
||||
|
||||
// size of pixel screen in texture coords:
|
||||
//float output_pixel_size = sourceSize[0].x/(outputSize.x*sourceSize[0].x);
|
||||
|
||||
// correctness check
|
||||
//if (fmod(p.x*output_pixel_size,2.0) < 1.0)
|
||||
// rgb = float3(0.,0.,0.);
|
||||
|
||||
#ifdef USE_COLORIMETRY
|
||||
float3 xyz1 = mul(RGB_to_XYZ,rgb);
|
||||
float3 srgb = saturate(mul(XYZ_to_sRGB,xyz1));
|
||||
float3 a1 = 12.92*srgb;
|
||||
float3 a2 = 1.055*pow(srgb,float3(1./2.4))-0.055;
|
||||
float3 ssrgb;
|
||||
ssrgb.x = (srgb.x<0.0031308?a1.x:a2.x);
|
||||
ssrgb.y = (srgb.y<0.0031308?a1.y:a2.y);
|
||||
ssrgb.z = (srgb.z<0.0031308?a1.z:a2.z);
|
||||
return ssrgb;
|
||||
#else
|
||||
return rgb;
|
||||
#endif
|
||||
}
|
||||
|
||||
// pos (left corner, sample size)
|
||||
float4 monitor_sample(sampler2D tex, float2 p, float2 sample_)
|
||||
{
|
||||
// linear interpolation was...
|
||||
// now other thing.
|
||||
// http://imgur.com/m8Z8trV
|
||||
// AT LAST IT WORKS!!!!
|
||||
// going to check in retroarch...
|
||||
float2 size = sourceSize[0].xy;
|
||||
float2 next = float2(.25,1.)/size;
|
||||
float2 f = frac(float2(4.,1.)*size*p);
|
||||
sample_ *= float2(4.,1.)*size;
|
||||
float2 l;
|
||||
float2 r;
|
||||
if (f.x+sample_.x < 1.)
|
||||
{
|
||||
l.x = f.x+sample_.x;
|
||||
r.x = 0.;
|
||||
}
|
||||
else
|
||||
{
|
||||
l.x = 1.-f.x;
|
||||
r.x = min(1.,f.x+sample_.x-1.);
|
||||
}
|
||||
if (f.y+sample_.y < 1.)
|
||||
{
|
||||
l.y = f.y+sample_.y;
|
||||
r.y = 0.;
|
||||
}
|
||||
else
|
||||
{
|
||||
l.y = 1.-f.y;
|
||||
r.y = min(1.,f.y+sample_.y-1.);
|
||||
}
|
||||
float3 top = mix(monitor(tex, p), monitor(tex, p+float2(next.x,0.)), r.x/(l.x+r.x));
|
||||
float3 bottom = mix(monitor(tex, p+float2(0.,next.y)), monitor(tex, p+next), r.x/(l.x+r.x));
|
||||
return float4(mix(top,bottom, r.y/(l.y+r.y)),1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
#ifdef USE_SAMPLED
|
||||
fragColor = vec4(monitor_sample(source[0], texCoord, outputSize.zw).rgb, 1.0);
|
||||
#else
|
||||
fragColor = float4(monitor(source[0], texCoord), 1.);
|
||||
#endif
|
||||
}
|
||||
@@ -10,6 +10,7 @@ auto ControllerPort::load(Node::Object parent) -> void {
|
||||
port->setType("Controller");
|
||||
port->setHotSwappable(true);
|
||||
port->setAllocate([&](auto name) { return allocate(name); });
|
||||
port->setDisconnect([&] { device.reset(); });
|
||||
port->setSupported({"Gamepad"});
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,10 @@ auto RIOT::step(u32 clocks) -> void {
|
||||
auto RIOT::power(bool reset) -> void {
|
||||
Thread::create(system.frequency() / 3, {&RIOT::main, this});
|
||||
timer = {};
|
||||
port[0] = {.data = 0xff};
|
||||
port[1] = {.data = 0xff};
|
||||
port[0] = {};
|
||||
port[0].data = 0xff;
|
||||
port[1] = {};
|
||||
port[1].data = 0xff;
|
||||
leftDifficulty = 1;
|
||||
rightDifficulty = 1;
|
||||
tvType = 1;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
static const string SerializerVersion = "v131";
|
||||
|
||||
auto System::serialize(bool synchronize) -> serializer {
|
||||
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
||||
serializer s;
|
||||
|
||||
@@ -20,7 +20,7 @@ struct System {
|
||||
|
||||
auto name() const -> string { return information.name; }
|
||||
auto region() const -> Region { return information.region; }
|
||||
auto frequency() const -> u32 { return information.frequency; }
|
||||
auto frequency() const -> f64 { return information.frequency; }
|
||||
|
||||
//system.cpp
|
||||
auto game() -> string;
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
struct Information {
|
||||
string name = "Atari 2600";
|
||||
Region region = Region::NTSC;
|
||||
u32 frequency = Constants::Colorburst::NTSC;
|
||||
f64 frequency = Constants::Colorburst::NTSC;
|
||||
} information;
|
||||
|
||||
//serialization.cpp
|
||||
|
||||
@@ -73,7 +73,6 @@ auto TIA::write(n8 address, n8 data) -> void {
|
||||
|
||||
auto TIA::vsync(n1 state) -> void {
|
||||
if(io.vsync && !state) {
|
||||
io.vcounter = 0;
|
||||
frame();
|
||||
}
|
||||
|
||||
|
||||
+20
-6
@@ -15,10 +15,10 @@ auto TIA::load(Node::Object parent) -> void {
|
||||
|
||||
screen = node->append<Node::Video::Screen>("Screen", 160, vlines());
|
||||
screen->colors(1 << 7, {&TIA::color, this});
|
||||
screen->setSize(160, vlines());
|
||||
screen->setScale(2.0, 1.0);
|
||||
screen->setAspect(1.0, 1.0);
|
||||
screen->setViewport(0, 0, 160, vlines());
|
||||
screen->setSize(160, displayHeight());
|
||||
screen->setScale(1.0, 1.0);
|
||||
screen->setAspect(12.0, 7.0);
|
||||
screen->setViewport(0, 0, 160, displayHeight());
|
||||
|
||||
stream = node->append<Node::Audio::Stream>("Audio");
|
||||
stream->setChannels(1);
|
||||
@@ -44,11 +44,17 @@ auto TIA::scanline() -> void {
|
||||
cpu.rdyLine(1);
|
||||
for(io.hcounter = 0; io.hcounter < 228; io.hcounter++) {
|
||||
auto x = io.hcounter - 68;
|
||||
if(x >= 0) pixel(x);
|
||||
if(x >= 0 && io.vcounter < vlines()) pixel(x);
|
||||
writeQueue.step();
|
||||
runAudio();
|
||||
step();
|
||||
}
|
||||
|
||||
// Prevent an infinite emulator hang when games miss vblank
|
||||
if(io.vcounter > vlines()) {
|
||||
scheduler.exit(Event::Frame);
|
||||
io.vcounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto TIA::pixel(n8 x) -> void {
|
||||
@@ -144,6 +150,14 @@ auto TIA::runBall(n8 x) -> n1 {
|
||||
}
|
||||
|
||||
auto TIA::frame() -> void {
|
||||
auto height = io.vcounter;
|
||||
|
||||
if(height <= 0) {
|
||||
debug(unusual, "invalid screen height");
|
||||
height = vlines();
|
||||
}
|
||||
|
||||
screen->setViewport(0, 0, 160, height);
|
||||
screen->frame();
|
||||
scheduler.exit(Event::Frame);
|
||||
}
|
||||
@@ -163,7 +177,7 @@ auto TIA::power(bool reset) -> void {
|
||||
ball = {};
|
||||
collision = {};
|
||||
for(auto n : range(writeQueue.maxItems)) writeQueue.items[n] = {};
|
||||
|
||||
audio[0] = {}; audio[1] = {};
|
||||
for(u32 level : range(15)) {
|
||||
volume[level] = pow(2, level * -2.0 / 6.0);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ struct TIA : Thread {
|
||||
Node::Audio::Stream stream;
|
||||
|
||||
auto vlines() const -> u32 { return Region::NTSC() ? 262 : 312; }
|
||||
auto displayHeight() const -> u32 { return Region::NTSC() ? 192 : 228; }
|
||||
|
||||
//tia.cpp
|
||||
auto load(Node::Object) -> void;
|
||||
|
||||
@@ -23,7 +23,7 @@ auto TIA::WriteQueue::step() -> void {
|
||||
|
||||
auto TIA::WriteQueue::QueueItem::commit() -> void {
|
||||
switch(address) {
|
||||
case 0x01: tia.io.vblank = data.bit(1); return; // VBLANK
|
||||
case 0x01: tia.io.vblank = data.bit(1); if(tia.io.vblank == 0) { tia.io.vcounter = 0; } return; // VBLANK
|
||||
case 0x0b: tia.player[0].reflect = data.bit(3); return; // REFP0
|
||||
case 0x0c: tia.player[1].reflect = data.bit(3); return; // REFP1
|
||||
case 0x0d: tia.playfield.graphics.bit(0, 3) = data.bit(4, 7); return; // PF0
|
||||
|
||||
+4
-2
@@ -8,10 +8,12 @@
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/bump-allocator.hpp>
|
||||
#include <nall/case-range.hpp>
|
||||
#include <nall/chrono.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/hashset.hpp>
|
||||
#include <nall/image.hpp>
|
||||
#include <nall/literals.hpp>
|
||||
#include <nall/priority-queue.hpp>
|
||||
@@ -35,10 +37,11 @@
|
||||
#include <nall/hash/crc32.hpp>
|
||||
#include <nall/hash/sha256.hpp>
|
||||
using namespace nall;
|
||||
using namespace nall::primitives;
|
||||
|
||||
namespace ares {
|
||||
static const string Name = "ares";
|
||||
static const string Version = "129";
|
||||
static const string Version = "133";
|
||||
static const string Copyright = "ares team, Near";
|
||||
static const string License = "ISC";
|
||||
static const string LicenseURI = "https://opensource.org/licenses/ISC";
|
||||
@@ -47,7 +50,6 @@ namespace ares {
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
|
||||
static const string SerializerVersion = "129";
|
||||
|
||||
namespace VFS {
|
||||
using Pak = shared_pointer<vfs::directory>;
|
||||
|
||||
@@ -4,19 +4,19 @@ struct Debug {
|
||||
auto reset() -> void;
|
||||
|
||||
template<typename... P> auto unhandled(P&&... p) -> void {
|
||||
return _unhandled({forward<P>(p)...});
|
||||
return _unhandled({std::forward<P>(p)...});
|
||||
}
|
||||
|
||||
template<typename... P> auto unimplemented(P&&... p) -> void {
|
||||
return _unimplemented({forward<P>(p)...});
|
||||
return _unimplemented({std::forward<P>(p)...});
|
||||
}
|
||||
|
||||
template<typename... P> auto unusual(P&&... p) -> void {
|
||||
return _unusual({forward<P>(p)...});
|
||||
return _unusual({std::forward<P>(p)...});
|
||||
}
|
||||
|
||||
template<typename... P> auto unverified(P&&... p) -> void {
|
||||
return _unverified({forward<P>(p)...});
|
||||
return _unverified({std::forward<P>(p)...});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
#if defined(PLATFORM_MACOS) && defined(ARCHITECTURE_ARM64)
|
||||
#if defined(PLATFORM_MACOS)
|
||||
//stub for unsupported platforms
|
||||
FixedAllocator::FixedAllocator() {
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
struct FixedAllocator {
|
||||
static auto get() -> bump_allocator&;
|
||||
|
||||
private:
|
||||
FixedAllocator();
|
||||
|
||||
bump_allocator _allocator;
|
||||
};
|
||||
|
||||
}
|
||||
#pragma once
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
struct FixedAllocator {
|
||||
static auto get() -> bump_allocator&;
|
||||
|
||||
private:
|
||||
FixedAllocator();
|
||||
|
||||
bump_allocator _allocator;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ struct Stream : Audio {
|
||||
template<typename... P>
|
||||
auto frame(P&&... p) -> void {
|
||||
if(runAhead()) return;
|
||||
f64 samples[sizeof...(p)] = {forward<P>(p)...};
|
||||
f64 samples[sizeof...(p)] = {f64(std::forward<P>(p))...};
|
||||
write(samples);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,14 @@ struct Instruction : Tracer {
|
||||
|
||||
auto setMask(bool mask) -> void {
|
||||
_mask = mask;
|
||||
_masks.reset();
|
||||
}
|
||||
|
||||
auto setDepth(u32 depth) -> void {
|
||||
_depth = depth;
|
||||
_history.reset();
|
||||
_history.resize(depth);
|
||||
for(auto& history : _history) history = ~0;
|
||||
for(auto& history : _history) history = ~0ull;
|
||||
}
|
||||
|
||||
auto address(u64 address) -> bool {
|
||||
@@ -32,9 +33,10 @@ struct Instruction : Tracer {
|
||||
_address = address;
|
||||
address >>= _addressMask; //clip unneeded alignment bits (to reduce _masks size)
|
||||
|
||||
if(_mask && updateMasks()) {
|
||||
if(_masks[address >> 3] & 1 << (address & 7)) return false; //do not trace twice
|
||||
_masks[address >> 3] |= 1 << (address & 7);
|
||||
if(_mask) {
|
||||
auto mask = _masks.find(address);
|
||||
if(!mask) mask = _masks.insert(address);
|
||||
if(mask->visit(address)) return false; //do not trace twice
|
||||
}
|
||||
|
||||
if(_depth) {
|
||||
@@ -56,10 +58,12 @@ struct Instruction : Tracer {
|
||||
//mark an already-executed address as not executed yet for trace masking.
|
||||
//call when writing to executable RAM to support self-modifying code.
|
||||
auto invalidate(u64 address) -> void {
|
||||
if(unlikely(_mask && updateMasks())) {
|
||||
if(unlikely(_mask)) {
|
||||
address &= ~0ull >> (64 - _addressBits);
|
||||
address >>= _addressMask;
|
||||
_masks[address >> 3] &= ~(1 << (address & 7));
|
||||
|
||||
auto mask = _masks.find(address);
|
||||
if(mask) mask->unvisit(address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,14 +107,27 @@ struct Instruction : Tracer {
|
||||
}
|
||||
|
||||
protected:
|
||||
auto updateMasks() -> bool {
|
||||
auto size = 1ull << (_addressBits - _addressMask - 3);
|
||||
if(!_mask || !size) return _masks.reset(), false;
|
||||
if(_masks.size() == size) return true;
|
||||
_masks.reset();
|
||||
_masks.resize(size);
|
||||
return true;
|
||||
}
|
||||
struct VisitMask {
|
||||
VisitMask(u64 address) : upper(address >> 6), mask(0) {}
|
||||
auto operator==(const VisitMask& source) const -> bool { return upper == source.upper; }
|
||||
auto hash() const -> u32 { return upper; }
|
||||
|
||||
auto visit(u64 address) -> bool {
|
||||
const u64 bit = 1ull << (address & 0x3f);
|
||||
if(mask & bit) return true;
|
||||
mask |= bit;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto unvisit(u64 address) -> void {
|
||||
const u64 bit = 1ull << (address & 0x3f);
|
||||
mask &= ~bit;
|
||||
}
|
||||
|
||||
private:
|
||||
u64 upper;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
u32 _addressBits = 32;
|
||||
u32 _addressMask = 0;
|
||||
@@ -120,6 +137,6 @@ protected:
|
||||
//unserialized:
|
||||
n64 _address = 0;
|
||||
n64 _omitted = 0;
|
||||
vector<u32> _history;
|
||||
vector<u08> _masks;
|
||||
vector<u64> _history;
|
||||
hashset<VisitMask> _masks;
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
struct Input : Object {
|
||||
DeclareClass(Input, "input")
|
||||
using Object::Object;
|
||||
u64 lastPoll;
|
||||
};
|
||||
@@ -33,7 +33,7 @@ struct Object : shared_pointer_this<Object> {
|
||||
template<typename T, typename... P>
|
||||
auto prepend(P&&... p) -> Node::Object {
|
||||
using Type = typename T::type;
|
||||
return prepend(shared_pointer<Type>::create(forward<P>(p)...));
|
||||
return prepend(shared_pointer<Type>::create(std::forward<P>(p)...));
|
||||
}
|
||||
|
||||
auto append(Node::Object node) -> Node::Object {
|
||||
@@ -47,7 +47,7 @@ struct Object : shared_pointer_this<Object> {
|
||||
template<typename T, typename... P>
|
||||
auto append(P&&... p) -> Node::Object {
|
||||
using Type = typename T::type;
|
||||
return append(shared_pointer<Type>::create(forward<P>(p)...));
|
||||
return append(shared_pointer<Type>::create(std::forward<P>(p)...));
|
||||
}
|
||||
|
||||
auto remove(Node::Object node) -> void {
|
||||
|
||||
@@ -82,10 +82,10 @@ protected:
|
||||
u32 _rotation = 0; //counter-clockwise (90 = left, 270 = right)
|
||||
|
||||
function<n64 (n32)> _color;
|
||||
unique_pointer<u32> _inputA;
|
||||
unique_pointer<u32> _inputB;
|
||||
unique_pointer<u32> _output;
|
||||
unique_pointer<u32> _rotate;
|
||||
unique_pointer<u32[]> _inputA;
|
||||
unique_pointer<u32[]> _inputB;
|
||||
unique_pointer<u32[]> _output;
|
||||
unique_pointer<u32[]> _rotate;
|
||||
unique_pointer<u32[]> _palette;
|
||||
vector<Node::Video::Sprite> _sprites;
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ inline auto Thread::synchronize(Thread& thread, P&&... p) -> void {
|
||||
co_switch(thread.handle());
|
||||
}
|
||||
//convenience: allow synchronizing multiple threads with one function call.
|
||||
if constexpr(sizeof...(p) > 0) synchronize(forward<P>(p)...);
|
||||
if constexpr(sizeof...(p) > 0) synchronize(std::forward<P>(p)...);
|
||||
}
|
||||
|
||||
inline auto Thread::serialize(serializer& s) -> void {
|
||||
|
||||
@@ -196,9 +196,11 @@ auto AY38910::write(n8 data) -> void {
|
||||
envelope.output = !envelope.attacking ? 15 : 0;
|
||||
break;
|
||||
case 14:
|
||||
portA.data = data;
|
||||
writeIO(0, data);
|
||||
break;
|
||||
case 15:
|
||||
portB.data = data;
|
||||
writeIO(1, data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,17 +20,17 @@ auto SN76489::clock() -> array<n4[4]> {
|
||||
}
|
||||
|
||||
auto SN76489::Tone::clock() -> void {
|
||||
if(!counter--) {
|
||||
if(!counter || !--counter) {
|
||||
counter = pitch;
|
||||
output ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto SN76489::Noise::clock() -> void {
|
||||
if(!counter--) {
|
||||
if(!counter || !--counter) {
|
||||
counter = array<n10[4]>{0x10, 0x20, 0x40, pitch}[rate];
|
||||
if(flip ^= 1) { //0->1 transition
|
||||
output = !lfsr.bit(0);
|
||||
output = lfsr.bit(0);
|
||||
lfsr = (lfsr.bit(0) ^ lfsr.bit(3) & enable) << 15 | lfsr >> 1;
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,10 @@ auto SN76489::write(n8 data) -> void {
|
||||
case 0: tone0.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
case 1: tone1.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
case 2: tone2.pitch.bit(4,9) = data.bit(0,5); noise.pitch = tone2.pitch; break;
|
||||
case 3: noise.rate = data.bit(0,1);
|
||||
noise.enable = data.bit(2);
|
||||
noise.lfsr = 0x8000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,106 @@
|
||||
auto YM2610::read(n2 address) -> n8 {
|
||||
switch(address) {
|
||||
case 0: return fm.readStatus();
|
||||
case 1: return ssg.read();
|
||||
case 2: return pcmStatus();
|
||||
}
|
||||
|
||||
debug(unimplemented, "[YM2610] read ", hex(address));
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto YM2610::pcmStatus() -> n8 {
|
||||
n8 output;
|
||||
for(auto c : range(6)) output.bit(c) = pcmA.channels[c].ended;
|
||||
output.bit(7) = pcmB.ended;
|
||||
return output;
|
||||
}
|
||||
|
||||
auto YM2610::write(n2 address, n8 data) -> void {
|
||||
switch(address) {
|
||||
case 0: register = 0x000 | data; return;
|
||||
case 0: {
|
||||
registerAddress = 0x000 | data;
|
||||
if (registerAddress <= 0xf) ssg.select(registerAddress);
|
||||
else fm.writeAddress(registerAddress);
|
||||
return;
|
||||
}
|
||||
case 1: return writeLower(data);
|
||||
case 2: register = 0x100 | data; return;
|
||||
case 2: registerAddress = 0x100 | data; fm.writeAddress(registerAddress); return;
|
||||
case 3: return writeUpper(data);
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2610::writeLower(n8 data) -> void {
|
||||
switch(register) {
|
||||
case 0x000 ... 0x00f:
|
||||
ssg.select(register);
|
||||
ssg.write(data);
|
||||
return;
|
||||
case 0x010 ... 0x01b:
|
||||
//ADPCM-B
|
||||
switch(registerAddress) {
|
||||
case range16(0x000, 0x00f):
|
||||
ssg.write(data);
|
||||
return;
|
||||
case 0x010:
|
||||
pcmB.repeat = data.bit(4);
|
||||
if(data.bit(0)) pcmB.power();
|
||||
if(data.bit(7)) pcmB.beginPlay();
|
||||
else pcmB.playing = 0;
|
||||
return;
|
||||
case 0x011: pcmB.left = data.bit(7);
|
||||
pcmB.right = data.bit(6); return;
|
||||
case 0x012: pcmB.startAddress.bit( 8, 15) = data; return;
|
||||
case 0x013: pcmB.startAddress.bit(16, 23) = data; return;
|
||||
case 0x014: pcmB.endAddress.bit ( 8, 15) = data; return;
|
||||
case 0x015: pcmB.endAddress.bit (16, 23) = data; return;
|
||||
case range3(0x016, 0x018):
|
||||
debug(unimplemented, "[YM2610::ADPCMB] Write ", hex(registerAddress), " = ", data);
|
||||
return;
|
||||
case 0x019: pcmB.delta.bit ( 0, 7) = data; return;
|
||||
case 0x01a: pcmB.delta.bit ( 8, 15) = data; return;
|
||||
case 0x01b: pcmB.volume = data; return;
|
||||
case 0x01c:
|
||||
//EOS
|
||||
return;
|
||||
case 0x01d ... 0x1ff:
|
||||
fm.writeAddress(register);
|
||||
fm.writeData(data);
|
||||
for(auto c : range(6)) {
|
||||
pcmA.channels[c].endedMask = data.bit(c);
|
||||
if(data.bit(c)) pcmA.channels[c].ended = 0;
|
||||
}
|
||||
pcmB.endedMask = data.bit(7);
|
||||
if(data.bit(7)) pcmB.ended = 0;
|
||||
return;
|
||||
default:
|
||||
if(registerAddress >= 0x01d && registerAddress <= 0x1ff) {
|
||||
fm.writeData(data);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
unreachable;
|
||||
|
||||
debug(unimplemented, "[YM2610] Write ", hex(registerAddress), " = ", data);
|
||||
}
|
||||
|
||||
auto YM2610::writeUpper(n8 data) -> void {
|
||||
switch(register) {
|
||||
case 0x000 ... 0x12f:
|
||||
//ADPCM-A
|
||||
return;
|
||||
case 0x130 ... 0x1ff:
|
||||
fm.writeAddress(register);
|
||||
fm.writeData(data);
|
||||
switch(registerAddress) {
|
||||
case 0x100:
|
||||
for(auto n : range(6)) {
|
||||
if(!data.bit(n)) continue;
|
||||
if(data.bit(7)) {
|
||||
pcmA.channels[n].keyOff();
|
||||
continue;
|
||||
}
|
||||
|
||||
pcmA.channels[n].keyOn();
|
||||
}
|
||||
return;
|
||||
case 0x101: pcmA.volume = data.bit(0, 5); return;
|
||||
case range6(0x108, 0x10d): pcmA.channels[registerAddress - 0x108].volume = data.bit(0,4);
|
||||
pcmA.channels[registerAddress - 0x108].left = data.bit(7);
|
||||
pcmA.channels[registerAddress - 0x108].right = data.bit(6); return;
|
||||
case range6(0x110, 0x115): pcmA.channels[registerAddress - 0x110].startAddress.bit( 8, 15) = data; return;
|
||||
case range6(0x118, 0x11d): pcmA.channels[registerAddress - 0x118].startAddress.bit(16, 23) = data; return;
|
||||
case range6(0x120, 0x125): pcmA.channels[registerAddress - 0x120].endAddress.bit ( 8, 15) = data; return;
|
||||
case range6(0x128, 0x12d): pcmA.channels[registerAddress - 0x128].endAddress.bit (16, 23) = data; return;
|
||||
default:
|
||||
if(registerAddress >= 0x130 && registerAddress <= 0x1ff) {
|
||||
fm.writeAddress(registerAddress);
|
||||
fm.writeData(data);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
debug(unimplemented, "[YM2610] Write ", hex(registerAddress), " = ", data);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
auto YM2610::PCMA::power() -> void {
|
||||
for(auto c : range(6)) {
|
||||
channels[c].startAddress.bit(0, 7) = 0x00;
|
||||
channels[c].endAddress.bit(0, 7) = 0x00;
|
||||
channels[c].decodeAccumulator = 0;
|
||||
channels[c].decodeStep = 0;
|
||||
}
|
||||
|
||||
i16 stepSize[] = {
|
||||
16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
|
||||
41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
|
||||
107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
|
||||
279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
|
||||
};
|
||||
|
||||
// Generate a decode table
|
||||
for (int step = 0; step < 49; step++) {
|
||||
for (int nibble = 0; nibble < 16; nibble++) {
|
||||
int value = (2 * (nibble & 0x07) + 1) * stepSize[step] / 8;
|
||||
decodeTable[step * 16 + nibble] = ((nibble & 0x08) != 0) ? -value : value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2610::PCMA::clock() -> array<i16[2]> {
|
||||
f32 left = 0;
|
||||
f32 right = 0;
|
||||
|
||||
for(auto c : range(6)) {
|
||||
if(!channels[c].playing) continue;
|
||||
if(((channels[c].currentAddress ^ (channels[c].endAddress + (1 << 8))) & 0xfffff) == 0) {
|
||||
channels[c].playing = 0;
|
||||
if(!channels[c].endedMask) channels[c].ended = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto sample = channels[c].decode(self.readPCMA(channels[c].currentAddress));
|
||||
|
||||
int totalVolume = (volume ^ 0x3f) + (channels[c].volume ^ 0x1f);
|
||||
int volumeMultiplier = 15 - (totalVolume & 7);
|
||||
int volumeShift = 5 + (totalVolume >> 3);
|
||||
|
||||
sample = ((sample * volumeMultiplier) >> volumeShift) & ~3;
|
||||
|
||||
if(channels[c].left) left += sample / 2047.0f;
|
||||
if(channels[c].right) right += sample / 2047.0f;
|
||||
}
|
||||
|
||||
return {sclamp<16>(left * 32768.0), sclamp<16>(right * 32768.0)};
|
||||
}
|
||||
|
||||
auto YM2610::PCMA::Channel::keyOn() -> void {
|
||||
if(ended) return;
|
||||
playing = 1;
|
||||
currentAddress = startAddress;
|
||||
decodeAccumulator = 0;
|
||||
decodeStep = 0;
|
||||
currentNibble = 0;
|
||||
}
|
||||
|
||||
auto YM2610::PCMA::Channel::keyOff() -> void {
|
||||
playing = 0;
|
||||
}
|
||||
|
||||
auto YM2610::PCMA::Channel::decode(n8 value) -> i12 {
|
||||
int stepAdjust[] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 };
|
||||
|
||||
value = currentNibble ? value.bit(0, 3) : value.bit(4, 7);
|
||||
if(currentNibble) currentAddress++;
|
||||
currentNibble = !currentNibble;
|
||||
|
||||
decodeAccumulator += self.decodeTable[decodeStep + value];
|
||||
|
||||
decodeStep += stepAdjust[value & 7] * 16;
|
||||
decodeStep = std::clamp((int)decodeStep, 0, 48 * 16);
|
||||
|
||||
return decodeAccumulator;
|
||||
}
|
||||
|
||||
auto YM2610::PCMB::power() -> void {
|
||||
currentNibble = 0;
|
||||
currentAddress = 0;
|
||||
decodeAccumulator = 0;
|
||||
previousAccumulator = 0;
|
||||
decodePosition = 0;
|
||||
decodeStep = 127;
|
||||
volume = 255;
|
||||
}
|
||||
|
||||
auto YM2610::PCMB::clock() -> array<i16[2]> {
|
||||
f32 leftSample = 0;
|
||||
f32 rightSample = 0;
|
||||
|
||||
decode();
|
||||
|
||||
i32 sample = (previousAccumulator * (i32)((decodePosition ^ 0xffff) + 1) + decodeAccumulator * (i32)(decodePosition)) >> 16;
|
||||
sample = (sample * (i32)volume) >> 9;
|
||||
|
||||
if(left) leftSample += (sample / 65535.0);
|
||||
if(right) rightSample += (sample / 65535.0);
|
||||
|
||||
return {sclamp<16>(leftSample * 32768.0), sclamp<16>(rightSample * 32768.0)};
|
||||
}
|
||||
|
||||
auto YM2610::PCMB::decode() -> void {
|
||||
if(!playing) {
|
||||
return;
|
||||
}
|
||||
|
||||
u8 stepSize[8] = { 57, 57, 57, 57, 77, 102, 128, 153 };
|
||||
|
||||
u32 position = decodePosition + delta;
|
||||
decodePosition = (u16)position;
|
||||
if(position < 0x10000) return;
|
||||
|
||||
n8 value = self.readPCMB(currentAddress);
|
||||
value = currentNibble ? value.bit(0, 3) : value.bit(4, 7);
|
||||
currentNibble = !currentNibble;
|
||||
|
||||
if(currentNibble == 0) {
|
||||
currentAddress++;
|
||||
if(currentAddress == endAddress) {
|
||||
if(repeat) beginPlay();
|
||||
else {
|
||||
decodeAccumulator = 0;
|
||||
previousAccumulator = 0;
|
||||
playing = 0;
|
||||
if(!endedMask) ended = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousAccumulator = decodeAccumulator;
|
||||
|
||||
i32 _delta = (value.bit(0, 2) * 2 + 1) * decodeStep / 8;
|
||||
if(value.bit(3)) _delta = -_delta;
|
||||
|
||||
decodeAccumulator = sclamp<16>(decodeAccumulator + _delta);
|
||||
|
||||
decodeStep = std::clamp(((int)decodeStep * stepSize[value.bit(0, 2)]) / 64, 127, 24576);
|
||||
}
|
||||
|
||||
auto YM2610::PCMB::beginPlay() -> void {
|
||||
if(ended) return;
|
||||
currentAddress = startAddress;
|
||||
currentNibble = 0;
|
||||
decodeAccumulator = 0;
|
||||
previousAccumulator = 0;
|
||||
decodePosition = 0;
|
||||
decodeStep = 127;
|
||||
playing = 1;
|
||||
}
|
||||
@@ -1,5 +1,44 @@
|
||||
auto YM2610::serialize(serializer& s) -> void {
|
||||
s(register);
|
||||
s(registerAddress);
|
||||
s(fm);
|
||||
s(ssg);
|
||||
s(pcmA);
|
||||
s(pcmB);
|
||||
}
|
||||
|
||||
auto YM2610::PCMA::serialize(serializer& s) -> void {
|
||||
for(auto n : range(6)) {
|
||||
s(channels[n].playing);
|
||||
s(channels[n].ended);
|
||||
s(channels[n].endedMask);
|
||||
s(channels[n].left);
|
||||
s(channels[n].right);
|
||||
s(channels[n].volume);
|
||||
s(channels[n].startAddress);
|
||||
s(channels[n].endAddress);
|
||||
s(channels[n].currentAddress);
|
||||
s(channels[n].decodeAccumulator);
|
||||
s(channels[n].decodeStep);
|
||||
s(channels[n].currentNibble);
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2610::PCMB::serialize(serializer& s) -> void {
|
||||
s(playing);
|
||||
s(ended);
|
||||
s(endedMask);
|
||||
s(repeat);
|
||||
s(left);
|
||||
s(right);
|
||||
s(startAddress);
|
||||
s(endAddress);
|
||||
s(delta);
|
||||
s(volume);
|
||||
|
||||
s(currentAddress);
|
||||
s(currentNibble);
|
||||
s(decodeAccumulator);
|
||||
s(decodePosition);
|
||||
s(previousAccumulator);
|
||||
s(decodeStep);
|
||||
}
|
||||
@@ -4,11 +4,14 @@
|
||||
namespace ares {
|
||||
|
||||
#include "io.cpp"
|
||||
#include "pcm.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto YM2610::power() -> void {
|
||||
fm.power();
|
||||
ssg.power();
|
||||
pcmA.power();
|
||||
pcmB.power();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,14 +16,82 @@ struct YM2610 {
|
||||
auto write(n2 address, n8 data) -> void;
|
||||
auto writeLower(n8 data) -> void;
|
||||
auto writeUpper(n8 data) -> void;
|
||||
auto pcmStatus() -> n8;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
virtual auto readPCMA(u32 address) -> u8 { return 0; }
|
||||
virtual auto readPCMB(u32 address) -> u8 { return 0; }
|
||||
|
||||
protected:
|
||||
n9 register;
|
||||
n9 registerAddress;
|
||||
YM2612 fm;
|
||||
YM2149 ssg;
|
||||
|
||||
struct PCMA {
|
||||
YM2610& self;
|
||||
|
||||
// pcm.cpp
|
||||
auto power() -> void;
|
||||
auto clock() -> array<i16[2]>;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Channel {
|
||||
PCMA& self;
|
||||
auto keyOn() -> void;
|
||||
auto keyOff() -> void;
|
||||
auto decode(n8) -> i12;
|
||||
n1 playing;
|
||||
n1 ended;
|
||||
n1 endedMask;
|
||||
n1 left;
|
||||
n1 right;
|
||||
n5 volume;
|
||||
n32 startAddress;
|
||||
n32 endAddress;
|
||||
n32 currentAddress;
|
||||
i12 decodeAccumulator;
|
||||
i32 decodeStep;
|
||||
bool currentNibble;
|
||||
} channels[6]{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}};
|
||||
|
||||
n6 volume;
|
||||
int decodeTable[16 * 49];
|
||||
} pcmA{*this};
|
||||
|
||||
struct PCMB {
|
||||
YM2610& self;
|
||||
|
||||
// pcm.cpp
|
||||
auto power() -> void;
|
||||
auto clock() -> array<i16[2]>;
|
||||
auto decode() -> void;
|
||||
auto beginPlay() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
n1 playing;
|
||||
n1 ended;
|
||||
n1 endedMask;
|
||||
n1 repeat;
|
||||
n1 left;
|
||||
n2 right;
|
||||
n32 startAddress;
|
||||
n32 endAddress;
|
||||
n16 delta;
|
||||
n8 volume;
|
||||
|
||||
n32 currentAddress;
|
||||
bool currentNibble;
|
||||
i32 decodeAccumulator;
|
||||
u32 decodePosition;
|
||||
i32 previousAccumulator;
|
||||
i32 decodeStep;
|
||||
} pcmB{*this};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
auto YM2612::Channel::Operator::trigger(bool state) -> void {
|
||||
auto YM2612::Channel::Operator::updateKeyState(bool state) -> void {
|
||||
if(keyOn == state) return; //no change
|
||||
|
||||
keyOn = state;
|
||||
envelope.state = Release;
|
||||
updateEnvelope();
|
||||
|
||||
if(keyOn) {
|
||||
//restart phase and envelope generators
|
||||
@@ -13,42 +10,46 @@ auto YM2612::Channel::Operator::trigger(bool state) -> void {
|
||||
updateEnvelope();
|
||||
|
||||
if(envelope.rate >= 62) {
|
||||
//skip attack and possibly decay stages
|
||||
//skip attack phase
|
||||
envelope.value = 0;
|
||||
envelope.state = envelope.sustainLevel ? Decay : Sustain;
|
||||
updateEnvelope();
|
||||
}
|
||||
} else if(ssg.enable && ssg.attack != ssg.invert) {
|
||||
//SSG-EG key-off
|
||||
envelope.value = 0x200 - envelope.value;
|
||||
} else {
|
||||
envelope.state = Release;
|
||||
updateEnvelope();
|
||||
|
||||
if(ssg.enable && ssg.attack != ssg.invert) {
|
||||
//SSG-EG key-off
|
||||
envelope.value = 0x200 - envelope.value;
|
||||
}
|
||||
}
|
||||
|
||||
updateLevel();
|
||||
}
|
||||
|
||||
auto YM2612::Channel::Operator::runEnvelope() -> void {
|
||||
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x3f0;
|
||||
updateKeyState(keyLine);
|
||||
if(ym2612.envelope.clock & (1 << envelope.divider) - 1) return;
|
||||
|
||||
u32 value = ym2612.envelope.clock >> envelope.divider;
|
||||
u32 step = envelope.steps >> ((~value & 7) << 2) & 0xf;
|
||||
if(ssg.enable) step <<= 2; //SSG results in a 4x faster envelope
|
||||
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x1f << 5;
|
||||
|
||||
if(envelope.state == Attack) {
|
||||
u32 next = envelope.value + (~u16(envelope.value) * step >> 4) & 0x3ff;
|
||||
if(next <= envelope.value) {
|
||||
envelope.value = next;
|
||||
} else {
|
||||
envelope.value = 0;
|
||||
envelope.state = envelope.value < sustain ? Decay : Sustain;
|
||||
if(envelope.value == 0) {
|
||||
envelope.state = Decay;
|
||||
updateEnvelope();
|
||||
} else if(envelope.rate < 62) {
|
||||
// will stop updating if attack rate is increased to upper threshold during attack phase (confirmed behavior)
|
||||
envelope.value += ~u16(envelope.value) * step >> 4;
|
||||
}
|
||||
} else if(!ssg.enable || envelope.value < 0x200) {
|
||||
envelope.value = min(envelope.value + step, 0x3ff);
|
||||
}
|
||||
if(envelope.state != Attack) {
|
||||
if(envelope.state == Decay && envelope.value >= sustain) {
|
||||
envelope.state = Sustain;
|
||||
updateEnvelope();
|
||||
}
|
||||
if(ssg.enable) step = envelope.value < 0x200 ? step << 2 : 0; //SSG results in a 4x faster envelope
|
||||
envelope.value = min(envelope.value + step, 0x3ff);
|
||||
}
|
||||
|
||||
updateLevel();
|
||||
@@ -59,18 +60,19 @@ auto YM2612::Channel::Operator::runPhase() -> void {
|
||||
if(!(ssg.enable && envelope.value >= 0x200)) return; //SSG loop check
|
||||
|
||||
if(!ssg.hold && !ssg.alternate) phase.value = 0;
|
||||
if(!ssg.hold || ssg.attack == ssg.invert) ssg.invert ^= ssg.alternate;
|
||||
if(!(ssg.hold && ssg.invert)) ssg.invert ^= ssg.alternate;
|
||||
|
||||
if(envelope.state == Attack) {
|
||||
//do nothing; SSG is meant to skip the attack phase
|
||||
} else if(envelope.state != Release && !ssg.hold) {
|
||||
//if still looping, reset the envelope
|
||||
envelope.state = Attack;
|
||||
if(envelope.attackRate >= 62) {
|
||||
envelope.value = 0;
|
||||
envelope.state = envelope.sustainLevel ? Decay : Sustain;
|
||||
}
|
||||
updateEnvelope();
|
||||
|
||||
if(envelope.rate >= 62) {
|
||||
//skip attack phase
|
||||
envelope.value = 0;
|
||||
}
|
||||
} else if(envelope.state == Release || (ssg.hold && ssg.attack == ssg.invert)) {
|
||||
//clear envelope once finished
|
||||
envelope.value = 0x3ff;
|
||||
@@ -115,11 +117,9 @@ auto YM2612::Channel::Operator::updatePhase() -> void {
|
||||
u32 tuning = detune & 3 ? detunes[(detune & 3) - 1][ksr & 7] >> (3 - (ksr >> 3)) : 0;
|
||||
|
||||
u32 lfo = ym2612.lfo.clock >> 2 & 0x1f;
|
||||
u32 pm = 4 * vibratos[channel.vibrato][lfo & 15] * (-lfo >> 4);
|
||||
u32 msb = 10;
|
||||
while(msb > 4 && ~pitch.value & 1 << msb) msb--;
|
||||
s32 pm = (pitch.value * vibratos[channel.vibrato][lfo & 15] >> 9) * (lfo > 15 ? -1 : 1);
|
||||
|
||||
phase.delta = pitch.value + (pm >> 10 - msb) << 6 >> 7 - octave.value;
|
||||
phase.delta = pitch.value + pm << 6 >> 7 - octave.value;
|
||||
phase.delta = (!detune.bit(2) ? phase.delta + tuning : phase.delta - tuning) & 0x1ffff;
|
||||
phase.delta = (multiple ? phase.delta * multiple : phase.delta >> 1) & 0xfffff;
|
||||
}
|
||||
@@ -147,6 +147,7 @@ auto YM2612::Channel::power() -> void {
|
||||
|
||||
for(auto& op : operators) {
|
||||
op.keyOn = 0;
|
||||
op.keyLine = 0;
|
||||
op.lfoEnable = 0;
|
||||
op.detune = 0;
|
||||
op.multiple = 0;
|
||||
@@ -155,6 +156,7 @@ auto YM2612::Channel::power() -> void {
|
||||
op.outputLevel = 0x1fff;
|
||||
op.output = 0;
|
||||
op.prior = 0;
|
||||
op.priorBuffer = 0;
|
||||
|
||||
op.pitch.value = 0;
|
||||
op.pitch.reload = 0;
|
||||
|
||||
@@ -14,6 +14,8 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
case 0x022: {
|
||||
lfo.rate = data.bit(0,2);
|
||||
lfo.enable = data.bit(3);
|
||||
lfo.clock = 0;
|
||||
lfo.divider = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -37,11 +39,12 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
|
||||
//timer control
|
||||
case 0x027: {
|
||||
//d6,d7 = mode (unimplemented; treated as mode 0 always)
|
||||
|
||||
//reload period on 0->1 transition
|
||||
if(!timerA.enable && data.bit(0)) timerA.counter = timerA.period;
|
||||
if(!timerB.enable && data.bit(1)) timerB.counter = timerB.period;
|
||||
if(!timerB.enable && data.bit(1)) {
|
||||
timerB.counter = timerB.period;
|
||||
timerB.divider = 0;
|
||||
}
|
||||
|
||||
timerA.enable = data.bit(0);
|
||||
timerB.enable = data.bit(1);
|
||||
@@ -51,6 +54,7 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
if(data.bit(4)) timerA.line = 0;
|
||||
if(data.bit(5)) timerB.line = 0;
|
||||
|
||||
//d7 is enable bit for CSM mode (not yet implemented)
|
||||
channels[2].mode = data.bit(6,7);
|
||||
for(auto& op : channels[2].operators) op.updatePitch();
|
||||
|
||||
@@ -64,10 +68,10 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
if(index == 3 || index == 7) break;
|
||||
if(index >= 4) index--;
|
||||
|
||||
channels[index][0].trigger(data.bit(4));
|
||||
channels[index][1].trigger(data.bit(5));
|
||||
channels[index][2].trigger(data.bit(6));
|
||||
channels[index][3].trigger(data.bit(7));
|
||||
channels[index][0].keyLine = data.bit(4);
|
||||
channels[index][1].keyLine = data.bit(5);
|
||||
channels[index][2].keyLine = data.bit(6);
|
||||
channels[index][3].keyLine = data.bit(7);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -145,10 +149,11 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
|
||||
//SSG-EG
|
||||
case 0x090: {
|
||||
op.ssg.hold = data.bit(0);
|
||||
op.ssg.alternate = data.bit(1);
|
||||
op.ssg.attack = data.bit(2);
|
||||
op.ssg.enable = data.bit(3);
|
||||
op.ssg.hold = op.ssg.enable ? data.bit(0) : 0;
|
||||
op.ssg.alternate = op.ssg.enable ? data.bit(1) : 0;
|
||||
op.ssg.attack = op.ssg.enable ? data.bit(2) : 0;
|
||||
channel[index].updateLevel();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ auto YM2612::Channel::serialize(serializer& s) -> void {
|
||||
|
||||
auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
|
||||
s(keyOn);
|
||||
s(keyLine);
|
||||
s(lfoEnable);
|
||||
s(detune);
|
||||
s(multiple);
|
||||
@@ -49,6 +50,7 @@ auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
|
||||
s(outputLevel);
|
||||
s(output);
|
||||
s(prior);
|
||||
s(priorBuffer);
|
||||
|
||||
s(pitch.value);
|
||||
s(pitch.reload);
|
||||
|
||||
@@ -27,16 +27,20 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
auto wave = [&](u32 n, u32 modulation) -> s32 {
|
||||
s32 x = (modulation >> 1) + (op[n].phase.value >> 10);
|
||||
s32 y = sine[x & 0x3ff] + op[n].outputLevel;
|
||||
return y < 0x2000 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0;
|
||||
return y < 0x1a00 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0; // -78 dB floor
|
||||
};
|
||||
|
||||
s32 feedback = modMask & op[0].output + op[0].prior >> 9 - channel.feedback;
|
||||
s32 feedback = modMask & op[0].prior + op[0].priorBuffer >> 9 - channel.feedback;
|
||||
s32 accumulator = 0;
|
||||
|
||||
op[0].priorBuffer = op[0].prior; // only need to buffer the output for feedback
|
||||
for(auto n : range(4)) op[n].prior = op[n].output;
|
||||
|
||||
op[0].output = wave(0, feedback * (channel.feedback > 0));
|
||||
|
||||
// Note: Despite not emulating per cycle, operator pipelining has been accounted for.
|
||||
// Given the op order 0-2-1-3, newly generated output is not available for the following op.
|
||||
|
||||
if(channel.algorithm == 0) {
|
||||
//0 -> 1 -> 2 -> 3
|
||||
op[1].output = wave(1, mod(0));
|
||||
@@ -48,7 +52,7 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
if(channel.algorithm == 1) {
|
||||
//(0 + 1) -> 2 -> 3
|
||||
op[1].output = wave(1, 0);
|
||||
op[2].output = wave(2, mod(0) + old(1));
|
||||
op[2].output = wave(2, old(0) + old(1));
|
||||
op[3].output = wave(3, mod(2));
|
||||
accumulator += out(3);
|
||||
}
|
||||
@@ -65,7 +69,7 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
//(0 -> 1) + 2 -> 3
|
||||
op[1].output = wave(1, mod(0));
|
||||
op[2].output = wave(2, 0);
|
||||
op[3].output = wave(3, mod(1) + mod(2));
|
||||
op[3].output = wave(3, old(1) + mod(2));
|
||||
accumulator += out(3);
|
||||
}
|
||||
|
||||
@@ -104,8 +108,18 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
s32 voiceData = sclamp<14>(accumulator) & outMask;
|
||||
if(dac.enable && (&channel == &channels[5])) voiceData = (s32)dac.sample - 0x80 << 6;
|
||||
|
||||
if(channel.leftEnable ) left += voiceData;
|
||||
if(channel.rightEnable) right += voiceData;
|
||||
// DAC output + voltage offset (crossover distortion)
|
||||
if(voiceData < 0) {
|
||||
left += channel.leftEnable * (voiceData + (1<<5)) - (4<<5);
|
||||
right += channel.rightEnable * (voiceData + (1<<5)) - (4<<5);
|
||||
} else {
|
||||
left += channel.leftEnable * (voiceData + (0<<5)) + (4<<5);
|
||||
right += channel.rightEnable * (voiceData + (0<<5)) + (4<<5);
|
||||
}
|
||||
|
||||
// DAC output (ym3438 fix)
|
||||
//if(channel.leftEnable ) left += voiceData;
|
||||
//if(channel.rightEnable) right += voiceData;
|
||||
}
|
||||
|
||||
timerA.run();
|
||||
@@ -124,7 +138,7 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
|
||||
if(++envelope.divider == 3) {
|
||||
envelope.divider = 0;
|
||||
envelope.clock++;
|
||||
if(!++envelope.clock) ++envelope.clock; // 12-bit counter: 1..4095 - zero-value is skipped (confirmed behavior)
|
||||
}
|
||||
|
||||
for(auto& channel : channels) {
|
||||
|
||||
@@ -36,7 +36,7 @@ protected:
|
||||
} dac;
|
||||
|
||||
struct Envelope {
|
||||
n32 clock = 0;
|
||||
n12 clock = 0;
|
||||
n32 divider = 0;
|
||||
} envelope;
|
||||
|
||||
@@ -91,7 +91,7 @@ protected:
|
||||
Operator(Channel& channel) : channel(channel), ym2612(channel.ym2612) {}
|
||||
|
||||
//channel.cpp
|
||||
auto trigger(bool) -> void;
|
||||
auto updateKeyState(bool) -> void;
|
||||
|
||||
auto runEnvelope() -> void;
|
||||
auto runPhase() -> void;
|
||||
@@ -105,6 +105,7 @@ protected:
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
n1 keyOn = 0;
|
||||
n1 keyLine = 0;
|
||||
n1 lfoEnable = 0;
|
||||
n3 detune = 0;
|
||||
n4 multiple = 0;
|
||||
@@ -113,6 +114,7 @@ protected:
|
||||
n16 outputLevel = 0x1fff;
|
||||
i16 output = 0;
|
||||
i16 prior = 0;
|
||||
i16 priorBuffer = 0;
|
||||
|
||||
struct Pitch {
|
||||
n11 value = 0;
|
||||
|
||||
@@ -30,20 +30,6 @@ auto GSU::disassembleOpcode(char* output) -> void {
|
||||
while(length++ < 20) strcat(output, " ");
|
||||
}
|
||||
|
||||
#define case4(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3
|
||||
#define case6(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5
|
||||
#define case12(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
|
||||
case id+ 8: case id+ 9: case id+10: case id+11
|
||||
#define case15(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
|
||||
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14
|
||||
#define case16(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
|
||||
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
|
||||
|
||||
#define op0 regs.pipeline
|
||||
#define op1 read((regs.pbr << 16) + regs.r[15] + 0)
|
||||
#define op2 read((regs.pbr << 16) + regs.r[15] + 1)
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
auto HuC6280::algorithmADC(n8 i) -> n8 {
|
||||
i16 o;
|
||||
i16 o = A + i + C;
|
||||
if(!D) {
|
||||
o = A + i + C;
|
||||
C = o.bit(8);
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
} else {
|
||||
idle();
|
||||
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
|
||||
if(o > 0x09) o += 0x06;
|
||||
C = o > 0x0f;
|
||||
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
|
||||
n8 l = (A & 0x0f) + (i & 0x0f) + C;
|
||||
if(l > 0x09) o += 0x06;
|
||||
if(o > 0x9f) o += 0x60;
|
||||
C = o > 0xff;
|
||||
}
|
||||
C = o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
@@ -125,19 +123,17 @@ auto HuC6280::algorithmROR(n8 i) -> n8 {
|
||||
|
||||
auto HuC6280::algorithmSBC(n8 i) -> n8 {
|
||||
i ^= 0xff;
|
||||
i16 o;
|
||||
i16 o = A + i + C;
|
||||
if(!D) {
|
||||
o = A + i + C;
|
||||
C = o.bit(8);
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
} else {
|
||||
idle();
|
||||
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
|
||||
if(o <= 0x0f) o -= 0x06;
|
||||
C = o > 0x0f;
|
||||
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
|
||||
n8 l = (A & 0x0f) + (i & 0x0f) + C;
|
||||
C = o > 0xff;
|
||||
if(o <= 0xff) o -= 0x60;
|
||||
if(l <= 0x0f) o -= 0x06;
|
||||
}
|
||||
C = o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,19 +1,32 @@
|
||||
auto MOS6502::algorithmADC(n8 i) -> n8 {
|
||||
i16 o;
|
||||
i16 o = A + i + C;
|
||||
if(!BCD || !D) {
|
||||
o = A + i + C;
|
||||
C = o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
N = o.bit(7);
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
} else {
|
||||
idle();
|
||||
Z = n8(o) == 0;
|
||||
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
|
||||
if(o > 0x09) o += 0x06;
|
||||
C = o > 0x0f;
|
||||
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
|
||||
N = o.bit(7);
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
if(o > 0x9f) o += 0x60;
|
||||
C = o > 0xff;
|
||||
}
|
||||
C = o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmALR(n8 i) -> n8 {
|
||||
n8 o = A & i;
|
||||
C = o.bit(0);
|
||||
o >>= 1;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -24,6 +37,29 @@ auto MOS6502::algorithmAND(n8 i) -> n8 {
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmANC(n8 i) -> n8 {
|
||||
n8 o = A & i;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
C = N;
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmARR(n8 i) -> n8 {
|
||||
n8 o = A & i;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
|
||||
bool c = C;
|
||||
o = c << 7 | o >> 1;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
C = o.bit(6);
|
||||
V = o.bit(6) ^ o.bit(5);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmASL(n8 i) -> n8 {
|
||||
C = i.bit(7);
|
||||
i <<= 1;
|
||||
@@ -32,6 +68,23 @@ auto MOS6502::algorithmASL(n8 i) -> n8 {
|
||||
return i;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmATX(n8 i) -> n8 {
|
||||
A |= 0xff; //TODO: OR value may differ on non-NES platforms
|
||||
n8 o = A & i;
|
||||
X = o;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmAXS(n8 i) -> n8 {
|
||||
n9 o = (A & X) - i;
|
||||
C = !o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmBIT(n8 i) -> n8 {
|
||||
Z = (A & i) == 0;
|
||||
V = i.bit(6);
|
||||
@@ -125,20 +178,35 @@ auto MOS6502::algorithmROR(n8 i) -> n8 {
|
||||
|
||||
auto MOS6502::algorithmSBC(n8 i) -> n8 {
|
||||
i = ~i;
|
||||
i16 o;
|
||||
i16 o = A + i + C;
|
||||
if(!BCD || !D) {
|
||||
o = A + i + C;
|
||||
C = o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
N = o.bit(7);
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
} else {
|
||||
idle();
|
||||
Z = n8(o) == 0;
|
||||
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
|
||||
if(o <= 0x0f) o -= 0x06;
|
||||
C = o > 0x0f;
|
||||
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
|
||||
N = o.bit(7);
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
if(o <= 0xff) o -= 0x60;
|
||||
C = o > 0xff;
|
||||
}
|
||||
C = o.bit(8);
|
||||
Z = n8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmSLO(n8 i) -> n8 {
|
||||
C = i.bit(7);
|
||||
i <<= 1;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
|
||||
A |= i;
|
||||
Z = A == 0;
|
||||
N = A.bit(7);
|
||||
return i;
|
||||
}
|
||||
@@ -23,23 +23,29 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x04, NoOperationZeroPage)
|
||||
op(0x05, ZeroPageRead, fp(ORA), A)
|
||||
op(0x06, ZeroPageModify, fp(ASL))
|
||||
op(0x07, ZeroPageModify, fp(SLO))
|
||||
op(0x08, PushP)
|
||||
op(0x09, Immediate, fp(ORA), A)
|
||||
op(0x0a, Implied, fp(ASL), A)
|
||||
op(0x0b, Immediate, fp(ANC), A)
|
||||
op(0x0c, NoOperationAbsolute)
|
||||
op(0x0d, AbsoluteRead, fp(ORA), A)
|
||||
op(0x0e, AbsoluteModify, fp(ASL))
|
||||
op(0x0f, AbsoluteModify, fp(SLO))
|
||||
op(0x10, Branch, N == 0)
|
||||
op(0x11, IndirectYRead, fp(ORA), A)
|
||||
op(0x14, NoOperationZeroPage, X)
|
||||
op(0x15, ZeroPageRead, fp(ORA), A, X)
|
||||
op(0x16, ZeroPageModify, fp(ASL), X)
|
||||
op(0x17, ZeroPageModify, fp(SLO), X)
|
||||
op(0x18, Clear, C)
|
||||
op(0x19, AbsoluteRead, fp(ORA), A, Y)
|
||||
op(0x1a, NoOperation)
|
||||
op(0x1b, AbsoluteModify, fp(SLO), Y)
|
||||
op(0x1c, NoOperationAbsolute, X)
|
||||
op(0x1d, AbsoluteRead, fp(ORA), A, X)
|
||||
op(0x1e, AbsoluteModify, fp(ASL), X)
|
||||
op(0x1f, AbsoluteModify, fp(SLO), X)
|
||||
op(0x20, CallAbsolute)
|
||||
op(0x21, IndirectXRead, fp(AND), A)
|
||||
op(0x24, ZeroPageRead, fp(BIT), A)
|
||||
@@ -48,6 +54,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x28, PullP)
|
||||
op(0x29, Immediate, fp(AND), A)
|
||||
op(0x2a, Implied, fp(ROL), A)
|
||||
op(0x2b, Immediate, fp(ANC), A)
|
||||
op(0x2c, AbsoluteRead, fp(BIT), A)
|
||||
op(0x2d, AbsoluteRead, fp(AND), A)
|
||||
op(0x2e, AbsoluteModify, fp(ROL))
|
||||
@@ -70,6 +77,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x48, Push, A)
|
||||
op(0x49, Immediate, fp(EOR), A)
|
||||
op(0x4a, Implied, fp(LSR), A)
|
||||
op(0x4b, Immediate, fp(ALR), A)
|
||||
op(0x4c, JumpAbsolute)
|
||||
op(0x4d, AbsoluteRead, fp(EOR), A)
|
||||
op(0x4e, AbsoluteModify, fp(LSR))
|
||||
@@ -92,6 +100,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x68, Pull, A)
|
||||
op(0x69, Immediate, fp(ADC), A)
|
||||
op(0x6a, Implied, fp(ROR), A)
|
||||
op(0x6b, Immediate, fp(ARR), A)
|
||||
op(0x6c, JumpIndirect)
|
||||
op(0x6d, AbsoluteRead, fp(ADC), A)
|
||||
op(0x6e, AbsoluteModify, fp(ROR))
|
||||
@@ -136,11 +145,13 @@ auto MOS6502::instruction() -> void {
|
||||
op(0xa8, Transfer, A, Y, 1)
|
||||
op(0xa9, Immediate, fp(LD), A)
|
||||
op(0xaa, Transfer, A, X, 1)
|
||||
op(0xab, Immediate, fp(ATX), A)
|
||||
op(0xac, AbsoluteRead, fp(LD), Y)
|
||||
op(0xad, AbsoluteRead, fp(LD), A)
|
||||
op(0xae, AbsoluteRead, fp(LD), X)
|
||||
op(0xb0, Branch, C == 1)
|
||||
op(0xb1, IndirectYRead, fp(LD), A)
|
||||
op(0xb3, IndirectYRead, fp(LD), A, X)
|
||||
op(0xb4, ZeroPageRead, fp(LD), Y, X)
|
||||
op(0xb5, ZeroPageRead, fp(LD), A, X)
|
||||
op(0xb6, ZeroPageRead, fp(LD), X, Y)
|
||||
@@ -159,6 +170,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0xc8, Implied, fp(INC), Y)
|
||||
op(0xc9, Immediate, fp(CMP), A)
|
||||
op(0xca, Implied, fp(DEC), X)
|
||||
op(0xcb, Immediate, fp(AXS), X)
|
||||
op(0xcc, AbsoluteRead, fp(CPY), Y)
|
||||
op(0xcd, AbsoluteRead, fp(CMP), A)
|
||||
op(0xce, AbsoluteModify, fp(DEC))
|
||||
@@ -182,6 +194,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0xe8, Implied, fp(INC), X)
|
||||
op(0xe9, Immediate, fp(SBC), A)
|
||||
op(0xea, NoOperation)
|
||||
op(0xeb, Immediate, fp(SBC), A)
|
||||
op(0xec, AbsoluteRead, fp(CPX), X)
|
||||
op(0xed, AbsoluteRead, fp(SBC), A)
|
||||
op(0xee, AbsoluteModify, fp(INC))
|
||||
@@ -199,6 +212,7 @@ auto MOS6502::instruction() -> void {
|
||||
}
|
||||
|
||||
//unimplemented instruction
|
||||
debug(unusual, "[6502] unimplemented opcode ", hex(code));
|
||||
return instructionNoOperation();
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,11 @@ auto MOS6502::instructionIndirectYRead(fp alu, n8& data) -> void {
|
||||
L data = ALU(read(absolute + Y));
|
||||
}
|
||||
|
||||
auto MOS6502::instructionIndirectYRead(fp alu, n8& data, n8& data2) -> void {
|
||||
instructionIndirectYRead(alu, data);
|
||||
data2 = data;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionIndirectYWrite(n8& data) -> void {
|
||||
auto zeroPage = operand();
|
||||
n16 absolute = load(zeroPage + 0);
|
||||
|
||||
@@ -32,11 +32,17 @@ namespace ares {
|
||||
#undef N
|
||||
#undef L
|
||||
|
||||
auto MOS6502::power() -> void {
|
||||
auto MOS6502::power(bool reset) -> void {
|
||||
if(reset) {
|
||||
S-=3;
|
||||
P.i = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
A = 0x00;
|
||||
X = 0x00;
|
||||
Y = 0x00;
|
||||
S = 0xff;
|
||||
S = 0xfd;
|
||||
P = 0x04;
|
||||
MDR = 0x00;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ struct MOS6502 {
|
||||
virtual auto readDebugger(n16 addr) -> n8 { return 0; }
|
||||
|
||||
//mos6502.cpp
|
||||
auto power() -> void;
|
||||
auto power(bool reset = false) -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto idle() -> void;
|
||||
@@ -31,7 +31,12 @@ struct MOS6502 {
|
||||
using fp = auto (MOS6502::*)(n8) -> n8;
|
||||
auto algorithmADC(n8) -> n8;
|
||||
auto algorithmAND(n8) -> n8;
|
||||
auto algorithmANC(n8) -> n8;
|
||||
auto algorithmARR(n8) -> n8;
|
||||
auto algorithmASL(n8) -> n8;
|
||||
auto algorithmATX(n8) -> n8;
|
||||
auto algorithmALR(n8) -> n8;
|
||||
auto algorithmAXS(n8) -> n8;
|
||||
auto algorithmBIT(n8) -> n8;
|
||||
auto algorithmCMP(n8) -> n8;
|
||||
auto algorithmCPX(n8) -> n8;
|
||||
@@ -45,6 +50,7 @@ struct MOS6502 {
|
||||
auto algorithmROL(n8) -> n8;
|
||||
auto algorithmROR(n8) -> n8;
|
||||
auto algorithmSBC(n8) -> n8;
|
||||
auto algorithmSLO(n8) -> n8;
|
||||
|
||||
//instruction.cpp
|
||||
auto interrupt() -> void;
|
||||
@@ -66,6 +72,7 @@ struct MOS6502 {
|
||||
auto instructionIndirectXRead(fp alu, n8& data) -> void;
|
||||
auto instructionIndirectXWrite(n8& data) -> void;
|
||||
auto instructionIndirectYRead(fp alu, n8& data) -> void;
|
||||
auto instructionIndirectYRead(fp, n8& data, n8& data2) -> void;
|
||||
auto instructionIndirectYWrite(n8& data) -> void;
|
||||
auto instructionJumpAbsolute() -> void;
|
||||
auto instructionJumpIndirect() -> void;
|
||||
|
||||
@@ -2,7 +2,8 @@ struct Accuracy {
|
||||
//enable all accuracy flags
|
||||
static constexpr bool Reference = 0;
|
||||
|
||||
static constexpr bool Interpreter = 0 | Reference;
|
||||
static constexpr bool Interpreter = 0 | Reference | !recompiler::generic::supported;
|
||||
static constexpr bool CachedInterpreter = 0 & !Interpreter;
|
||||
static constexpr bool Recompiler = !Interpreter;
|
||||
|
||||
//exceptions when the CPU or DMA accesses unaligned memory addresses
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
auto SH2::Recompiler::invalidate(u32 address) -> void {
|
||||
auto pool = pools[address >> 8 & 0xffffff];
|
||||
if(!pool) return;
|
||||
memory::jitprotect(false);
|
||||
pool->blocks[address >> 1 & 0x7f] = nullptr;
|
||||
memory::jitprotect(true);
|
||||
}
|
||||
|
||||
auto SH2::Recompiler::pool(u32 address) -> Pool* {
|
||||
auto& pool = pools[address >> 8 & 0xffffff];
|
||||
if(!pool) pool = (Pool*)allocator.acquire(sizeof(Pool));
|
||||
return pool;
|
||||
}
|
||||
|
||||
auto SH2::Recompiler::block(u32 address) -> Block* {
|
||||
if(auto block = pool(address)->blocks[address >> 1 & 0x7f]) return block;
|
||||
auto block = emit(address);
|
||||
pool(address)->blocks[address >> 1 & 0x7f] = block;
|
||||
memory::jitprotect(true);
|
||||
return block;
|
||||
}
|
||||
|
||||
alwaysinline auto SH2::Recompiler::emitInstruction(u16 opcode) -> bool {
|
||||
#define op(id, name, ...) \
|
||||
case id: \
|
||||
call(&SH2::name, &self, ##__VA_ARGS__); \
|
||||
return 0;
|
||||
#define br(id, name, ...) \
|
||||
case id: \
|
||||
call(&SH2::name, &self, ##__VA_ARGS__); \
|
||||
return 1;
|
||||
#include "decoder.hpp"
|
||||
#undef op
|
||||
#undef br
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CCR mem(sreg(1), offsetof(Registers, CCR))
|
||||
|
||||
auto SH2::Recompiler::emit(u32 address) -> Block* {
|
||||
if(unlikely(allocator.available() < 1_MiB)) {
|
||||
print("SH2 allocator flush\n");
|
||||
memory::jitprotect(false);
|
||||
allocator.release(bump_allocator::zero_fill);
|
||||
memory::jitprotect(true);
|
||||
reset();
|
||||
}
|
||||
|
||||
auto block = (Block*)allocator.acquire(sizeof(Block));
|
||||
beginFunction(2);
|
||||
|
||||
bool hasBranched = 0;
|
||||
while(true) {
|
||||
u16 instruction = self.readWord(address);
|
||||
bool branched = emitInstruction(instruction);
|
||||
add64(CCR, CCR, imm(1));
|
||||
call(&SH2::instructionEpilogue);
|
||||
address += 2;
|
||||
if(hasBranched || (address & 0xfe) == 0) break; //block boundary
|
||||
hasBranched = branched;
|
||||
testJumpEpilog();
|
||||
}
|
||||
jumpEpilog();
|
||||
|
||||
memory::jitprotect(false);
|
||||
block->code = endFunction();
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
#undef CCR
|
||||
@@ -6,68 +6,68 @@
|
||||
#define d8 (opcode >> 0 & 0x0ff)
|
||||
#define d12 (opcode >> 0 & 0xfff)
|
||||
switch(opcode >> 8 & 0x00f0 | opcode & 0x000f) {
|
||||
op(0x04, MOVBS0, m, n); //MOV.B Rm,@(R0,Rn)
|
||||
op(0x05, MOVWS0, m, n); //MOV.W Rm,@(R0,Rn)
|
||||
op(0x06, MOVLS0, m, n); //MOV.L Rm,@(R0,Rn)
|
||||
op(0x07, MULL, m, n); //MUL.L Rm,Rn
|
||||
op(0x0c, MOVBL0, m, n); //MOV.B @(R0,Rm),Rn
|
||||
op(0x0d, MOVWL0, m, n); //MOV.W @(R0,Rm),Rn
|
||||
op(0x0e, MOVLL0, m, n); //MOV.L @(R0,Rm),Rn
|
||||
op(0x0f, MACL_, m, n); //MAC.L @Rm+,@Rn+
|
||||
op(0x10 ... 0x1f, MOVLS4, m, d4, n); //MOV.L Rm,@(disp,Rn)
|
||||
op(0x20, MOVBS, m, n); //MOV.B Rm,@Rn
|
||||
op(0x21, MOVWS, m, n); //MOV.W Rm,@Rn
|
||||
op(0x22, MOVLS, m, n); //MOV.L Rm,@Rn
|
||||
op(0x24, MOVBM, m, n); //MOV.B Rm,@-Rn
|
||||
op(0x25, MOVWM, m, n); //MOV.W Rm,@-Rn
|
||||
op(0x26, MOVLM, m, n); //MOV.L Rm,@-Rn
|
||||
op(0x27, DIV0S, m, n); //DIV0S Rm,Rn
|
||||
op(0x28, TST, m, n); //TST Rm,Rn
|
||||
op(0x29, AND, m, n); //AND Rm,Rn
|
||||
op(0x2a, XOR, m, n); //XOR Rm,Rn
|
||||
op(0x2b, OR, m, n); //OR Rm,Rn
|
||||
op(0x2c, CMPSTR, m, n); //CMP/STR Rm,Rn
|
||||
op(0x2d, XTRCT, m, n); //XTRCT Rm,Rn
|
||||
op(0x2e, MULU, m, n); //MULU Rm,Rn
|
||||
op(0x2f, MULS, m, n); //MULS Rm,Rn
|
||||
op(0x30, CMPEQ, m, n); //CMP/EQ Rm,Rn
|
||||
op(0x32, CMPHS, m, n); //CMP/HS Rm,Rn
|
||||
op(0x33, CMPGE, m, n); //CMP/GE Rm,Rn
|
||||
op(0x34, DIV1, m, n); //DIV1 Rm,Rn
|
||||
op(0x35, DMULU, m, n); //DMULU.L Rm,Rn
|
||||
op(0x36, CMPHI, m, n); //CMP/HI Rm,Rn
|
||||
op(0x37, CMPGT, m, n); //CMP/GT Rm,Rn
|
||||
op(0x38, SUB, m, n); //SUB Rm,Rn
|
||||
op(0x3a, SUBC, m, n); //SUBC Rm,Rn
|
||||
op(0x3b, SUBV, m, n); //SUBV Rm,Rn
|
||||
op(0x3c, ADD, m, n); //ADD Rm,Rn
|
||||
op(0x3d, DMULS, m, n); //DMULS.L Rm,Rn
|
||||
op(0x3e, ADDC, m, n); //ADDC Rm,Rn
|
||||
op(0x3f, ADDV, m, n); //ADDV Rm,Rn
|
||||
op(0x4f, MACW, m, n); //MAC.W @Rm+,@Rn+
|
||||
op(0x50 ... 0x5f, MOVLL4, m, d4, n); //MOV.L @(disp,Rm),Rn
|
||||
op(0x60, MOVBL, m, n); //MOV.B @Rm,Rn
|
||||
op(0x61, MOVWL, m, n); //MOV.W @Rm,Rn
|
||||
op(0x62, MOVLL, m, n); //MOV.L @Rm,Rn
|
||||
op(0x63, MOV, m, n); //MOV Rm,Rn
|
||||
op(0x64, MOVBP, m, n); //MOV.B @Rm+,Rn
|
||||
op(0x65, MOVWP, m, n); //MOV.W @Rm+,Rn
|
||||
op(0x66, MOVLP, m, n); //MOV.L @Rm+,Rn
|
||||
op(0x67, NOT, m, n); //NOT Rm,Rn
|
||||
op(0x68, SWAPB, m, n); //SWAP.B Rm,Rn
|
||||
op(0x69, SWAPW, m, n); //SWAP.W Rm,Rn
|
||||
op(0x6a, NEGC, m, n); //NEGC Rm,Rn
|
||||
op(0x6b, NEG, m, n); //NEG Rm,Rn
|
||||
op(0x6c, EXTUB, m, n); //EXTU.B Rm,Rn
|
||||
op(0x6d, EXTUW, m, n); //EXTU.W Rm,Rn
|
||||
op(0x6e, EXTSB, m, n); //EXTS.B Rm,Rn
|
||||
op(0x6f, EXTSW, m, n); //EXTS.W Rm,Rn
|
||||
op(0x70 ... 0x7f, ADDI, i, n); //ADD #imm,Rn
|
||||
op(0x90 ... 0x9f, MOVWI, d8, n); //MOV.W @(disp,PC),Rn
|
||||
br(0xa0 ... 0xaf, BRA, d12); //BRA disp
|
||||
br(0xb0 ... 0xbf, BSR, d12); //BSR disp
|
||||
op(0xd0 ... 0xdf, MOVLI, d8, n); //MOV.L @(disp.PC),Rn
|
||||
op(0xe0 ... 0xef, MOVI, i, n); //MOV #imm,Rn
|
||||
op(0x04, MOVBS0, m, n); //MOV.B Rm,@(R0,Rn)
|
||||
op(0x05, MOVWS0, m, n); //MOV.W Rm,@(R0,Rn)
|
||||
op(0x06, MOVLS0, m, n); //MOV.L Rm,@(R0,Rn)
|
||||
op(0x07, MULL, m, n); //MUL.L Rm,Rn
|
||||
op(0x0c, MOVBL0, m, n); //MOV.B @(R0,Rm),Rn
|
||||
op(0x0d, MOVWL0, m, n); //MOV.W @(R0,Rm),Rn
|
||||
op(0x0e, MOVLL0, m, n); //MOV.L @(R0,Rm),Rn
|
||||
op(0x0f, MACL_, m, n); //MAC.L @Rm+,@Rn+
|
||||
op(range16(0x10, 0x1f), MOVLS4, m, d4, n); //MOV.L Rm,@(disp,Rn)
|
||||
op(0x20, MOVBS, m, n); //MOV.B Rm,@Rn
|
||||
op(0x21, MOVWS, m, n); //MOV.W Rm,@Rn
|
||||
op(0x22, MOVLS, m, n); //MOV.L Rm,@Rn
|
||||
op(0x24, MOVBM, m, n); //MOV.B Rm,@-Rn
|
||||
op(0x25, MOVWM, m, n); //MOV.W Rm,@-Rn
|
||||
op(0x26, MOVLM, m, n); //MOV.L Rm,@-Rn
|
||||
op(0x27, DIV0S, m, n); //DIV0S Rm,Rn
|
||||
op(0x28, TST, m, n); //TST Rm,Rn
|
||||
op(0x29, AND, m, n); //AND Rm,Rn
|
||||
op(0x2a, XOR, m, n); //XOR Rm,Rn
|
||||
op(0x2b, OR, m, n); //OR Rm,Rn
|
||||
op(0x2c, CMPSTR, m, n); //CMP/STR Rm,Rn
|
||||
op(0x2d, XTRCT, m, n); //XTRCT Rm,Rn
|
||||
op(0x2e, MULU, m, n); //MULU Rm,Rn
|
||||
op(0x2f, MULS, m, n); //MULS Rm,Rn
|
||||
op(0x30, CMPEQ, m, n); //CMP/EQ Rm,Rn
|
||||
op(0x32, CMPHS, m, n); //CMP/HS Rm,Rn
|
||||
op(0x33, CMPGE, m, n); //CMP/GE Rm,Rn
|
||||
op(0x34, DIV1, m, n); //DIV1 Rm,Rn
|
||||
op(0x35, DMULU, m, n); //DMULU.L Rm,Rn
|
||||
op(0x36, CMPHI, m, n); //CMP/HI Rm,Rn
|
||||
op(0x37, CMPGT, m, n); //CMP/GT Rm,Rn
|
||||
op(0x38, SUB, m, n); //SUB Rm,Rn
|
||||
op(0x3a, SUBC, m, n); //SUBC Rm,Rn
|
||||
op(0x3b, SUBV, m, n); //SUBV Rm,Rn
|
||||
op(0x3c, ADD, m, n); //ADD Rm,Rn
|
||||
op(0x3d, DMULS, m, n); //DMULS.L Rm,Rn
|
||||
op(0x3e, ADDC, m, n); //ADDC Rm,Rn
|
||||
op(0x3f, ADDV, m, n); //ADDV Rm,Rn
|
||||
op(0x4f, MACW, m, n); //MAC.W @Rm+,@Rn+
|
||||
op(range16(0x50, 0x5f), MOVLL4, m, d4, n); //MOV.L @(disp,Rm),Rn
|
||||
op(0x60, MOVBL, m, n); //MOV.B @Rm,Rn
|
||||
op(0x61, MOVWL, m, n); //MOV.W @Rm,Rn
|
||||
op(0x62, MOVLL, m, n); //MOV.L @Rm,Rn
|
||||
op(0x63, MOV, m, n); //MOV Rm,Rn
|
||||
op(0x64, MOVBP, m, n); //MOV.B @Rm+,Rn
|
||||
op(0x65, MOVWP, m, n); //MOV.W @Rm+,Rn
|
||||
op(0x66, MOVLP, m, n); //MOV.L @Rm+,Rn
|
||||
op(0x67, NOT, m, n); //NOT Rm,Rn
|
||||
op(0x68, SWAPB, m, n); //SWAP.B Rm,Rn
|
||||
op(0x69, SWAPW, m, n); //SWAP.W Rm,Rn
|
||||
op(0x6a, NEGC, m, n); //NEGC Rm,Rn
|
||||
op(0x6b, NEG, m, n); //NEG Rm,Rn
|
||||
op(0x6c, EXTUB, m, n); //EXTU.B Rm,Rn
|
||||
op(0x6d, EXTUW, m, n); //EXTU.W Rm,Rn
|
||||
op(0x6e, EXTSB, m, n); //EXTS.B Rm,Rn
|
||||
op(0x6f, EXTSW, m, n); //EXTS.W Rm,Rn
|
||||
op(range16(0x70, 0x7f), ADDI, i, n); //ADD #imm,Rn
|
||||
op(range16(0x90, 0x9f), MOVWI, d8, n); //MOV.W @(disp,PC),Rn
|
||||
br(range16(0xa0, 0xaf), BRA, d12); //BRA disp
|
||||
br(range16(0xb0, 0xbf), BSR, d12); //BSR disp
|
||||
op(range16(0xd0, 0xdf), MOVLI, d8, n); //MOV.L @(disp.PC),Rn
|
||||
op(range16(0xe0, 0xef), MOVI, i, n); //MOV #imm,Rn
|
||||
}
|
||||
#undef n
|
||||
#undef m
|
||||
@@ -94,7 +94,7 @@
|
||||
op(0xc0, MOVBSG, d8); //MOV.B R0,@(disp,GBR)
|
||||
op(0xc1, MOVWSG, d8); //MOV.W R0,@(disp,GBR)
|
||||
op(0xc2, MOVLSG, d8); //MOV.L R0,@(disp,GBR)
|
||||
op(0xc3, TRAPA, i); //TRAPA #imm
|
||||
br(0xc3, TRAPA, i); //TRAPA #imm
|
||||
op(0xc4, MOVBLG, d8); //MOV.B @(disp,GBR),R0
|
||||
op(0xc5, MOVWLG, d8); //MOV.W @(disp,GBR),R0
|
||||
op(0xc6, MOVLLG, d8); //MOV.L @(disp,GBR),R0
|
||||
@@ -174,7 +174,7 @@
|
||||
br(0x000b, RTS); //RTS
|
||||
op(0x0018, SETT); //SETT
|
||||
op(0x0019, DIV0U); //DIV0U
|
||||
op(0x001b, SLEEP); //SLEEP
|
||||
br(0x001b, SLEEP); //SLEEP
|
||||
op(0x0028, CLRMAC); //CLRMAC
|
||||
br(0x002b, RTE); //RTE
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
template<typename... P>
|
||||
auto SH2::hint(P&&... p) const -> string {
|
||||
if(1) return {};
|
||||
if(1) return {"\e[0m\e[37m", forward<P>(p)..., "\e[0m"};
|
||||
return {forward<P>(p)...};
|
||||
if(1) return {terminal::csi, "0m", terminal::csi, "37m", std::forward<P>(p)..., terminal::csi, "0m"};
|
||||
return {std::forward<P>(p)...};
|
||||
}
|
||||
|
||||
auto SH2::disassembleInstruction() -> string {
|
||||
@@ -81,7 +81,7 @@ auto SH2::disassembleInstruction() -> string {
|
||||
case 0x0f: //MAC.L @Rm+,@Rn+
|
||||
s = {"mac.l", postincrementIndirectRegister(m), postincrementIndirectRegister(n)};
|
||||
break;
|
||||
case 0x10 ... 0x1f: //MOV.L Rm,@(disp,Rn)
|
||||
case range16(0x10, 0x1f): //MOV.L Rm,@(disp,Rn)
|
||||
s = {"mov.l", registerValue(m), indirectRegisterDisplacement(n, d4, 4)};
|
||||
break;
|
||||
case 0x20: //MOV.B Rm,@Rn
|
||||
@@ -174,7 +174,7 @@ auto SH2::disassembleInstruction() -> string {
|
||||
case 0x4f: //MAC.W @Rm+,@Rn+
|
||||
s = {"mac.w", postincrementIndirectRegister(m), postincrementIndirectRegister(n)};
|
||||
break;
|
||||
case 0x50 ... 0x5f: //MOV.L @(disp,Rm),Rn
|
||||
case range16(0x50, 0x5f): //MOV.L @(disp,Rm),Rn
|
||||
s = {"mov.l", indirectRegisterDisplacement(m, d4, 4), registerName(n)};
|
||||
break;
|
||||
case 0x60: //MOV.B @Rm,Rn
|
||||
@@ -225,22 +225,22 @@ auto SH2::disassembleInstruction() -> string {
|
||||
case 0x6f: //EXTS.W Rm,Rn
|
||||
s = {"exts.w", registerValue(m), registerName(n)};
|
||||
break;
|
||||
case 0x70 ... 0x7f: //ADD #imm,Rn
|
||||
case range16(0x70, 0x7f): //ADD #imm,Rn
|
||||
s = {"add", immediate(i), registerValue(n)};
|
||||
break;
|
||||
case 0x90 ... 0x9f: //MOV.W @(disp,PC),Rn
|
||||
case range16(0x90, 0x9f): //MOV.W @(disp,PC),Rn
|
||||
s = {"mov.w", pcRelativeDisplacement(d8, 2), registerName(n)};
|
||||
break;
|
||||
case 0xa0 ... 0xaf: //BRA disp
|
||||
case range16(0xa0, 0xaf): //BRA disp
|
||||
s = {"bra", branch12(d12)};
|
||||
break;
|
||||
case 0xb0 ... 0xbf: //BSR disp
|
||||
case range16(0xb0, 0xbf): //BSR disp
|
||||
s = {"bsr", branch12(d12)};
|
||||
break;
|
||||
case 0xd0 ... 0xdf: //MOV.L @(disp,PC),Rn
|
||||
case range16(0xd0, 0xdf): //MOV.L @(disp,PC),Rn
|
||||
s = {"mov.l", pcRelativeDisplacement(d8, 4), registerName(n)};
|
||||
break;
|
||||
case 0xe0 ... 0xef: //MOV #imm,Rn
|
||||
case range16(0xe0, 0xef): //MOV #imm,Rn
|
||||
s = {"mov", immediate(i), registerName(n)};
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
auto SH2::exceptionHandler() -> void {
|
||||
if(!exceptions) return;
|
||||
if(inDelaySlot()) return;
|
||||
if(inDelaySlot()) { cyclesUntilSync = 0; return; }
|
||||
|
||||
if(exceptions & ResetCold) {
|
||||
exceptions &= ~ResetCold;
|
||||
@@ -34,22 +34,16 @@ auto SH2::push(u32 data) -> void {
|
||||
|
||||
auto SH2::interrupt(u8 level, u8 vector) -> void {
|
||||
push(SR);
|
||||
push(PC);
|
||||
push(PC - 4);
|
||||
jump(readLong(VBR + vector * 4) + 4);
|
||||
SR.I = level;
|
||||
}
|
||||
|
||||
auto SH2::exception(u8 vector) -> void {
|
||||
push(SR);
|
||||
push(PC - 2);
|
||||
jump(readLong(VBR + vector * 4) + 4);
|
||||
}
|
||||
|
||||
auto SH2::addressErrorCPU() -> void {
|
||||
static constexpr u8 vector = 0x09;
|
||||
SP &= ~3; //not accurate; but prevents infinite recursion
|
||||
push(SR);
|
||||
push(PC);
|
||||
push(PC - 4);
|
||||
jump(readLong(VBR + vector * 4) + 4);
|
||||
}
|
||||
|
||||
@@ -57,23 +51,23 @@ auto SH2::addressErrorDMA() -> void {
|
||||
static constexpr u8 vector = 0x0a;
|
||||
SP &= ~3; //not accurate; but prevents infinite recursion
|
||||
push(SR);
|
||||
push(PC);
|
||||
push(PC - 4);
|
||||
jump(readLong(VBR + vector * 4) + 4);
|
||||
}
|
||||
|
||||
auto SH2::illegalInstruction() -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
debug(unusual, "[SH2] illegal instruction: 0x", hex(busReadWord(PC - 4), 4L), " @ 0x", hex(PC - 4));
|
||||
static constexpr u8 vector = 0x04;
|
||||
push(SR);
|
||||
push(PC);
|
||||
push(PC - 4);
|
||||
jump(readLong(VBR + vector * 4) + 4);
|
||||
debug(unusual, "[SH2] illegal instruction: 0x", hex(busReadWord(PC - 4), 4L), " @ 0x", hex(PC - 4));
|
||||
}
|
||||
|
||||
auto SH2::illegalSlotInstruction() -> void {
|
||||
debug(unusual, "[SH2] illegal slot instruction: 0x", hex(busReadWord(PC - 4), 4L));
|
||||
static constexpr u8 vector = 0x06;
|
||||
push(SR);
|
||||
push(PC - 2);
|
||||
push(PPC - 4);
|
||||
jump(readLong(VBR + vector * 4) + 4);
|
||||
debug(unusual, "[SH2] illegal slot instruction: 0x", hex(busReadWord(PC - 4), 4L));
|
||||
}
|
||||
@@ -4,13 +4,11 @@ auto SH2::jump(u32 pc) -> void {
|
||||
}
|
||||
|
||||
auto SH2::branch(u32 pc) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
PPC = pc;
|
||||
PPM = Branch::Take;
|
||||
}
|
||||
|
||||
auto SH2::delaySlot(u32 pc) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
PPC = pc;
|
||||
PPM = Branch::Slot;
|
||||
}
|
||||
@@ -37,7 +35,7 @@ auto SH2::instruction() -> void {
|
||||
do {
|
||||
auto block = recompiler.block(PC - 4);
|
||||
block->execute(*this);
|
||||
} while (CCR <= recompiler.min_cycles);
|
||||
} while (CCR < cyclesUntilSync);
|
||||
|
||||
step(CCR);
|
||||
CCR = 0;
|
||||
|
||||
@@ -43,6 +43,7 @@ auto SH2::ANDM(u32 i) -> void {
|
||||
|
||||
//BF disp
|
||||
auto SH2::BF(u32 d) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
if(SR.T == 0) {
|
||||
branch(PC + 4 + (s8)d * 2);
|
||||
}
|
||||
@@ -50,6 +51,7 @@ auto SH2::BF(u32 d) -> void {
|
||||
|
||||
//BF/S disp
|
||||
auto SH2::BFS(u32 d) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
if(SR.T == 0) {
|
||||
delaySlot(PC + 4 + (s8)d * 2);
|
||||
}
|
||||
@@ -57,28 +59,33 @@ auto SH2::BFS(u32 d) -> void {
|
||||
|
||||
//BRA disp
|
||||
auto SH2::BRA(u32 d) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
delaySlot(PC + 4 + (i12)d * 2);
|
||||
}
|
||||
|
||||
//BRAF disp
|
||||
auto SH2::BRAF(u32 m) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
delaySlot(PC + 4 + R[m]);
|
||||
}
|
||||
|
||||
//BSR disp
|
||||
auto SH2::BSR(u32 d) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
PR = PC;
|
||||
delaySlot(PC + 4 + (i12)d * 2);
|
||||
}
|
||||
|
||||
//BSRF Rm
|
||||
auto SH2::BSRF(u32 m) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
PR = PC;
|
||||
delaySlot(PC + 4 + R[m]);
|
||||
}
|
||||
|
||||
//BT disp
|
||||
auto SH2::BT(u32 d) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
if(SR.T == 1) {
|
||||
branch(PC + 4 + (s8)d * 2);
|
||||
}
|
||||
@@ -86,6 +93,7 @@ auto SH2::BT(u32 d) -> void {
|
||||
|
||||
//BT/S disp
|
||||
auto SH2::BTS(u32 d) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
if(SR.T == 1) {
|
||||
delaySlot(PC + 4 + (s8)d * 2);
|
||||
}
|
||||
@@ -221,11 +229,13 @@ auto SH2::ILLEGAL() -> void {
|
||||
|
||||
//JMP @Rm
|
||||
auto SH2::JMP(u32 m) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
delaySlot(R[m] + 4);
|
||||
}
|
||||
|
||||
//JSR @Rm
|
||||
auto SH2::JSR(u32 m) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
PR = PC;
|
||||
delaySlot(R[m] + 4);
|
||||
}
|
||||
@@ -503,18 +513,21 @@ auto SH2::MOVI(u32 i, u32 n) -> void {
|
||||
}
|
||||
|
||||
//MOV.W @(disp,PC),Rn
|
||||
auto SH2::MOVWI(u32 d, u32 n) -> void {
|
||||
R[n] = (s16)readWord(PC + d * 2);
|
||||
noinline auto SH2::MOVWI(u32 d, u32 n) -> void {
|
||||
u32 pc = inDelaySlot() ? PPC - 2 : PC;
|
||||
R[n] = (s16)readWord(pc + d * 2);
|
||||
}
|
||||
|
||||
//MOV.L @(disp,PC),Rn
|
||||
auto SH2::MOVLI(u32 d, u32 n) -> void {
|
||||
R[n] = readLong((PC & ~3) + d * 4);
|
||||
noinline auto SH2::MOVLI(u32 d, u32 n) -> void {
|
||||
u32 pc = inDelaySlot() ? PPC - 2 : PC;
|
||||
R[n] = readLong((pc & ~3) + d * 4);
|
||||
}
|
||||
|
||||
//MOVA @(disp,PC),R0
|
||||
auto SH2::MOVA(u32 d) -> void {
|
||||
R[0] = (PC & ~3) + d * 4 - inDelaySlot() * 2;
|
||||
noinline auto SH2::MOVA(u32 d) -> void {
|
||||
u32 pc = inDelaySlot() ? PPC - 2 : PC;
|
||||
R[0] = (pc & ~3) + d * 4;
|
||||
}
|
||||
|
||||
//MOVT Rn
|
||||
@@ -602,13 +615,15 @@ auto SH2::ROTR(u32 n) -> void {
|
||||
|
||||
//RTE
|
||||
auto SH2::RTE() -> void {
|
||||
delaySlot(readLong(SP + 0));
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
delaySlot(readLong(SP + 0) + 4);
|
||||
SR = readLong(SP + 4);
|
||||
SP += 8;
|
||||
}
|
||||
|
||||
//RTS
|
||||
auto SH2::RTS() -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
delaySlot(PR + 4);
|
||||
}
|
||||
|
||||
@@ -800,18 +815,16 @@ auto SH2::TAS(u32 n) -> void {
|
||||
) return (void)(exceptions |= AddressErrorCPU);
|
||||
}
|
||||
|
||||
auto cacheEnable = cache.enable;
|
||||
cache.enable = 0;
|
||||
u8 b = readByte(R[n]);
|
||||
cache.enable = cacheEnable;
|
||||
u8 b = readByte<Bus::Internal>(R[n]);
|
||||
SR.T = b == 0;
|
||||
writeByte(R[n], b | 0x80);
|
||||
}
|
||||
|
||||
//TRAPA #imm
|
||||
auto SH2::TRAPA(u32 i) -> void {
|
||||
if(inDelaySlot()) return illegalSlotInstruction();
|
||||
push(SR);
|
||||
push(PC + 2);
|
||||
push(PC - 2);
|
||||
branch(readLong(VBR + i * 4) + 4);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1,6 @@
|
||||
#define XXH_INLINE_ALL
|
||||
#include <xxhash.h>
|
||||
|
||||
#include <ares/ares.hpp>
|
||||
#include "sh2.hpp"
|
||||
|
||||
@@ -45,11 +48,12 @@ auto SH2::power(bool reset) -> void {
|
||||
ET = 0;
|
||||
ID = 0;
|
||||
exceptions = !reset ? ResetCold : ResetWarm;
|
||||
cyclesUntilSync = 0;
|
||||
|
||||
cache = {*this};
|
||||
intc = {*this};
|
||||
dmac = {*this};
|
||||
sci = {*this};
|
||||
sci = {*this, reset ? sci.link : maybe<SH2&>()};
|
||||
wdt = {};
|
||||
ubc = {};
|
||||
frt = {*this};
|
||||
|
||||
@@ -29,7 +29,6 @@ struct SH2 {
|
||||
auto exceptionHandler() -> void;
|
||||
auto push(u32 data) -> void;
|
||||
auto interrupt(u8 level, u8 vector) -> void;
|
||||
auto exception(u8 vector) -> void;
|
||||
auto addressErrorCPU() -> void;
|
||||
auto addressErrorDMA() -> void;
|
||||
auto illegalInstruction() -> void;
|
||||
@@ -246,6 +245,9 @@ struct SH2 {
|
||||
};
|
||||
u32 exceptions = 0; //delayed exception flags
|
||||
|
||||
s32 cyclesUntilSync = 0;
|
||||
s32 minCyclesBetweenSyncs = 0;
|
||||
|
||||
struct Recompiler : recompiler::generic {
|
||||
SH2& self;
|
||||
Recompiler(SH2& self) : self(self), generic(allocator) {}
|
||||
@@ -256,27 +258,53 @@ struct SH2 {
|
||||
}
|
||||
|
||||
u8* code;
|
||||
u8 size;
|
||||
};
|
||||
|
||||
struct Pool {
|
||||
u32 generation;
|
||||
u64 dirty;
|
||||
Block* blocks[1 << 7];
|
||||
};
|
||||
|
||||
struct BlockHashPair {
|
||||
auto operator==(const BlockHashPair& source) const -> bool { return hashcode == source.hashcode; }
|
||||
auto hash() const -> u32 { return hashcode; }
|
||||
|
||||
Block* block;
|
||||
u64 hashcode;
|
||||
};
|
||||
|
||||
auto reset() -> void {
|
||||
generation = 0;
|
||||
blocks.reset();
|
||||
for(u32 index : range(1 << 24)) pools[index] = nullptr;
|
||||
}
|
||||
|
||||
auto invalidate(u32 address) -> void;
|
||||
auto invalidateCached() -> void {
|
||||
generation++;
|
||||
}
|
||||
|
||||
auto invalidate(u32 address, u8 size) -> void;
|
||||
auto pool(u32 address) -> Pool*;
|
||||
auto block(u32 address) -> Block*;
|
||||
auto measure(u32 address) -> u8;
|
||||
auto hash(u32 address, u8 size) -> u64;
|
||||
auto emit(u32 address) -> Block*;
|
||||
auto emitInstruction(u16 opcode) -> bool;
|
||||
auto emitInstruction(u16 opcode) -> u32;
|
||||
auto getSR(reg dst) -> void;
|
||||
auto setSR(reg src) -> void;
|
||||
template<typename F> auto checkDelaySlot(F body) -> void;
|
||||
auto isTerminal(u16 instruction) -> bool;
|
||||
|
||||
static auto mask(u8 address, u8 size) -> u64;
|
||||
|
||||
bool inDelaySlot;
|
||||
u32 generation;
|
||||
bump_allocator allocator;
|
||||
hashset<BlockHashPair> blocks;
|
||||
u16 instructions[1 << 7];
|
||||
Pool* pools[1 << 24];
|
||||
int min_cycles = 0;
|
||||
} recompiler{*this};
|
||||
|
||||
#include "sh7604/sh7604.hpp"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
auto SH2::readByte(u32 address) -> u32 {
|
||||
template<u32 Origin> auto SH2::readByte(u32 address) -> u32 {
|
||||
switch(address >> 29) {
|
||||
|
||||
case Area::Cached: {
|
||||
if(likely(cache.enable)) return cache.read<Byte>(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
if(likely(cache.enable)) return cache.read<Byte>(address);
|
||||
}
|
||||
return busReadByte(address & 0x1fff'ffff);
|
||||
}
|
||||
|
||||
@@ -11,7 +13,10 @@ auto SH2::readByte(u32 address) -> u32 {
|
||||
}
|
||||
|
||||
case Area::Data: {
|
||||
return cache.readData<Byte>(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.readData<Byte>(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::IO: {
|
||||
@@ -28,7 +33,7 @@ auto SH2::readByte(u32 address) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SH2::readWord(u32 address) -> u32 {
|
||||
template<u32 Origin> auto SH2::readWord(u32 address) -> u32 {
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
if(unlikely(address & 1)) return exceptions |= AddressErrorCPU, 0;
|
||||
}
|
||||
@@ -36,7 +41,9 @@ auto SH2::readWord(u32 address) -> u32 {
|
||||
switch(address >> 29) {
|
||||
|
||||
case Area::Cached: {
|
||||
if(likely(cache.enable)) return cache.read<Word>(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
if(likely(cache.enable)) return cache.read<Word>(address);
|
||||
}
|
||||
return busReadWord(address & 0x1fff'fffe);
|
||||
}
|
||||
|
||||
@@ -45,7 +52,10 @@ auto SH2::readWord(u32 address) -> u32 {
|
||||
}
|
||||
|
||||
case Area::Data: {
|
||||
return cache.readData<Word>(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.readData<Word>(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::IO: {
|
||||
@@ -60,7 +70,7 @@ auto SH2::readWord(u32 address) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SH2::readLong(u32 address) -> u32 {
|
||||
template<u32 Origin> auto SH2::readLong(u32 address) -> u32 {
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
if(unlikely(address & 3)) return exceptions |= AddressErrorCPU, 0;
|
||||
}
|
||||
@@ -68,7 +78,9 @@ auto SH2::readLong(u32 address) -> u32 {
|
||||
switch(address >> 29) {
|
||||
|
||||
case Area::Cached: {
|
||||
if(likely(cache.enable)) return cache.read<Long>(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
if(likely(cache.enable)) return cache.read<Long>(address);
|
||||
}
|
||||
return busReadLong(address & 0x1fff'fffc);
|
||||
}
|
||||
|
||||
@@ -77,11 +89,17 @@ auto SH2::readLong(u32 address) -> u32 {
|
||||
}
|
||||
|
||||
case Area::Address: {
|
||||
return cache.readAddress(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.readAddress(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::Data: {
|
||||
return cache.readData<Long>(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.readData<Long>(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::IO: {
|
||||
@@ -104,28 +122,37 @@ auto SH2::readLong(u32 address) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SH2::writeByte(u32 address, u32 data) -> void {
|
||||
template<u32 Origin> auto SH2::writeByte(u32 address, u32 data) -> void {
|
||||
if constexpr(Accuracy::Recompiler) {
|
||||
recompiler.invalidate(address);
|
||||
recompiler.invalidate(address, 1);
|
||||
}
|
||||
|
||||
switch(address >> 29) {
|
||||
|
||||
case Area::Cached: {
|
||||
if(likely(cache.enable)) cache.write<Byte>(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
if(likely(cache.enable)) cache.write<Byte>(address, data);
|
||||
}
|
||||
return busWriteByte(address & 0x1fff'ffff, data);
|
||||
}
|
||||
|
||||
case Area::Uncached: {
|
||||
cyclesUntilSync = 0;
|
||||
return busWriteByte(address & 0x1fff'ffff, data);
|
||||
}
|
||||
|
||||
case Area::Purge: {
|
||||
return cache.purge(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.purge(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::Data: {
|
||||
return cache.writeData<Byte>(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.writeData<Byte>(address, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::IO: {
|
||||
@@ -140,32 +167,41 @@ auto SH2::writeByte(u32 address, u32 data) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto SH2::writeWord(u32 address, u32 data) -> void {
|
||||
template<u32 Origin> auto SH2::writeWord(u32 address, u32 data) -> void {
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
if(unlikely(address & 1)) return (void)(exceptions |= AddressErrorCPU);
|
||||
}
|
||||
|
||||
if constexpr(Accuracy::Recompiler) {
|
||||
recompiler.invalidate(address);
|
||||
recompiler.invalidate(address, 2);
|
||||
}
|
||||
|
||||
switch(address >> 29) {
|
||||
|
||||
case Area::Cached: {
|
||||
if(likely(cache.enable)) cache.write<Word>(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
if(likely(cache.enable)) cache.write<Word>(address, data);
|
||||
}
|
||||
return busWriteWord(address & 0x1fff'fffe, data);
|
||||
}
|
||||
|
||||
case Area::Uncached: {
|
||||
cyclesUntilSync = 0;
|
||||
return busWriteWord(address & 0x1fff'fffe, data);
|
||||
}
|
||||
|
||||
case Area::Purge: {
|
||||
return cache.purge(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.purge(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::Data: {
|
||||
return cache.writeData<Word>(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.writeData<Word>(address, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::IO: {
|
||||
@@ -177,37 +213,48 @@ auto SH2::writeWord(u32 address, u32 data) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto SH2::writeLong(u32 address, u32 data) -> void {
|
||||
template<u32 Origin> auto SH2::writeLong(u32 address, u32 data) -> void {
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
if(unlikely(address & 3)) return (void)(exceptions |= AddressErrorCPU);
|
||||
}
|
||||
|
||||
if constexpr(Accuracy::Recompiler) {
|
||||
recompiler.invalidate(address + 0);
|
||||
recompiler.invalidate(address + 2);
|
||||
recompiler.invalidate(address, 4);
|
||||
}
|
||||
|
||||
switch(address >> 29) {
|
||||
|
||||
case Area::Cached: {
|
||||
if(likely(cache.enable)) cache.write<Long>(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
if(likely(cache.enable)) cache.write<Long>(address, data);
|
||||
}
|
||||
return busWriteLong(address & 0x1fff'fffc, data);
|
||||
}
|
||||
|
||||
case Area::Uncached: {
|
||||
cyclesUntilSync = 0;
|
||||
return busWriteLong(address & 0x1fff'fffc, data);
|
||||
}
|
||||
|
||||
case Area::Purge: {
|
||||
return cache.purge(address);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.purge(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::Address: {
|
||||
return cache.writeAddress(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.writeAddress(address, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::Data: {
|
||||
return cache.writeData<Long>(address, data);
|
||||
if constexpr(Origin == Bus::Cache) {
|
||||
return cache.writeData<Long>(address, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Area::IO: {
|
||||
|
||||
@@ -88,12 +88,20 @@ auto SH2::Cache::purge(u32 address) -> void {
|
||||
if(tags[Way1 | entry] == tag) tags[Way1 | entry] |= Invalid;
|
||||
if(tags[Way2 | entry] == tag) tags[Way2 | entry] |= Invalid;
|
||||
if(tags[Way3 | entry] == tag) tags[Way3 | entry] |= Invalid;
|
||||
|
||||
if constexpr(Accuracy::Recompiler) {
|
||||
self->recompiler.invalidate(address & 0x1fff'fff0, 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
template<u32 Ways>
|
||||
auto SH2::Cache::purge() -> void {
|
||||
for(auto index : range(64)) lrus[index] = 0;
|
||||
for(auto index : range(64 * Ways)) tags[index] |= Invalid;
|
||||
|
||||
if constexpr(Accuracy::Recompiler) {
|
||||
self->recompiler.invalidateCached();
|
||||
}
|
||||
}
|
||||
|
||||
auto SH2::Cache::power() -> void {
|
||||
|
||||
@@ -4,12 +4,16 @@ auto SH2::DMAC::run() -> void {
|
||||
if(chcr[c].ar) {
|
||||
transfer(c);
|
||||
} else if(drcr[c] == 0) {
|
||||
if(dreq) transfer(c);
|
||||
if(dreq[c]) transfer(c);
|
||||
// Note: DACK is not implemented (not used by 32X)
|
||||
} else if(drcr[c] == 1) {
|
||||
debug(unimplemented, "[SH2] DMA RXI");
|
||||
} else if(drcr[c] == 2) {
|
||||
debug(unimplemented, "[SH2] DMA TXI");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break; // ignoring cycle-steal mode for now
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +22,7 @@ auto SH2::DMAC::transfer(bool c) -> void {
|
||||
switch(chcr[c].ts) {
|
||||
|
||||
case 0: //8-bit
|
||||
self->writeByte(dar[c], self->readByte(sar[c]));
|
||||
self->writeByte<Bus::Internal>(dar[c], self->readByte<Bus::Internal>(sar[c]));
|
||||
break;
|
||||
case 1: //16-bit
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
@@ -27,7 +31,7 @@ auto SH2::DMAC::transfer(bool c) -> void {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self->writeWord(dar[c], self->readWord(sar[c]));
|
||||
self->writeWord<Bus::Internal>(dar[c], self->readWord<Bus::Internal>(sar[c]));
|
||||
break;
|
||||
case 2: //32-bit
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
@@ -36,7 +40,7 @@ auto SH2::DMAC::transfer(bool c) -> void {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self->writeLong(dar[c], self->readLong(sar[c]));
|
||||
self->writeLong<Bus::Internal>(dar[c], self->readLong<Bus::Internal>(sar[c]));
|
||||
break;
|
||||
case 3: //32-bit x4
|
||||
if constexpr(Accuracy::AddressErrors) {
|
||||
@@ -45,10 +49,10 @@ auto SH2::DMAC::transfer(bool c) -> void {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self->writeLong(dar[c] + 0, self->readLong(sar[c] + 0));
|
||||
self->writeLong(dar[c] + 4, self->readLong(sar[c] + 4));
|
||||
self->writeLong(dar[c] + 8, self->readLong(sar[c] + 8));
|
||||
self->writeLong(dar[c] + 12, self->readLong(sar[c] + 12));
|
||||
self->writeLong<Bus::Internal>(dar[c] + 0, self->readLong<Bus::Internal>(sar[c] + 0));
|
||||
self->writeLong<Bus::Internal>(dar[c] + 4, self->readLong<Bus::Internal>(sar[c] + 4));
|
||||
self->writeLong<Bus::Internal>(dar[c] + 8, self->readLong<Bus::Internal>(sar[c] + 8));
|
||||
self->writeLong<Bus::Internal>(dar[c] + 12, self->readLong<Bus::Internal>(sar[c] + 12));
|
||||
sar[c] += 16; //always increments regardless of chcr[c].sm
|
||||
tcr[c] -= 3; //always decrements by four instead of by one
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
auto SH2::INTC::run() -> void {
|
||||
if(self->inDelaySlot()) return;
|
||||
if(self->inDelaySlot()) { self->cyclesUntilSync = 0; return; }
|
||||
|
||||
if(self->frt.pendingOutputIRQ) {
|
||||
if(self->SR.I < iprb.frtip) {
|
||||
|
||||
@@ -177,6 +177,7 @@ auto SH2::internalReadByte(u32 address, n8 data) -> n8 {
|
||||
|
||||
//CCR: cache control register
|
||||
case 0xffff'fe92:
|
||||
case 0xffff'fe93:
|
||||
data.bit(0) = cache.enable;
|
||||
data.bit(1) = cache.disableCode;
|
||||
data.bit(2) = cache.disableData;
|
||||
@@ -553,7 +554,7 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
|
||||
sci.scr.te = data.bit(5);
|
||||
sci.scr.rie = data.bit(6);
|
||||
sci.scr.tie = data.bit(7);
|
||||
if(!te && sci.scr.te) sci.run();
|
||||
if(te && !sci.scr.te) sci.ssr.tdre = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -563,7 +564,8 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
|
||||
return;
|
||||
|
||||
//SSR: serial status register
|
||||
case 0xffff'fe04:
|
||||
case 0xffff'fe04: {
|
||||
bool tdre = sci.ssr.tdre;
|
||||
sci.ssr.mpbt = data.bit(0);
|
||||
//sci.ssr.mpb = data.bit(1) = readonly;
|
||||
//sci.ssr.tend = data.bit(2) = readonly;
|
||||
@@ -572,8 +574,9 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
|
||||
sci.ssr.orer &= data.bit(5);
|
||||
sci.ssr.rdrf &= data.bit(6);
|
||||
sci.ssr.tdre &= data.bit(7);
|
||||
if(sci.scr.te) sci.run();
|
||||
if(tdre && !sci.ssr.tdre) sci.run();
|
||||
return;
|
||||
}
|
||||
|
||||
//RDR: receive data register
|
||||
case 0xffff'fe05:
|
||||
@@ -717,6 +720,7 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
|
||||
|
||||
//CCR: cache control register
|
||||
case 0xffff'fe92:
|
||||
case 0xffff'fe93:
|
||||
cache.enable = data.bit(0);
|
||||
cache.disableCode = data.bit(1);
|
||||
cache.disableData = data.bit(2);
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
//struct SH2 {
|
||||
enum : u32 { Byte, Word, Long };
|
||||
|
||||
struct Bus {
|
||||
enum : u32 { Cache, Internal, Peripheral };
|
||||
};
|
||||
|
||||
struct Area { enum : u32 {
|
||||
Cached = 0,
|
||||
Uncached = 1,
|
||||
@@ -15,12 +19,12 @@
|
||||
};};
|
||||
|
||||
//bus.cpp
|
||||
auto readByte(u32 address) -> u32;
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto readLong(u32 address) -> u32;
|
||||
auto writeByte(u32 address, u32 data) -> void;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto writeLong(u32 address, u32 data) -> void;
|
||||
template<u32 Origin = Bus::Cache> auto readByte(u32 address) -> u32;
|
||||
template<u32 Origin = Bus::Cache> auto readWord(u32 address) -> u32;
|
||||
template<u32 Origin = Bus::Cache> auto readLong(u32 address) -> u32;
|
||||
template<u32 Origin = Bus::Cache> auto writeByte(u32 address, u32 data) -> void;
|
||||
template<u32 Origin = Bus::Cache> auto writeWord(u32 address, u32 data) -> void;
|
||||
template<u32 Origin = Bus::Cache> auto writeLong(u32 address, u32 data) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto internalReadByte(u32 address, n8 data = 0) -> n8;
|
||||
@@ -155,8 +159,9 @@
|
||||
n1 pr; //priority mode bit
|
||||
} dmaor;
|
||||
|
||||
n1 dreq[2];
|
||||
|
||||
//internal:
|
||||
n1 dreq;
|
||||
n2 pendingIRQ;
|
||||
} dmac;
|
||||
|
||||
@@ -197,7 +202,7 @@
|
||||
n1 fer; //framing error
|
||||
n1 orer; //overrun error
|
||||
n1 rdrf; //receive data register full
|
||||
n1 tdre; //transmit data register empty
|
||||
n1 tdre = 1; //transmit data register empty
|
||||
} ssr;
|
||||
n8 brr = 0xff; //bit rate register
|
||||
n8 tdr = 0xff; //transmit data register
|
||||
|
||||
@@ -27,7 +27,7 @@ auto SH2::FRT::run() -> void {
|
||||
}
|
||||
}
|
||||
auto SH2::WDT::run() -> void {
|
||||
static constexpr u32 frequencies[8] = {2, 64, 128, 256, 512, 1024, 2096, 8192};
|
||||
static constexpr u32 frequencies[8] = {2, 64, 128, 256, 512, 1024, 4096, 8192};
|
||||
|
||||
if(!wtcsr.tme) return;
|
||||
if(wtcsr.wtit) return; // Watchdog mode currently unsupported
|
||||
|
||||
@@ -12,54 +12,54 @@ auto SM5K::disassembleInstruction() -> string {
|
||||
string pc = {"0x", hex(n4(opcode) << 8 | operand, 3L)};
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00 ... 0x0f: s = {"adx ", p4}; break;
|
||||
case 0x10 ... 0x1f: s = {"lax ", p4}; break;
|
||||
case 0x20 ... 0x2f: s = {"lblx ", p4}; break;
|
||||
case 0x30 ... 0x3f: s = {"lbmx ", p4}; break;
|
||||
case 0x40 ... 0x43: s = {"rm ", p2}; break;
|
||||
case 0x44 ... 0x47: s = {"sm ", p2}; break;
|
||||
case 0x48 ... 0x4b: s = {"tm ", p2}; break;
|
||||
case 0x4c ... 0x4f: s = {"tpb ", p2}; break;
|
||||
case 0x50 ... 0x53: s = {"lda ", p2}; break;
|
||||
case 0x54 ... 0x57: s = {"exc ", p2}; break;
|
||||
case 0x58 ... 0x5b: s = {"exci ", p2}; break;
|
||||
case 0x5c ... 0x5f: s = {"excd ", p2}; break;
|
||||
case 0x60: s = {"rc " }; break;
|
||||
case 0x61: s = {"sc " }; break;
|
||||
case 0x62: s = {"id " }; break;
|
||||
case 0x63: s = {"ie " }; break;
|
||||
case 0x64: s = {"exax " }; break;
|
||||
case 0x65: s = {"atx " }; break;
|
||||
case 0x66: s = {"exbm " }; break;
|
||||
case 0x67: s = {"exbl " }; break;
|
||||
case 0x68: s = {"ex " }; break;
|
||||
case 0x69: s = {"dta ", p8}; break;
|
||||
case 0x6a: s = {"pat ", p8}; break;
|
||||
case 0x6b: s = {"tabl " }; break;
|
||||
case 0x6c: s = {"ta " }; break;
|
||||
case 0x6d: s = {"tb " }; break;
|
||||
case 0x6e: s = {"tc " }; break;
|
||||
case 0x6f: s = {"tam " }; break;
|
||||
case 0x70: s = {"inl " }; break;
|
||||
case 0x71: s = {"outl " }; break;
|
||||
case 0x72: s = {"anp " }; break;
|
||||
case 0x73: s = {"orp " }; break;
|
||||
case 0x74: s = {"in " }; break;
|
||||
case 0x75: s = {"out " }; break;
|
||||
case 0x76: s = {"stop " }; break;
|
||||
case 0x77: s = {"halt " }; break;
|
||||
case 0x78: s = {"incb " }; break;
|
||||
case 0x79: s = {"coma " }; break;
|
||||
case 0x7a: s = {"add " }; break;
|
||||
case 0x7b: s = {"adc " }; break;
|
||||
case 0x7c: s = {"decb " }; break;
|
||||
case 0x7d: s = {"rtn " }; break;
|
||||
case 0x7e: s = {"rtns " }; break;
|
||||
case 0x7f: s = {"rtni " }; break;
|
||||
case 0x80 ... 0xbf: s = {"tr ", p6}; break;
|
||||
case 0xc0 ... 0xdf: s = {"trs ", p5}; break;
|
||||
case 0xe0 ... 0xef: s = {"tl ", pc}; break;
|
||||
case 0xf0 ... 0xff: s = {"call ", pc}; break;
|
||||
case range16(0x00, 0x0f): s = {"adx ", p4}; break;
|
||||
case range16(0x10, 0x1f): s = {"lax ", p4}; break;
|
||||
case range16(0x20, 0x2f): s = {"lblx ", p4}; break;
|
||||
case range16(0x30, 0x3f): s = {"lbmx ", p4}; break;
|
||||
case range4 (0x40, 0x43): s = {"rm ", p2}; break;
|
||||
case range4 (0x44, 0x47): s = {"sm ", p2}; break;
|
||||
case range4 (0x48, 0x4b): s = {"tm ", p2}; break;
|
||||
case range4 (0x4c, 0x4f): s = {"tpb ", p2}; break;
|
||||
case range4 (0x50, 0x53): s = {"lda ", p2}; break;
|
||||
case range4 (0x54, 0x57): s = {"exc ", p2}; break;
|
||||
case range4 (0x58, 0x5b): s = {"exci ", p2}; break;
|
||||
case range4 (0x5c, 0x5f): s = {"excd ", p2}; break;
|
||||
case 0x60: s = {"rc " }; break;
|
||||
case 0x61: s = {"sc " }; break;
|
||||
case 0x62: s = {"id " }; break;
|
||||
case 0x63: s = {"ie " }; break;
|
||||
case 0x64: s = {"exax " }; break;
|
||||
case 0x65: s = {"atx " }; break;
|
||||
case 0x66: s = {"exbm " }; break;
|
||||
case 0x67: s = {"exbl " }; break;
|
||||
case 0x68: s = {"ex " }; break;
|
||||
case 0x69: s = {"dta ", p8}; break;
|
||||
case 0x6a: s = {"pat ", p8}; break;
|
||||
case 0x6b: s = {"tabl " }; break;
|
||||
case 0x6c: s = {"ta " }; break;
|
||||
case 0x6d: s = {"tb " }; break;
|
||||
case 0x6e: s = {"tc " }; break;
|
||||
case 0x6f: s = {"tam " }; break;
|
||||
case 0x70: s = {"inl " }; break;
|
||||
case 0x71: s = {"outl " }; break;
|
||||
case 0x72: s = {"anp " }; break;
|
||||
case 0x73: s = {"orp " }; break;
|
||||
case 0x74: s = {"in " }; break;
|
||||
case 0x75: s = {"out " }; break;
|
||||
case 0x76: s = {"stop " }; break;
|
||||
case 0x77: s = {"halt " }; break;
|
||||
case 0x78: s = {"incb " }; break;
|
||||
case 0x79: s = {"coma " }; break;
|
||||
case 0x7a: s = {"add " }; break;
|
||||
case 0x7b: s = {"adc " }; break;
|
||||
case 0x7c: s = {"decb " }; break;
|
||||
case 0x7d: s = {"rtn " }; break;
|
||||
case 0x7e: s = {"rtns " }; break;
|
||||
case 0x7f: s = {"rtni " }; break;
|
||||
case range64(0x80, 0xbf): s = {"tr ", p6}; break;
|
||||
case range32(0xc0, 0xdf): s = {"trs ", p5}; break;
|
||||
case range16(0xe0, 0xef): s = {"tl ", pc}; break;
|
||||
case range16(0xf0, 0xff): s = {"call ", pc}; break;
|
||||
}
|
||||
|
||||
while(s.size() < 10) s.append(" ");
|
||||
|
||||
@@ -20,54 +20,54 @@ auto SM5K::instruction() -> void {
|
||||
|
||||
n8 opcode = fetch();
|
||||
switch(opcode) {
|
||||
op(0x00 ... 0x0f, ADX, n4(opcode));
|
||||
op(0x10 ... 0x1f, LAX, n4(opcode));
|
||||
op(0x20 ... 0x2f, LBLX, n4(opcode));
|
||||
op(0x30 ... 0x3f, LBMX, n4(opcode));
|
||||
op(0x40 ... 0x43, RM, n2(opcode));
|
||||
op(0x44 ... 0x47, SM, n2(opcode));
|
||||
op(0x48 ... 0x4b, TM, n2(opcode));
|
||||
op(0x4c ... 0x4f, TPB, n2(opcode));
|
||||
op(0x50 ... 0x53, LDA, n2(opcode));
|
||||
op(0x54 ... 0x57, EXC, n2(opcode));
|
||||
op(0x58 ... 0x5b, EXCI, n2(opcode));
|
||||
op(0x5c ... 0x5f, EXCD, n2(opcode));
|
||||
op(0x60, RC );
|
||||
op(0x61, SC );
|
||||
op(0x62, ID );
|
||||
op(0x63, IE );
|
||||
op(0x64, EXAX );
|
||||
op(0x65, ATX );
|
||||
op(0x66, EXBM );
|
||||
op(0x67, EXBL );
|
||||
op(0x68, EX );
|
||||
op(0x69, DTA, fetch());
|
||||
op(0x6a, PAT, fetch());
|
||||
op(0x6b, TABL );
|
||||
op(0x6c, TA );
|
||||
op(0x6d, TB );
|
||||
op(0x6e, TC );
|
||||
op(0x6f, TAM );
|
||||
op(0x70, INL );
|
||||
op(0x71, OUTL );
|
||||
op(0x72, ANP );
|
||||
op(0x73, ORP );
|
||||
op(0x74, IN );
|
||||
op(0x75, OUT );
|
||||
op(0x76, STOP );
|
||||
op(0x77, HALT );
|
||||
op(0x78, INCB );
|
||||
op(0x79, COMA );
|
||||
op(0x7a, ADD );
|
||||
op(0x7b, ADC );
|
||||
op(0x7c, DECB );
|
||||
op(0x7d, RTN );
|
||||
op(0x7e, RTNS );
|
||||
op(0x7f, RTNI );
|
||||
op(0x80 ... 0xbf, TR, n6(opcode));
|
||||
op(0xc0 ... 0xdf, TRS, n5(opcode));
|
||||
op(0xe0 ... 0xef, TL, n4(opcode) << 8 | fetch());
|
||||
op(0xf0 ... 0xff, CALL, n4(opcode) << 8 | fetch());
|
||||
op(range16(0x00, 0x0f), ADX, n4(opcode));
|
||||
op(range16(0x10, 0x1f), LAX, n4(opcode));
|
||||
op(range16(0x20, 0x2f), LBLX, n4(opcode));
|
||||
op(range16(0x30, 0x3f), LBMX, n4(opcode));
|
||||
op(range4 (0x40, 0x43), RM, n2(opcode));
|
||||
op(range4 (0x44, 0x47), SM, n2(opcode));
|
||||
op(range4 (0x48, 0x4b), TM, n2(opcode));
|
||||
op(range4 (0x4c, 0x4f), TPB, n2(opcode));
|
||||
op(range4 (0x50, 0x53), LDA, n2(opcode));
|
||||
op(range4 (0x54, 0x57), EXC, n2(opcode));
|
||||
op(range4 (0x58, 0x5b), EXCI, n2(opcode));
|
||||
op(range4 (0x5c, 0x5f), EXCD, n2(opcode));
|
||||
op(0x60, RC );
|
||||
op(0x61, SC );
|
||||
op(0x62, ID );
|
||||
op(0x63, IE );
|
||||
op(0x64, EXAX );
|
||||
op(0x65, ATX );
|
||||
op(0x66, EXBM );
|
||||
op(0x67, EXBL );
|
||||
op(0x68, EX );
|
||||
op(0x69, DTA, fetch());
|
||||
op(0x6a, PAT, fetch());
|
||||
op(0x6b, TABL );
|
||||
op(0x6c, TA );
|
||||
op(0x6d, TB );
|
||||
op(0x6e, TC );
|
||||
op(0x6f, TAM );
|
||||
op(0x70, INL );
|
||||
op(0x71, OUTL );
|
||||
op(0x72, ANP );
|
||||
op(0x73, ORP );
|
||||
op(0x74, IN );
|
||||
op(0x75, OUT );
|
||||
op(0x76, STOP );
|
||||
op(0x77, HALT );
|
||||
op(0x78, INCB );
|
||||
op(0x79, COMA );
|
||||
op(0x7a, ADD );
|
||||
op(0x7b, ADC );
|
||||
op(0x7c, DECB );
|
||||
op(0x7d, RTN );
|
||||
op(0x7e, RTNS );
|
||||
op(0x7f, RTNI );
|
||||
op(range64(0x80, 0xbf), TR, n6(opcode));
|
||||
op(range32(0xc0, 0xdf), TRS, n5(opcode));
|
||||
op(range16(0xe0, 0xef), TL, n4(opcode) << 8 | fetch());
|
||||
op(range16(0xf0, 0xff), CALL, n4(opcode) << 8 | fetch());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ auto SSP1601::cmp(u32 source) -> void {
|
||||
N = result >> 31;
|
||||
}
|
||||
|
||||
auto SSP1601::and(u32 v) -> void {
|
||||
auto SSP1601::and_(u32 v) -> void {
|
||||
A &= v;
|
||||
Z = A == 0;
|
||||
N = A >> 31;
|
||||
}
|
||||
|
||||
auto SSP1601::or(u32 v) -> void {
|
||||
auto SSP1601::or_(u32 v) -> void {
|
||||
A |= v;
|
||||
Z = A == 0;
|
||||
N = A >> 31;
|
||||
|
||||
@@ -210,7 +210,7 @@ auto SSP1601::disassembleInstruction(u16 pc, u16 op, u16 imm) -> string {
|
||||
}
|
||||
|
||||
//ldi ri,simm
|
||||
case 0x0c ... 0x0f: {
|
||||
case range4(0x0c, 0x0f): {
|
||||
o = "ldi";
|
||||
p = {"r", (op >> 8 & 7), ",0x", hex(op & 0xff, 2L)};
|
||||
break;
|
||||
|
||||
@@ -95,7 +95,7 @@ auto SSP1601::instruction() -> void {
|
||||
}
|
||||
|
||||
//ldi ri,simm
|
||||
case 0x0c ... 0x0f: {
|
||||
case range4(0x0c, 0x0f): {
|
||||
R[n3(op >> 8)] = n8(op);
|
||||
break;
|
||||
}
|
||||
@@ -173,56 +173,56 @@ auto SSP1601::instruction() -> void {
|
||||
case 0x10: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); sub(v); break; }
|
||||
case 0x30: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); cmp(v); break; }
|
||||
case 0x40: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); add(v); break; }
|
||||
case 0x50: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); and(v); break; }
|
||||
case 0x60: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); or (v); break; }
|
||||
case 0x50: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); and_(v); break; }
|
||||
case 0x60: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); or_(v); break; }
|
||||
case 0x70: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); eor(v); break; }
|
||||
|
||||
//alu a,(ri)
|
||||
case 0x11: { auto v = readPR1(op) << 16; sub(v); break; }
|
||||
case 0x31: { auto v = readPR1(op) << 16; cmp(v); break; }
|
||||
case 0x41: { auto v = readPR1(op) << 16; add(v); break; }
|
||||
case 0x51: { auto v = readPR1(op) << 16; and(v); break; }
|
||||
case 0x61: { auto v = readPR1(op) << 16; or (v); break; }
|
||||
case 0x51: { auto v = readPR1(op) << 16; and_(v); break; }
|
||||
case 0x61: { auto v = readPR1(op) << 16; or_(v); break; }
|
||||
case 0x71: { auto v = readPR1(op) << 16; eor(v); break; }
|
||||
|
||||
//alu a,addr
|
||||
case 0x13: { auto v = RAM[n9(op)] << 16; sub(v); break; }
|
||||
case 0x33: { auto v = RAM[n9(op)] << 16; cmp(v); break; }
|
||||
case 0x43: { auto v = RAM[n9(op)] << 16; add(v); break; }
|
||||
case 0x53: { auto v = RAM[n9(op)] << 16; and(v); break; }
|
||||
case 0x63: { auto v = RAM[n9(op)] << 16; or (v); break; }
|
||||
case 0x53: { auto v = RAM[n9(op)] << 16; and_(v); break; }
|
||||
case 0x63: { auto v = RAM[n9(op)] << 16; or_(v); break; }
|
||||
case 0x73: { auto v = RAM[n9(op)] << 16; eor(v); break; }
|
||||
|
||||
//alu a,imm
|
||||
case 0x14: { auto v = fetch() << 16; sub(v); break; }
|
||||
case 0x34: { auto v = fetch() << 16; cmp(v); break; }
|
||||
case 0x44: { auto v = fetch() << 16; add(v); break; }
|
||||
case 0x54: { auto v = fetch() << 16; and(v); break; }
|
||||
case 0x64: { auto v = fetch() << 16; or (v); break; }
|
||||
case 0x54: { auto v = fetch() << 16; and_(v); break; }
|
||||
case 0x64: { auto v = fetch() << 16; or_(v); break; }
|
||||
case 0x74: { auto v = fetch() << 16; eor(v); break; }
|
||||
|
||||
//alu a,((ri))
|
||||
case 0x15: { auto v = readPR2(op) << 16; sub(v); break; }
|
||||
case 0x35: { auto v = readPR2(op) << 16; cmp(v); break; }
|
||||
case 0x45: { auto v = readPR2(op) << 16; add(v); break; }
|
||||
case 0x55: { auto v = readPR2(op) << 16; and(v); break; }
|
||||
case 0x65: { auto v = readPR2(op) << 16; or (v); break; }
|
||||
case 0x55: { auto v = readPR2(op) << 16; and_(v); break; }
|
||||
case 0x65: { auto v = readPR2(op) << 16; or_(v); break; }
|
||||
case 0x75: { auto v = readPR2(op) << 16; eor(v); break; }
|
||||
|
||||
//alu a,ri
|
||||
case 0x19: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; sub(v); break; }
|
||||
case 0x39: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; cmp(v); break; }
|
||||
case 0x49: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; add(v); break; }
|
||||
case 0x59: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; and(v); break; }
|
||||
case 0x69: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; or (v); break; }
|
||||
case 0x59: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; and_(v); break; }
|
||||
case 0x69: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; or_(v); break; }
|
||||
case 0x79: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; eor(v); break; }
|
||||
|
||||
//alu simm
|
||||
case 0x1c: { auto v = u8(op) << 16; sub(v); break; }
|
||||
case 0x3c: { auto v = u8(op) << 16; cmp(v); break; }
|
||||
case 0x4c: { auto v = u8(op) << 16; add(v); break; }
|
||||
case 0x5c: { auto v = u8(op) << 16; and(v); break; }
|
||||
case 0x6c: { auto v = u8(op) << 16; or (v); break; }
|
||||
case 0x5c: { auto v = u8(op) << 16; and_(v); break; }
|
||||
case 0x6c: { auto v = u8(op) << 16; or_(v); break; }
|
||||
case 0x7c: { auto v = u8(op) << 16; eor(v); break; }
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ struct SSP1601 {
|
||||
auto add(u32) -> void;
|
||||
auto sub(u32) -> void;
|
||||
auto cmp(u32) -> void;
|
||||
auto and(u32) -> void;
|
||||
auto or (u32) -> void;
|
||||
auto and_(u32) -> void;
|
||||
auto or_(u32) -> void;
|
||||
auto eor(u32) -> void;
|
||||
auto shr() -> void;
|
||||
auto shl() -> void;
|
||||
|
||||
@@ -144,23 +144,23 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x1d: name = "call"; lhs.immediate(24, read24()); break;
|
||||
case 0x1e: name = "calr"; lhs.displacementPC(16, read16()); break;
|
||||
case 0x1f: break;
|
||||
case 0x20 ... 0x27: name = "ld"; lhs.register3(8, fetch); rhs.immediate(8, read8()); break;
|
||||
case 0x28 ... 0x2f: name = "push"; lhs.register3(16, fetch); break;
|
||||
case 0x30 ... 0x37: name = "ld"; lhs.register3(16, fetch); rhs.immediate(16, read16()); break;
|
||||
case 0x38 ... 0x3f: name = "push"; lhs.register3(32, fetch); break;
|
||||
case 0x40 ... 0x47: name = "ld"; lhs.register3(32, fetch); rhs.immediate(32, read32()); break;
|
||||
case 0x48 ... 0x4f: name = "pop"; lhs.register3(16, fetch); break;
|
||||
case 0x50 ... 0x5f: name = "pop"; lhs.register3(32, fetch); break;
|
||||
case 0x60 ... 0x6f: name = "jr"; lhs.condition(fetch); rhs.displacementPC(8, read8()); break;
|
||||
case 0x70 ... 0x7f: name = "jrl"; lhs.condition(fetch); rhs.displacementPC(16, read16()); break;
|
||||
case 0x80 ... 0x87: opSourceMemory = true; lhs.indirectRegister3(8, fetch); break;
|
||||
case 0x88 ... 0x8f: opSourceMemory = true; lhs.indirectRegister3Displacement8(8, fetch, read8()); break;
|
||||
case 0x90 ... 0x97: opSourceMemory = true; lhs.indirectRegister3(16, fetch); break;
|
||||
case 0x98 ... 0x9f: opSourceMemory = true; lhs.indirectRegister3Displacement8(16, fetch, read8()); break;
|
||||
case 0xa0 ... 0xa7: opSourceMemory = true; lhs.indirectRegister3(32, fetch); break;
|
||||
case 0xa8 ... 0xaf: opSourceMemory = true; lhs.indirectRegister3Displacement8(32, fetch, read8()); break;
|
||||
case 0xb0 ... 0xb7: opTargetMemory = true; lhs.indirectRegister3(0, fetch); break;
|
||||
case 0xb8 ... 0xbf: opTargetMemory = true; lhs.indirectRegister3Displacement8(0, fetch, read8()); break;
|
||||
case range8(0x20, 0x27): name = "ld"; lhs.register3(8, fetch); rhs.immediate(8, read8()); break;
|
||||
case range8(0x28, 0x2f): name = "push"; lhs.register3(16, fetch); break;
|
||||
case range8(0x30, 0x37): name = "ld"; lhs.register3(16, fetch); rhs.immediate(16, read16()); break;
|
||||
case range8(0x38, 0x3f): name = "push"; lhs.register3(32, fetch); break;
|
||||
case range8(0x40, 0x47): name = "ld"; lhs.register3(32, fetch); rhs.immediate(32, read32()); break;
|
||||
case range8(0x48, 0x4f): name = "pop"; lhs.register3(16, fetch); break;
|
||||
case range16(0x50, 0x5f): name = "pop"; lhs.register3(32, fetch); break;
|
||||
case range16(0x60, 0x6f): name = "jr"; lhs.condition(fetch); rhs.displacementPC(8, read8()); break;
|
||||
case range16(0x70, 0x7f): name = "jrl"; lhs.condition(fetch); rhs.displacementPC(16, read16()); break;
|
||||
case range8(0x80, 0x87): opSourceMemory = true; lhs.indirectRegister3(8, fetch); break;
|
||||
case range8(0x88, 0x8f): opSourceMemory = true; lhs.indirectRegister3Displacement8(8, fetch, read8()); break;
|
||||
case range8(0x90, 0x97): opSourceMemory = true; lhs.indirectRegister3(16, fetch); break;
|
||||
case range8(0x98, 0x9f): opSourceMemory = true; lhs.indirectRegister3Displacement8(16, fetch, read8()); break;
|
||||
case range8(0xa0, 0xa7): opSourceMemory = true; lhs.indirectRegister3(32, fetch); break;
|
||||
case range8(0xa8, 0xaf): opSourceMemory = true; lhs.indirectRegister3Displacement8(32, fetch, read8()); break;
|
||||
case range8(0xb0, 0xb7): opTargetMemory = true; lhs.indirectRegister3(0, fetch); break;
|
||||
case range8(0xb8, 0xbf): opTargetMemory = true; lhs.indirectRegister3Displacement8(0, fetch, read8()); break;
|
||||
case 0xc0: case 0xd0: case 0xe0: case 0xf0:
|
||||
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
|
||||
lhs.indirectImmediate8(opSize, read8()); break;
|
||||
@@ -203,10 +203,10 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
read8(); lhs.indirectImmediate8(8, read8());
|
||||
read8(); rhs.immediate(8, read8());
|
||||
read8(); break;
|
||||
case 0xc8 ... 0xcf: opRegister = true; lhs.register3(8, fetch); break;
|
||||
case 0xd8 ... 0xdf: opRegister = true; lhs.register3(16, fetch); break;
|
||||
case 0xe8 ... 0xef: opRegister = true; lhs.register3(32, fetch); break;
|
||||
case 0xf8 ... 0xff: name = "swi"; lhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xc8, 0xcf): opRegister = true; lhs.register3(8, fetch); break;
|
||||
case range8(0xd8, 0xdf): opRegister = true; lhs.register3(16, fetch); break;
|
||||
case range8(0xe8, 0xef): opRegister = true; lhs.register3(32, fetch); break;
|
||||
case range8(0xf8, 0xff): name = "swi"; lhs.immediate(3, (n3)fetch); break;
|
||||
}
|
||||
#undef opSize
|
||||
|
||||
@@ -221,7 +221,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
//size defined
|
||||
if(opRegister)
|
||||
switch(auto fetch = read8()) {
|
||||
case 0x00 ... 0x02: break;
|
||||
case range3(0x00, 0x02): break;
|
||||
case 0x03: name = "ld"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0x04: name = "push"; break;
|
||||
case 0x05: name = "pop"; break;
|
||||
@@ -242,17 +242,17 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x14: name = "paa"; break;
|
||||
case 0x15: break;
|
||||
case 0x16: name = "mirr"; break;
|
||||
case 0x17 ... 0x18: break;
|
||||
case range2(0x17, 0x18): break;
|
||||
case 0x19: name = "mula"; break;
|
||||
case 0x1a ... 0x1b: break;
|
||||
case range2(0x1a, 0x1b): break;
|
||||
case 0x1c: name = "djnz"; rhs.displacementPC(8, read8()); break;
|
||||
case 0x1d ... 0x1f: break;
|
||||
case range3(0x1d, 0x1f): break;
|
||||
case 0x20: name = "andcf"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x21: name = "orcf"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x22: name = "xorcf"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x23: name = "ldcf"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x24: name = "stcf"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x25 ... 0x27: break;
|
||||
case range3(0x25, 0x27): break;
|
||||
case 0x28: name = "andcf"; rhs.register(8, A.id); break;
|
||||
case 0x29: name = "orcf"; rhs.register(8, A.id); break;
|
||||
case 0x2a: name = "xorcf"; rhs.register(8, A.id); break;
|
||||
@@ -266,7 +266,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x32: name = "chg"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x33: name = "bit"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x34: name = "tset"; rhs.immediate(4, (n4)read8()); break;
|
||||
case 0x35 ... 0x37: break;
|
||||
case range3(0x35, 0x37): break;
|
||||
case 0x38: name = "minc1"; rhs.immediate(16, read16()); break;
|
||||
case 0x39: name = "minc2"; rhs.immediate(16, read16()); break;
|
||||
case 0x3a: name = "minc4"; rhs.immediate(16, read16()); break;
|
||||
@@ -275,22 +275,22 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x3d: name = "mdec2"; rhs.immediate(16, read16()); break;
|
||||
case 0x3e: name = "mdec4"; rhs.immediate(16, read16()); break;
|
||||
case 0x3f: break;
|
||||
case 0x40 ... 0x47: name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x48 ... 0x4f: name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x50 ... 0x57: name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x58 ... 0x5f: name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x60 ... 0x67: name = "inc"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case 0x68 ... 0x6f: name = "dec"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case 0x70 ... 0x7f: name = "scc"; rhs = lhs; lhs.condition(fetch); break;
|
||||
case 0x80 ... 0x87: name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x88 ... 0x8f: name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x90 ... 0x97: name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x98 ... 0x9f: name = "ld"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xa0 ... 0xa7: name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xa8 ... 0xaf: name = "ld"; rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xb0 ... 0xb7: name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xb8 ... 0xbf: name = "ex"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xc0 ... 0xc7: name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x40, 0x47): name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x48, 0x4f): name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x50, 0x57): name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x58, 0x5f): name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x60, 0x67): name = "inc"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case range8(0x68, 0x6f): name = "dec"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case range16(0x70, 0x7f): name = "scc"; rhs = lhs; lhs.condition(fetch); break;
|
||||
case range8(0x80, 0x87): name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x88, 0x8f): name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x90, 0x97): name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x98, 0x9f): name = "ld"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xa0, 0xa7): name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xa8, 0xaf): name = "ld"; rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xb0, 0xb7): name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xb8, 0xbf): name = "ex"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xc0, 0xc7): name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xc8: name = "add"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0xc9: name = "adc"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0xca: name = "sub"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
@@ -299,9 +299,9 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0xcd: name = "xor"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0xce: name = "or"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0xcf: name = "cp"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0xd0 ... 0xd7: name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xd8 ... 0xdf: name = "cp"; rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xe0 ... 0xe7: name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xd0, 0xd7): name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xd8, 0xdf): name = "cp"; rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xe0, 0xe7): name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xe8: name = "rlc"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
|
||||
case 0xe9: name = "rrc"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
|
||||
case 0xea: name = "rl"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
|
||||
@@ -310,7 +310,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0xed: name = "sra"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
|
||||
case 0xee: name = "sll"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
|
||||
case 0xef: name = "srl"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
|
||||
case 0xf0 ... 0xf7: name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xf0, 0xf7): name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xf8: name = "rlc"; rhs.register(8, A.id); break;
|
||||
case 0xf9: name = "rrc"; rhs.register(8, A.id); break;
|
||||
case 0xfa: name = "rl"; rhs.register(8, A.id); break;
|
||||
@@ -324,12 +324,12 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
//size defined
|
||||
if(opSourceMemory)
|
||||
switch(auto fetch = read8()) {
|
||||
case 0x00 ... 0x03: break;
|
||||
case range4(0x00, 0x03): break;
|
||||
case 0x04: name = lhs.size() == 8 ? "push" : "pushw"; break;
|
||||
case 0x05: break;
|
||||
case 0x06: name = "rld"; rhs = lhs; lhs.register(8, A.id); break;
|
||||
case 0x07: name = "rrd"; rhs = lhs; lhs.register(8, A.id); break;
|
||||
case 0x08 ... 0x0f: break;
|
||||
case range8(0x08, 0x0f): break;
|
||||
case 0x10:
|
||||
name = lhs.size() == 8 ? "ldi" : "ldiw";
|
||||
lhs.indirectRegisterIncrement(32, (n3)op[0] != 5 ? XDE.id : XIX.id);
|
||||
@@ -372,10 +372,10 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
break;
|
||||
case 0x18: break;
|
||||
case 0x19: name = "ld"; rhs = lhs; lhs.indirectImmediate16(16, read16()); break;
|
||||
case 0x1a ... 0x1f: break;
|
||||
case 0x20 ... 0x27: name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x28 ... 0x2f: break;
|
||||
case 0x30 ... 0x37: name = "ex"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range6(0x1a, 0x1f): break;
|
||||
case range8(0x20, 0x27): name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x28, 0x2f): break;
|
||||
case range8(0x30, 0x37): name = "ex"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0x38: name = "add"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0x39: name = "adc"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0x3a: name = "sub"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
@@ -384,13 +384,13 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x3d: name = "xor"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0x3e: name = "or"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0x3f: name = "cp"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
|
||||
case 0x40 ... 0x47: name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x48 ... 0x4f: name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x50 ... 0x57: name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x58 ... 0x5f: name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x60 ... 0x67: name = "inc"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case 0x68 ... 0x6f: name = "dec"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case 0x70 ... 0x77: break;
|
||||
case range8(0x40, 0x47): name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x48, 0x4f): name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x50, 0x57): name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x58, 0x5f): name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x60, 0x67): name = "inc"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case range8(0x68, 0x6f): name = "dec"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
|
||||
case range8(0x70, 0x77): break;
|
||||
case 0x78: name = "rlc"; break;
|
||||
case 0x79: name = "rrc"; break;
|
||||
case 0x7a: name = "rl"; break;
|
||||
@@ -399,22 +399,22 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x7d: name = "sra"; break;
|
||||
case 0x7e: name = "sll"; break;
|
||||
case 0x7f: name = "srl"; break;
|
||||
case 0x80 ... 0x87: name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x88 ... 0x8f: name = "add"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0x90 ... 0x97: name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x98 ... 0x9f: name = "adc"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xa0 ... 0xa7: name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xa8 ... 0xaf: name = "sub"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xb0 ... 0xb7: name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xb8 ... 0xbf: name = "sbb"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xc0 ... 0xc7: name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xc8 ... 0xcf: name = "and"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xd0 ... 0xd7: name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xd8 ... 0xdf: name = "xor"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xe0 ... 0xe7: name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xe8 ... 0xef: name = "or"; rhs.register3(lhs.size(), fetch); break;
|
||||
case 0xf0 ... 0xf7: name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0xf8 ... 0xff: name = "cp"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0x80, 0x87): name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x88, 0x8f): name = "add"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0x90, 0x97): name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x98, 0x9f): name = "adc"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xa0, 0xa7): name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xa8, 0xaf): name = "sub"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xb0, 0xb7): name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xb8, 0xbf): name = "sbb"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xc0, 0xc7): name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xc8, 0xcf): name = "and"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xd0, 0xd7): name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xd8, 0xdf): name = "xor"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xe0, 0xe7): name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xe8, 0xef): name = "or"; rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0xf0, 0xf7): name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0xf8, 0xff): name = "cp"; rhs.register3(lhs.size(), fetch); break;
|
||||
}
|
||||
|
||||
//size undefined
|
||||
@@ -427,41 +427,41 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
|
||||
case 0x04: name = "pop"; lhs.size(8); break;
|
||||
case 0x05: break;
|
||||
case 0x06: name = "pop"; lhs.size(16); break;
|
||||
case 0x07 ... 0x13: break;
|
||||
case range13(0x07, 0x13): break;
|
||||
case 0x14: name = "ld"; lhs.size(8); rhs.indirectImmediate16(16, read16()); break;
|
||||
case 0x15: break;
|
||||
case 0x16: name = "ld"; lhs.size(16); rhs.indirectImmediate16(16, read16()); break;
|
||||
case 0x17 ... 0x1f: break;
|
||||
case 0x20 ... 0x27: name = "lda"; lhs.size(16); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range9(0x17, 0x1f): break;
|
||||
case range8(0x20, 0x27): name = "lda"; lhs.size(16); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x28: name = "andcf"; lhs.size(8); rhs.register3(8, A.id); break;
|
||||
case 0x29: name = "orcf"; lhs.size(8); rhs.register3(8, A.id); break;
|
||||
case 0x2a: name = "xorcf"; lhs.size(8); rhs.register3(8, A.id); break;
|
||||
case 0x2b: name = "ldcf"; lhs.size(8); rhs.register3(8, A.id); break;
|
||||
case 0x2c: name = "stcf"; lhs.size(8); rhs.register3(8, A.id); break;
|
||||
case 0x2d ... 0x2f: break;
|
||||
case 0x30 ... 0x37: name = "lda"; lhs.size(32); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case 0x38 ... 0x3f: break;
|
||||
case 0x40 ... 0x47: name = "ld"; lhs.size(8); rhs.register3(lhs.size(), fetch); break;
|
||||
case 0x48 ... 0x4f: break;
|
||||
case 0x50 ... 0x57: name = "ld"; lhs.size(16); rhs.register3(lhs.size(), fetch); break;
|
||||
case 0x58 ... 0x5f: break;
|
||||
case 0x60 ... 0x67: name = "ld"; lhs.size(32); rhs.register3(lhs.size(), fetch); break;
|
||||
case 0x68 ... 0x6f: break;
|
||||
case 0x70 ... 0x77: break;
|
||||
case 0x78 ... 0x7f: break;
|
||||
case 0x80 ... 0x87: name = "andcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0x88 ... 0x8f: name = "orcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0x90 ... 0x97: name = "xorcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0x98 ... 0x9f: name = "ldcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xa0 ... 0xa7: name = "stcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xa8 ... 0xaf: name = "tset"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xb0 ... 0xb7: name = "res"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xb8 ... 0xbf: name = "set"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xc0 ... 0xc7: name = "chg"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xc8 ... 0xcf: name = "bit"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case 0xd0 ... 0xdf: name = "jp"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
|
||||
case 0xe0 ... 0xef: name = "call"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
|
||||
case 0xf0 ... 0xff: name = "ret"; lhs.condition(fetch); break;
|
||||
case range3(0x2d, 0x2f): break;
|
||||
case range8(0x30, 0x37): name = "lda"; lhs.size(32); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
|
||||
case range8(0x38, 0x3f): break;
|
||||
case range8(0x40, 0x47): name = "ld"; lhs.size(8); rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0x48, 0x4f): break;
|
||||
case range8(0x50, 0x57): name = "ld"; lhs.size(16); rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0x58, 0x5f): break;
|
||||
case range8(0x60, 0x67): name = "ld"; lhs.size(32); rhs.register3(lhs.size(), fetch); break;
|
||||
case range8(0x68, 0x6f): break;
|
||||
case range8(0x70, 0x77): break;
|
||||
case range8(0x78, 0x7f): break;
|
||||
case range8(0x80, 0x87): name = "andcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0x88, 0x8f): name = "orcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0x90, 0x97): name = "xorcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0x98, 0x9f): name = "ldcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xa0, 0xa7): name = "stcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xa8, 0xaf): name = "tset"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xb0, 0xb7): name = "res"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xb8, 0xbf): name = "set"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xc0, 0xc7): name = "chg"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range8(0xc8, 0xcf): name = "bit"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
|
||||
case range16(0xd0, 0xdf): name = "jp"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
|
||||
case range16(0xe0, 0xef): name = "call"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
|
||||
case range16(0xf0, 0xff): name = "ret"; lhs.condition(fetch); break;
|
||||
}
|
||||
|
||||
auto operand = [&](Operand& operand) -> string {
|
||||
|
||||
@@ -187,41 +187,41 @@ auto TLCS900H::instruction() -> void {
|
||||
case 0x1f: {
|
||||
return undefined();
|
||||
}
|
||||
case 0x20 ... 0x27: { //LD R,n
|
||||
case range8(0x20, 0x27): { //LD R,n
|
||||
auto immediate = fetchImmediate<n8>();
|
||||
prefetch(4);
|
||||
return instructionLoad(toRegister3<n8>(data), immediate);
|
||||
}
|
||||
case 0x28 ... 0x2f: { //PUSH.W rr
|
||||
case range8(0x28, 0x2f): { //PUSH.W rr
|
||||
prefetch(4);
|
||||
return instructionPush(toRegister3<n16>(data));
|
||||
}
|
||||
case 0x30 ... 0x37: { //LD RR,nn
|
||||
case range8(0x30, 0x37): { //LD RR,nn
|
||||
auto immediate = fetchImmediate<n16>();
|
||||
prefetch(6);
|
||||
return instructionLoad(toRegister3<n16>(data), immediate);
|
||||
}
|
||||
case 0x38 ... 0x3f: { //PUSH.L XRR
|
||||
case range8(0x38, 0x3f): { //PUSH.L XRR
|
||||
prefetch(6);
|
||||
return instructionPush(toRegister3<n32>(data));
|
||||
}
|
||||
case 0x40 ... 0x47: { //LD XRR,nnnn
|
||||
case range8(0x40, 0x47): { //LD XRR,nnnn
|
||||
auto immediate = fetchImmediate<n32>();
|
||||
prefetch(10);
|
||||
return instructionLoad(toRegister3<n32>(data), immediate);
|
||||
}
|
||||
case 0x48 ... 0x4f: { //POP.W RR
|
||||
case range8(0x48, 0x4f): { //POP.W RR
|
||||
prefetch(6);
|
||||
return instructionPop(toRegister3<n16>(data));
|
||||
}
|
||||
case 0x50 ... 0x57: {
|
||||
case range8(0x50, 0x57): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x58 ... 0x5f: { //POP.L XRR
|
||||
case range8(0x58, 0x5f): { //POP.L XRR
|
||||
prefetch(8);
|
||||
return instructionPop(toRegister3<n32>(data));
|
||||
}
|
||||
case 0x60 ... 0x6f: { //JR cc,PC+d
|
||||
case range16(0x60, 0x6f): { //JR cc,PC+d
|
||||
auto immediate = fetchImmediate<i8>();
|
||||
prefetch(4);
|
||||
if(!condition((n4)data)) return;
|
||||
@@ -229,7 +229,7 @@ auto TLCS900H::instruction() -> void {
|
||||
instructionJumpRelative(immediate);
|
||||
return prefetch(2);
|
||||
}
|
||||
case 0x70 ... 0x7f: { //JRL cc,PC+dd
|
||||
case range16(0x70, 0x7f): { //JRL cc,PC+dd
|
||||
auto immediate = fetchImmediate<i16>();
|
||||
prefetch(4);
|
||||
if(!condition((n4)data)) return;
|
||||
@@ -237,34 +237,34 @@ auto TLCS900H::instruction() -> void {
|
||||
instructionJumpRelative(immediate);
|
||||
return prefetch(2);
|
||||
}
|
||||
case 0x80 ... 0x87: { //src.B
|
||||
case range8(0x80, 0x87): { //src.B
|
||||
return instructionSourceMemory(toMemory<n8>(load(toRegister3<n32>(data))));
|
||||
}
|
||||
case 0x88 ... 0x8f: { //src.B
|
||||
case range8(0x88, 0x8f): { //src.B
|
||||
auto immediate = fetch<i8>();
|
||||
prefetch(2);
|
||||
return instructionSourceMemory(toMemory<n8>(load(toRegister3<n32>(data)) + immediate));
|
||||
}
|
||||
case 0x90 ... 0x97: { //src.W
|
||||
case range8(0x90, 0x97): { //src.W
|
||||
return instructionSourceMemory(toMemory<n16>(load(toRegister3<n32>(data))));
|
||||
}
|
||||
case 0x98 ... 0x9f: { //src.W
|
||||
case range8(0x98, 0x9f): { //src.W
|
||||
auto immediate = fetch<i8>();
|
||||
prefetch(2);
|
||||
return instructionSourceMemory(toMemory<n16>(load(toRegister3<n32>(data)) + immediate));
|
||||
}
|
||||
case 0xa0 ... 0xa7: { //src.L
|
||||
case range8(0xa0, 0xa7): { //src.L
|
||||
return instructionSourceMemory(toMemory<n32>(load(toRegister3<n32>(data))));
|
||||
}
|
||||
case 0xa8 ... 0xaf: { //src.L
|
||||
case range8(0xa8, 0xaf): { //src.L
|
||||
auto immediate = fetch<i8>();
|
||||
prefetch(2);
|
||||
return instructionSourceMemory(toMemory<n32>(load(toRegister3<n32>(data)) + immediate));
|
||||
}
|
||||
case 0xb0 ... 0xb7: { //dst
|
||||
case range8(0xb0, 0xb7): { //dst
|
||||
return instructionTargetMemory(load(toRegister3<n32>(data)));
|
||||
}
|
||||
case 0xb8 ... 0xbf: { //dst
|
||||
case range8(0xb8, 0xbf): { //dst
|
||||
auto immediate = fetch<i8>();
|
||||
prefetch(2);
|
||||
return instructionTargetMemory(load(toRegister3<n32>(data)) + immediate);
|
||||
@@ -342,7 +342,7 @@ auto TLCS900H::instruction() -> void {
|
||||
prefetch(2);
|
||||
return instructionRegister(register);
|
||||
}
|
||||
case 0xc8 ... 0xcf: { //reg.B
|
||||
case range8(0xc8, 0xcf): { //reg.B
|
||||
return instructionRegister(toRegister3<n8>(data));
|
||||
}
|
||||
case 0xd0: { //src.W
|
||||
@@ -418,7 +418,7 @@ auto TLCS900H::instruction() -> void {
|
||||
prefetch(2);
|
||||
return instructionRegister(register);
|
||||
}
|
||||
case 0xd8 ... 0xdf: { //reg.W
|
||||
case range8(0xd8, 0xdf): { //reg.W
|
||||
return instructionRegister(toRegister3<n16>(data));
|
||||
}
|
||||
case 0xe0: { //src.L
|
||||
@@ -494,7 +494,7 @@ auto TLCS900H::instruction() -> void {
|
||||
prefetch(2);
|
||||
return instructionRegister(register);
|
||||
}
|
||||
case 0xe8 ... 0xef: { //reg.L
|
||||
case range8(0xe8, 0xef): { //reg.L
|
||||
return instructionRegister(toRegister3<n32>(data));
|
||||
}
|
||||
case 0xf0: { //dst
|
||||
@@ -542,10 +542,10 @@ auto TLCS900H::instruction() -> void {
|
||||
auto address = load(PC) + immediate; //load PC before final byte fetch
|
||||
data = fetch();
|
||||
switch(data) {
|
||||
case 0x20 ... 0x27:
|
||||
case range8(0x20, 0x27):
|
||||
prefetch(14);
|
||||
return instructionLoad(toRegister3<n16>(data), toImmediate<n16>(address));
|
||||
case 0x30 ... 0x37:
|
||||
case range8(0x30, 0x37):
|
||||
prefetch(14);
|
||||
return instructionLoad(toRegister3<n32>(data), toImmediate<n32>(address));
|
||||
}
|
||||
@@ -587,7 +587,7 @@ auto TLCS900H::instruction() -> void {
|
||||
prefetch(14);
|
||||
return instructionLoad(memory, immediate);
|
||||
}
|
||||
case 0xf8 ... 0xff: { //SWI n
|
||||
case range8(0xf8, 0xff): { //SWI n
|
||||
return instructionSoftwareInterrupt((n3)data);
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
|
||||
switch(data) {
|
||||
|
||||
case 0x00 ... 0x02: {
|
||||
case range3(0x00, 0x02): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x03: { //LD r,#
|
||||
@@ -744,7 +744,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x17 ... 0x18: {
|
||||
case range2(0x17, 0x18): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x19: { //MULA r
|
||||
@@ -754,7 +754,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x1a ... 0x1b: {
|
||||
case range2(0x1a, 0x1b): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x1c: { //DJNZ r,d
|
||||
@@ -765,7 +765,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x1d ... 0x1f: {
|
||||
case range3(0x1d, 0x1f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x20: { //ANDCF #,r
|
||||
@@ -808,7 +808,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x25 ... 0x27: {
|
||||
case range3(0x25, 0x27): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x28: { //ANDCF A,r
|
||||
@@ -899,7 +899,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x35 ... 0x37: {
|
||||
case range3(0x35, 0x37): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x38: { //MINC1 #,r
|
||||
@@ -956,7 +956,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
case 0x3f: {
|
||||
return undefined();
|
||||
}
|
||||
case 0x40 ... 0x47: { //MUL R,r
|
||||
case range8(0x40, 0x47): { //MUL R,r
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(22);
|
||||
if constexpr(Word) prefetch(28);
|
||||
@@ -964,7 +964,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x48 ... 0x4f: { //MULS R,r
|
||||
case range8(0x48, 0x4f): { //MULS R,r
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(18);
|
||||
if constexpr(Word) prefetch(24);
|
||||
@@ -972,7 +972,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x50 ... 0x57: { //DIV R,r
|
||||
case range8(0x50, 0x57): { //DIV R,r
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(30);
|
||||
if constexpr(Word) prefetch(46);
|
||||
@@ -980,7 +980,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x58 ... 0x5f: { //DIVS R,r
|
||||
case range8(0x58, 0x5f): { //DIVS R,r
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(36);
|
||||
if constexpr(Word) prefetch(52);
|
||||
@@ -988,57 +988,57 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x60 ... 0x67: { //INC #3,r
|
||||
case range8(0x60, 0x67): { //INC #3,r
|
||||
prefetch(4);
|
||||
return instructionIncrement(register, toImmediate<T>((n3)data));
|
||||
}
|
||||
case 0x68 ... 0x6f: { //DEC #3,r
|
||||
case range8(0x68, 0x6f): { //DEC #3,r
|
||||
prefetch(4);
|
||||
return instructionDecrement(register, toImmediate<T>((n3)data));
|
||||
}
|
||||
case 0x70 ... 0x7f: { //SCC cc,r
|
||||
case range16(0x70, 0x7f): { //SCC cc,r
|
||||
if constexpr(!Long) {
|
||||
prefetch(4);
|
||||
return instructionSetConditionCode((n4)data, register);
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x80 ... 0x87: { //ADD R,r
|
||||
case range8(0x80, 0x87): { //ADD R,r
|
||||
prefetch(4);
|
||||
return instructionAdd(toRegister3<T>(data), register);
|
||||
}
|
||||
case 0x88 ... 0x8f: { //LD R,r
|
||||
case range8(0x88, 0x8f): { //LD R,r
|
||||
prefetch(4);
|
||||
return instructionLoad(toRegister3<T>(data), register);
|
||||
}
|
||||
case 0x90 ... 0x97: { //ADC R,r
|
||||
case range8(0x90, 0x97): { //ADC R,r
|
||||
prefetch(4);
|
||||
return instructionAddCarry(toRegister3<T>(data), register);
|
||||
}
|
||||
case 0x98 ... 0x9f: { //LD r,R
|
||||
case range8(0x98, 0x9f): { //LD r,R
|
||||
prefetch(4);
|
||||
return instructionLoad(register, toRegister3<T>(data));
|
||||
}
|
||||
case 0xa0 ... 0xa7: { //SUB R,r
|
||||
case range8(0xa0, 0xa7): { //SUB R,r
|
||||
prefetch(4);
|
||||
return instructionSubtract(toRegister3<T>(data), register);
|
||||
}
|
||||
case 0xa8 ... 0xaf: { //LD r,#3
|
||||
case range8(0xa8, 0xaf): { //LD r,#3
|
||||
prefetch(4);
|
||||
return instructionLoad(register, toImmediate<T>((n3)data));
|
||||
}
|
||||
case 0xb0 ... 0xb7: { //SBC R,r
|
||||
case range8(0xb0, 0xb7): { //SBC R,r
|
||||
prefetch(4);
|
||||
return instructionSubtractBorrow(toRegister3<T>(data), register);
|
||||
}
|
||||
case 0xb8 ... 0xbf: { //EX R,r
|
||||
case range8(0xb8, 0xbf): { //EX R,r
|
||||
if constexpr(!Long) {
|
||||
prefetch(6);
|
||||
return instructionExchange(toRegister3<T>(data), register);
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0xc0 ... 0xc7: { //AND R,r
|
||||
case range8(0xc0, 0xc7): { //AND R,r
|
||||
prefetch(4);
|
||||
return instructionAnd(toRegister3<T>(data), register);
|
||||
}
|
||||
@@ -1098,18 +1098,18 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionCompare(register, immediate);
|
||||
}
|
||||
case 0xd0 ... 0xd7: { //XOR R,r
|
||||
case range8(0xd0, 0xd7): { //XOR R,r
|
||||
prefetch(4);
|
||||
return instructionXor(toRegister3<T>(data), register);
|
||||
}
|
||||
case 0xd8 ... 0xdf: { //CP r,#3
|
||||
case range8(0xd8, 0xdf): { //CP r,#3
|
||||
if constexpr(!Long) {
|
||||
prefetch(4);
|
||||
return instructionCompare(register, toImmediate<T>((n3)data));
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0xe0 ... 0xe7: { //OR R,r
|
||||
case range8(0xe0, 0xe7): { //OR R,r
|
||||
prefetch(4);
|
||||
return instructionOr(toRegister3<T>(data), register);
|
||||
}
|
||||
@@ -1153,7 +1153,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
|
||||
prefetch(6);
|
||||
return instructionShiftRightLogical(register, immediate);
|
||||
}
|
||||
case 0xf0 ... 0xf7: { //CP R,r
|
||||
case range8(0xf0, 0xf7): { //CP R,r
|
||||
prefetch(4);
|
||||
return instructionCompare(toRegister3<T>(data), register);
|
||||
}
|
||||
@@ -1201,7 +1201,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
|
||||
switch(data) {
|
||||
|
||||
case 0x00 ... 0x03: {
|
||||
case range4(0x00, 0x03): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x04: { //PUSH (mem)
|
||||
@@ -1228,7 +1228,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x08 ... 0x0f: {
|
||||
case range8(0x08, 0x0f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x10: { //LDI
|
||||
@@ -1301,19 +1301,19 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x1a ... 0x1f: {
|
||||
case range6(0x1a, 0x1f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x20 ... 0x27: { //LD R,(mem)
|
||||
case range8(0x20, 0x27): { //LD R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionLoad(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0x28 ... 0x2f: {
|
||||
case range8(0x28, 0x2f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x30 ... 0x37: { //EX (mem),R
|
||||
case range8(0x30, 0x37): { //EX (mem),R
|
||||
if constexpr(!Long) {
|
||||
prefetch(8);
|
||||
return instructionExchange(memory, toRegister3<T>(data));
|
||||
@@ -1391,7 +1391,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x40 ... 0x47: { //MUL R,(mem)
|
||||
case range8(0x40, 0x47): { //MUL R,(mem)
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(24);
|
||||
if constexpr(Word) prefetch(30);
|
||||
@@ -1399,7 +1399,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x48 ... 0x4f: { //MULS R,(mem)
|
||||
case range8(0x48, 0x4f): { //MULS R,(mem)
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(20);
|
||||
if constexpr(Word) prefetch(26);
|
||||
@@ -1407,7 +1407,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x50 ... 0x57: { //DIV R,(mem)
|
||||
case range8(0x50, 0x57): { //DIV R,(mem)
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(30);
|
||||
if constexpr(Word) prefetch(46);
|
||||
@@ -1415,7 +1415,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x58 ... 0x5f: { //DIVS R,(mem)
|
||||
case range8(0x58, 0x5f): { //DIVS R,(mem)
|
||||
if constexpr(!Long) {
|
||||
if constexpr(Byte) prefetch(36);
|
||||
if constexpr(Word) prefetch(52);
|
||||
@@ -1423,21 +1423,21 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x60 ... 0x67: { //INC #3,(mem)
|
||||
case range8(0x60, 0x67): { //INC #3,(mem)
|
||||
if constexpr(!Long) {
|
||||
prefetch(8);
|
||||
return instructionIncrement(memory, toImmediate<T>((n3)data));
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x68 ... 0x6f: { //DEC #3,(mem)
|
||||
case range8(0x68, 0x6f): { //DEC #3,(mem)
|
||||
if constexpr(!Long) {
|
||||
prefetch(8);
|
||||
return instructionDecrement(memory, toImmediate<T>((n3)data));
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x70 ... 0x77: {
|
||||
case range8(0x70, 0x77): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x78: { //RLC (mem)
|
||||
@@ -1496,97 +1496,97 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
|
||||
}
|
||||
return undefined();
|
||||
}
|
||||
case 0x80 ... 0x87: { //ADD R,(mem)
|
||||
case range8(0x80, 0x87): { //ADD R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionAdd(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0x88 ... 0x8f: { //ADD (mem),R
|
||||
case range8(0x88, 0x8f): { //ADD (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionAdd(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0x90 ... 0x97: { //ADC R,(mem)
|
||||
case range8(0x90, 0x97): { //ADC R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionAddCarry(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0x98 ... 0x9f: { //ADC (mem),R
|
||||
case range8(0x98, 0x9f): { //ADC (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionAddCarry(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0xa0 ... 0xa7: { //SUB R,(mem)
|
||||
case range8(0xa0, 0xa7): { //SUB R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionSubtract(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0xa8 ... 0xaf: { //SUB (mem),R
|
||||
case range8(0xa8, 0xaf): { //SUB (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionSubtract(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0xb0 ... 0xb7: { //SBC R,(mem)
|
||||
case range8(0xb0, 0xb7): { //SBC R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionSubtractBorrow(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0xb8 ... 0xbf: { //SBC (mem),R
|
||||
case range8(0xb8, 0xbf): { //SBC (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionSubtractBorrow(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0xc0 ... 0xc7: { //AND R,(mem)
|
||||
case range8(0xc0, 0xc7): { //AND R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionAnd(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0xc8 ... 0xcf: { //AND (mem),R
|
||||
case range8(0xc8, 0xcf): { //AND (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionAnd(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0xd0 ... 0xd7: { //XOR R,(mem)
|
||||
case range8(0xd0, 0xd7): { //XOR R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionXor(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0xd8 ... 0xdf: { //XOR (mem),R
|
||||
case range8(0xd8, 0xdf): { //XOR (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionXor(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0xe0 ... 0xe7: { //OR R,(mem)
|
||||
case range8(0xe0, 0xe7): { //OR R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionOr(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0xe8 ... 0xef: { //OR (mem),R
|
||||
case range8(0xe8, 0xef): { //OR (mem),R
|
||||
if constexpr(Byte) prefetch(8);
|
||||
if constexpr(Word) prefetch(8);
|
||||
if constexpr(Long) prefetch(12);
|
||||
return instructionOr(memory, toRegister3<T>(data));
|
||||
}
|
||||
case 0xf0 ... 0xf7: { //CP R,(mem)
|
||||
case range8(0xf0, 0xf7): { //CP R,(mem)
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
return instructionCompare(toRegister3<T>(data), memory);
|
||||
}
|
||||
case 0xf8 ... 0xff: { //CP (mem),R
|
||||
case range8(0xf8, 0xff): { //CP (mem),R
|
||||
if constexpr(Byte) prefetch(6);
|
||||
if constexpr(Word) prefetch(6);
|
||||
if constexpr(Long) prefetch(8);
|
||||
@@ -1628,7 +1628,7 @@ auto TLCS900H::instructionTargetMemory(n32 address) -> void {
|
||||
prefetch(10);
|
||||
return instructionPop(toMemory<n16>(address));
|
||||
}
|
||||
case 0x07 ... 0x13: {
|
||||
case range13(0x07, 0x13): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x14: { //LD.B (m),(nn)
|
||||
@@ -1644,10 +1644,10 @@ auto TLCS900H::instructionTargetMemory(n32 address) -> void {
|
||||
prefetch(12);
|
||||
return instructionLoad(toMemory<n16>(address), source);
|
||||
}
|
||||
case 0x17 ... 0x1f: {
|
||||
case range9(0x17, 0x1f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x20 ... 0x27: { //LDA.W R,mem
|
||||
case range8(0x20, 0x27): { //LDA.W R,mem
|
||||
prefetch(8);
|
||||
return instructionLoad(toRegister3<n16>(data), toImmediate<n16>(address));
|
||||
}
|
||||
@@ -1671,91 +1671,91 @@ auto TLCS900H::instructionTargetMemory(n32 address) -> void {
|
||||
prefetch(12);
|
||||
return instructionStoreCarry(toMemory<n8>(address), A);
|
||||
}
|
||||
case 0x2d ... 0x2f: {
|
||||
case range3(0x2d, 0x2f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x30 ... 0x37: { //LDA.L R,mem
|
||||
case range8(0x30, 0x37): { //LDA.L R,mem
|
||||
prefetch(8);
|
||||
return instructionLoad(toRegister3<n32>(data), toImmediate<n32>(address));
|
||||
}
|
||||
case 0x38 ... 0x3f: {
|
||||
case range8(0x38, 0x3f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x40 ... 0x47: { //LD.B (mem),R
|
||||
case range8(0x40, 0x47): { //LD.B (mem),R
|
||||
prefetch(6);
|
||||
return instructionLoad(toMemory<n8>(address), toRegister3<n8>(data));
|
||||
}
|
||||
case 0x48 ... 0x4f: {
|
||||
case range8(0x48, 0x4f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x50 ... 0x57: { //LD.W (mem),R
|
||||
case range8(0x50, 0x57): { //LD.W (mem),R
|
||||
prefetch(6);
|
||||
return instructionLoad(toMemory<n16>(address), toRegister3<n16>(data));
|
||||
}
|
||||
case 0x58 ... 0x5f: {
|
||||
case range8(0x58, 0x5f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x60 ... 0x67: { //LD.L (mem),R
|
||||
case range8(0x60, 0x67): { //LD.L (mem),R
|
||||
prefetch(8);
|
||||
return instructionLoad(toMemory<n32>(address), toRegister3<n32>(data));
|
||||
}
|
||||
case 0x68 ... 0x7f: {
|
||||
case range24(0x68, 0x7f): {
|
||||
return undefined();
|
||||
}
|
||||
case 0x80 ... 0x87: { //ANDCF #3,(mem)
|
||||
case range8(0x80, 0x87): { //ANDCF #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionAndCarry(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0x88 ... 0x8f: { //ORCF #3,(mem)
|
||||
case range8(0x88, 0x8f): { //ORCF #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionOrCarry(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0x90 ... 0x97: { //XORCF #3,(mem)
|
||||
case range8(0x90, 0x97): { //XORCF #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionXorCarry(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0x98 ... 0x9f: { //LDCF #3,(mem)
|
||||
case range8(0x98, 0x9f): { //LDCF #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionLoadCarry(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xa0 ... 0xa7: { //STCF #3,(mem)
|
||||
case range8(0xa0, 0xa7): { //STCF #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionStoreCarry(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xa8 ... 0xaf: { //TSET #3,(mem)
|
||||
case range8(0xa8, 0xaf): { //TSET #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionTestSet(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xb0 ... 0xb7: { //RES #3,(mem)
|
||||
case range8(0xb0, 0xb7): { //RES #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionReset(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xb8 ... 0xbf: { //SET #3,(mem)
|
||||
case range8(0xb8, 0xbf): { //SET #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionSet(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xc0 ... 0xc7: { //CHG #3,(mem)
|
||||
case range8(0xc0, 0xc7): { //CHG #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionChange(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xc8 ... 0xcf: { //BIT #3,(mem)
|
||||
case range8(0xc8, 0xcf): { //BIT #3,(mem)
|
||||
prefetch(10);
|
||||
return instructionBit(toMemory<n8>(address), toImmediate<n3>(data));
|
||||
}
|
||||
case 0xd0 ... 0xdf: { //JP cc,mem
|
||||
case range16(0xd0, 0xdf): { //JP cc,mem
|
||||
prefetch(8);
|
||||
if(!condition((n4)data)) return;
|
||||
prefetch(4);
|
||||
instructionJump(toImmediate<n32>(address));
|
||||
return prefetch(2);
|
||||
}
|
||||
case 0xe0 ... 0xef: { //CALL cc,mem
|
||||
case range16(0xe0, 0xef): { //CALL cc,mem
|
||||
if(!condition((n4)data)) return prefetch(8);
|
||||
prefetch(20);
|
||||
instructionCall(toImmediate<n32>(address));
|
||||
return prefetch(2);
|
||||
}
|
||||
case 0xf0 ... 0xff: { //RET cc
|
||||
case range16(0xf0, 0xff): { //RET cc
|
||||
if(!condition((n4)data)) return prefetch(8);
|
||||
prefetch(20);
|
||||
instructionReturn();
|
||||
|
||||
@@ -11,18 +11,23 @@ auto V30MZ::parity(u8 value) const -> bool {
|
||||
#define sign (size == Byte ? 0x80 : 0x8000)
|
||||
|
||||
template<u32 size> auto V30MZ::ADC(u16 x, u16 y) -> u16 {
|
||||
return ADD<size>(x, y + PSW.CY);
|
||||
return ADD<size>(x, y, PSW.CY);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::ADD(u16 x, u16 y) -> u16 {
|
||||
u16 result = (x + y) & mask;
|
||||
PSW.CY = x + y > mask;
|
||||
return ADD<size>(x, y, 0);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::ADD(u16 x, u16 y, u16 c) -> u16 {
|
||||
u32 result = x + y + c;
|
||||
PSW.CY = result > mask;
|
||||
result &= mask;
|
||||
PSW.P = parity(result);
|
||||
PSW.AC = (u4)x + (u4)y >= 16;
|
||||
PSW.AC = (u4)x + (u4)y + (u4)c >= 16;
|
||||
PSW.Z = result == 0;
|
||||
PSW.S = result & sign;
|
||||
PSW.V = (result ^ x) & (result ^ y) & sign;
|
||||
return result;
|
||||
return result & mask;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::AND(u16 x, u16 y) -> u16 {
|
||||
@@ -47,20 +52,20 @@ template<u32 size> auto V30MZ::DEC(u16 x) -> u16 {
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::DIVI(s32 x, s32 y) -> u32 {
|
||||
if(y == 0) return interrupt(0), x;
|
||||
if(y == 0) return interrupt(0, InterruptSource::CPU), x;
|
||||
x = size == Byte ? (s16)x : (s32)x;
|
||||
y = size == Byte ? ( s8)y : (s16)y;
|
||||
s32 quotient = x / y;
|
||||
s32 remainder = x % y;
|
||||
if(quotient > mask >> 1 || quotient < -sign) return interrupt(0), x;
|
||||
if(quotient > mask >> 1 || quotient < -sign) return interrupt(0, InterruptSource::CPU), x;
|
||||
return (remainder & mask) << bits | (quotient & mask);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::DIVU(u32 x, u32 y) -> u32 {
|
||||
if(y == 0) return interrupt(0), x;
|
||||
if(y == 0) return interrupt(0, InterruptSource::CPU), x;
|
||||
u32 quotient = x / y;
|
||||
u32 remainder = x % y;
|
||||
if(quotient > mask) return interrupt(0), x;
|
||||
if(quotient > mask) return interrupt(0, InterruptSource::CPU), x;
|
||||
return (remainder & mask) << bits | (quotient & mask);
|
||||
}
|
||||
|
||||
@@ -77,9 +82,14 @@ template<u32 size> auto V30MZ::INC(u16 x) -> u16 {
|
||||
template<u32 size> auto V30MZ::MULI(s16 x, s16 y) -> u32 {
|
||||
x = size == Byte ? (s8)x : (s16)x;
|
||||
y = size == Byte ? (s8)y : (s16)y;
|
||||
u32 result = x * y;
|
||||
PSW.CY = result >> bits;
|
||||
PSW.V = result >> bits;
|
||||
s32 result = x * y;
|
||||
s32 truncatedResult = size == Byte ? (s8)result : (s16)result;
|
||||
PSW.CY = result != truncatedResult;
|
||||
PSW.V = result != truncatedResult;
|
||||
PSW.P = 0; // undefined
|
||||
PSW.AC = 0; // undefined
|
||||
PSW.Z = 1; // undefined
|
||||
PSW.S = 0; // undefined
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -87,6 +97,10 @@ template<u32 size> auto V30MZ::MULU(u16 x, u16 y) -> u32 {
|
||||
u32 result = x * y;
|
||||
PSW.CY = result >> bits;
|
||||
PSW.V = result >> bits;
|
||||
PSW.P = 0; // undefined
|
||||
PSW.AC = 0; // undefined
|
||||
PSW.Z = 1; // undefined
|
||||
PSW.S = 0; // undefined
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -124,7 +138,7 @@ template<u32 size> auto V30MZ::RCL(u16 x, u5 y) -> u16 {
|
||||
result = (result << 1) | PSW.CY;
|
||||
PSW.CY = carry;
|
||||
}
|
||||
PSW.V = (x ^ result) & sign;
|
||||
PSW.V = (result ^ (PSW.CY << (bits - 1))) & sign;
|
||||
return result & mask;
|
||||
}
|
||||
|
||||
@@ -135,78 +149,81 @@ template<u32 size> auto V30MZ::RCR(u16 x, u5 y) -> u16 {
|
||||
result = (PSW.CY ? sign : 0) | (result >> 1);
|
||||
PSW.CY = carry;
|
||||
}
|
||||
PSW.V = (x ^ result) & sign;
|
||||
PSW.V = (result ^ (result << 1)) & sign;
|
||||
return result & mask;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::ROL(u16 x, u4 y) -> u16 {
|
||||
PSW.CY = (x << y) & (1 << bits);
|
||||
u16 result = ((x << y) | (x >> (bits - y))) & mask;
|
||||
PSW.V = (x ^ result) & sign;
|
||||
return result;
|
||||
template<u32 size> auto V30MZ::ROL(u16 x, u5 y) -> u16 {
|
||||
u16 result = x;
|
||||
for(u32 n = 0; n < y; n++) {
|
||||
PSW.CY = result & sign;
|
||||
result = (result << 1) | PSW.CY;
|
||||
}
|
||||
PSW.V = (result ^ (PSW.CY << (bits - 1))) & sign;
|
||||
return result & mask;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::ROR(u16 x, u4 y) -> u16 {
|
||||
PSW.CY = (x >> (y - 1)) & 1;
|
||||
u16 result = ((x >> y) | (x << (bits - y))) & mask;
|
||||
PSW.V = (x ^ result) & sign;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SAL(u16 x, u5 y) -> u16 {
|
||||
PSW.CY = (x << y) & (1 << bits);
|
||||
u16 result = (x << y) & mask;
|
||||
PSW.P = parity(result);
|
||||
PSW.Z = result == 0;
|
||||
PSW.S = result & sign;
|
||||
PSW.V = 0;
|
||||
return result;
|
||||
template<u32 size> auto V30MZ::ROR(u16 x, u5 y) -> u16 {
|
||||
u16 result = x;
|
||||
for(u32 n = 0; n < y; n++) {
|
||||
PSW.CY = result & 1;
|
||||
result = (PSW.CY ? sign : 0) | (result >> 1);
|
||||
}
|
||||
PSW.V = (result ^ (result << 1)) & sign;
|
||||
return result & mask;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SAR(u16 x, u5 y) -> u16 {
|
||||
if(y & 16) {
|
||||
PSW.CY = x & sign;
|
||||
return 0 - PSW.CY;
|
||||
u16 result = x;
|
||||
for(u32 n = 0; n < y; n++) {
|
||||
PSW.CY = result & 1;
|
||||
result = (result & sign) | (result >> 1);
|
||||
}
|
||||
PSW.CY = (x >> (y - 1)) & 1;
|
||||
u16 result = (x >> y) & mask;
|
||||
if(x & sign) result |= mask << (bits - y);
|
||||
result &= mask;
|
||||
PSW.AC = 0;
|
||||
PSW.P = parity(result);
|
||||
PSW.Z = result == 0;
|
||||
PSW.S = result & sign;
|
||||
PSW.V = 0;
|
||||
PSW.V = (result ^ (result << 1)) & sign;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SBB(u16 x, u16 y) -> u16 {
|
||||
return SUB<size>(x, y + PSW.CY);
|
||||
return SUB<size>(x, y, PSW.CY);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SHL(u16 x, u5 y) -> u16 {
|
||||
PSW.CY = (x << y) & (1 << bits);
|
||||
if(y != 0) PSW.CY = (x << y) & (1 << bits);
|
||||
u16 result = (x << y) & mask;
|
||||
PSW.AC = 0;
|
||||
PSW.P = parity(result);
|
||||
PSW.Z = result == 0;
|
||||
PSW.S = result & sign;
|
||||
PSW.V = (x ^ result) & sign;
|
||||
PSW.V = (result ^ (PSW.CY << (bits - 1))) & sign;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SHR(u16 x, u5 y) -> u16 {
|
||||
PSW.CY = (x >> (y - 1)) & 1;
|
||||
if(y != 0) PSW.CY = (x >> (y - 1)) & 1;
|
||||
u16 result = (x >> y) & mask;
|
||||
PSW.AC = 0;
|
||||
PSW.P = parity(result);
|
||||
PSW.Z = result == 0;
|
||||
PSW.S = result & sign;
|
||||
PSW.V = (x ^ result) & sign;
|
||||
PSW.V = (result ^ (result << 1)) & sign;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SUB(u16 x, u16 y) -> u16 {
|
||||
u16 result = (x - y) & mask;
|
||||
PSW.CY = y > x;
|
||||
return SUB<size>(x, y, 0);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::SUB(u16 x, u16 y, u16 c) -> u16 {
|
||||
s32 result = ((s32)x - (s32)y - (s32)c);
|
||||
PSW.CY = result < 0;
|
||||
result &= mask;
|
||||
PSW.P = parity(result);
|
||||
PSW.AC = (u4)y > (u4)x;
|
||||
PSW.AC = (((s16)(x & 0xF)) - ((s16)(y & 0xF)) - ((s16)(c & 0xF))) < 0;
|
||||
PSW.Z = result == 0;
|
||||
PSW.S = result & sign;
|
||||
PSW.V = (x ^ y) & (x ^ result) & sign;
|
||||
|
||||
@@ -6,7 +6,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
string output, repeat, prefix;
|
||||
|
||||
auto read = [&](u32 offset) -> n8 {
|
||||
return V30MZ::read<Byte>(ps, pc + offset);
|
||||
return this->read(ps * 16 + ((pc + offset) & 0xFFFF));
|
||||
};
|
||||
|
||||
auto modRM = [&](u32 offset = 1) -> u32 {
|
||||
@@ -379,7 +379,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
op(0xd3, group2(), memoryWord(), "cl");
|
||||
op(0xd4, "aam", immediateByte());
|
||||
op(0xd5, "aad", immediateByte());
|
||||
op(0xd6, "xlat"); //undocumented mirror
|
||||
op(0xd6, "salc");
|
||||
op(0xd7, "xlat");
|
||||
//op(0xd8);
|
||||
//op(0xd9);
|
||||
@@ -394,9 +394,9 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
op(0xe2, "loop");
|
||||
op(0xe3, "jcwz", relativeByte());
|
||||
op(0xe4, "in", "al", immediateByte());
|
||||
op(0xe5, "in", "aw", immediateWord());
|
||||
op(0xe5, "in", "aw", immediateByte());
|
||||
op(0xe6, "out", immediateByte(), "al");
|
||||
op(0xe7, "out", immediateWord(), "aw");
|
||||
op(0xe7, "out", immediateByte(), "aw");
|
||||
op(0xe8, "call", relativeWord());
|
||||
op(0xe9, "jmp", relativeWord());
|
||||
op(0xea, "jmp", immediateLong());
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
auto V30MZ::interrupt(u8 vector) -> void {
|
||||
wait(32);
|
||||
auto V30MZ::interrupt(u8 vector, InterruptSource source) -> bool {
|
||||
if(source == InterruptSource::INT) wait(32);
|
||||
else if (source == InterruptSource::NMI) wait(26);
|
||||
else wait(25);
|
||||
|
||||
state.halt = 0;
|
||||
state.poll = 1;
|
||||
@@ -17,16 +19,28 @@ auto V30MZ::interrupt(u8 vector) -> void {
|
||||
auto ps = read<Word>(0x0000, vector * 4 + 2);
|
||||
|
||||
push(PSW);
|
||||
push(PS);
|
||||
push(PC);
|
||||
|
||||
PSW.MD = 1;
|
||||
PSW.IE = 0;
|
||||
PSW.BRK = 0;
|
||||
|
||||
PC = pc;
|
||||
push(PS);
|
||||
PS = ps;
|
||||
push(PC);
|
||||
PC = pc;
|
||||
|
||||
flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto V30MZ::interrupt(u8 vector) -> bool {
|
||||
state.halt = false;
|
||||
if(!PSW.IE) return false;
|
||||
return interrupt(vector, InterruptSource::INT);
|
||||
}
|
||||
|
||||
auto V30MZ::nonMaskableInterrupt() -> bool {
|
||||
return interrupt(2, InterruptSource::NMI);
|
||||
}
|
||||
|
||||
#define op(id, name, ...) case id: instruction##name(__VA_ARGS__); break;
|
||||
@@ -52,7 +66,7 @@ auto V30MZ::instruction() -> void {
|
||||
op(0x0c, OrAccImm<Byte>)
|
||||
op(0x0d, OrAccImm<Word>)
|
||||
op(0x0e, PushSeg, PS)
|
||||
op(0x0f, PopSeg, PS)
|
||||
op(0x0f, Undefined)
|
||||
op(0x10, AdcMemReg<Byte>)
|
||||
op(0x11, AdcMemReg<Word>)
|
||||
op(0x12, AdcRegMem<Byte>)
|
||||
@@ -136,11 +150,11 @@ auto V30MZ::instruction() -> void {
|
||||
op(0x60, PushAll)
|
||||
op(0x61, PopAll)
|
||||
op(0x62, Bound)
|
||||
//op(0x63, ...)
|
||||
//op(0x64, ...) repnc
|
||||
//op(0x65, ...) repc
|
||||
//op(0x66, ...) fpo2
|
||||
//op(0x67, ...) fpo2
|
||||
op(0x63, Undefined)
|
||||
op(0x64, Undefined)
|
||||
op(0x65, Undefined)
|
||||
op(0x66, Undefined)
|
||||
op(0x67, Undefined)
|
||||
op(0x68, PushImm<Word>)
|
||||
op(0x69, MultiplySignedRegMemImm<Word>)
|
||||
op(0x6a, PushImm<Byte>)
|
||||
@@ -156,13 +170,13 @@ auto V30MZ::instruction() -> void {
|
||||
op(0x74, JumpIf, PSW.Z == 1)
|
||||
op(0x75, JumpIf, PSW.Z == 0)
|
||||
op(0x76, JumpIf, PSW.Z == 1 || PSW.CY == 1)
|
||||
op(0x77, JumpIf, PSW.Z != 1 && PSW.CY != 1)
|
||||
op(0x77, JumpIf, PSW.Z == 0 && PSW.CY == 0)
|
||||
op(0x78, JumpIf, PSW.S == 1)
|
||||
op(0x79, JumpIf, PSW.S == 0)
|
||||
op(0x7a, JumpIf, PSW.P == 1)
|
||||
op(0x7b, JumpIf, PSW.P == 0)
|
||||
op(0x7c, JumpIf, PSW.S != PSW.V && PSW.Z == 0)
|
||||
op(0x7d, JumpIf, PSW.S == PSW.V || PSW.Z == 1)
|
||||
op(0x7c, JumpIf, PSW.S != PSW.V)
|
||||
op(0x7d, JumpIf, PSW.S == PSW.V)
|
||||
op(0x7e, JumpIf, PSW.S != PSW.V || PSW.Z == 1)
|
||||
op(0x7f, JumpIf, PSW.S == PSW.V && PSW.Z == 0)
|
||||
op(0x80, Group1MemImm<Byte>, 0)
|
||||
@@ -251,16 +265,16 @@ auto V30MZ::instruction() -> void {
|
||||
op(0xd3, Group2MemImm<Word>, 3, (u8)CL)
|
||||
op(0xd4, AdjustAfterMultiply)
|
||||
op(0xd5, AdjustAfterDivide)
|
||||
op(0xd6, Translate, 7) //xlat (undocumented mirror)
|
||||
op(0xd7, Translate, 4) //xlat
|
||||
//op(0xd8, ...) //fpo1
|
||||
//op(0xd9, ...) //fpo1
|
||||
//op(0xda, ...) //fpo1
|
||||
//op(0xdb, ...) //fpo1
|
||||
//op(0xdc, ...) //fpo1
|
||||
//op(0xdd, ...) //fpo1
|
||||
//op(0xde, ...) //fpo1
|
||||
//op(0xdf, ...) //fpo1
|
||||
op(0xd6, SetALCarry) //salc
|
||||
op(0xd7, Translate) //xlat
|
||||
op(0xd8, Undefined1)
|
||||
op(0xd9, Undefined1)
|
||||
op(0xda, Undefined1)
|
||||
op(0xdb, Undefined1)
|
||||
op(0xdc, Undefined1)
|
||||
op(0xdd, Undefined1)
|
||||
op(0xde, Undefined1)
|
||||
op(0xdf, Undefined1)
|
||||
op(0xe0, LoopWhile, 0) //loopnz
|
||||
op(0xe1, LoopWhile, 1) //loopz
|
||||
op(0xe2, Loop)
|
||||
@@ -296,6 +310,7 @@ auto V30MZ::instruction() -> void {
|
||||
}
|
||||
|
||||
if(!state.prefix) prefixes.flush();
|
||||
if(PSW.BRK) interrupt(1, InterruptSource::SingleStep);
|
||||
}
|
||||
|
||||
#undef op
|
||||
@@ -1,13 +1,23 @@
|
||||
auto V30MZ::instructionDecimalAdjust(bool negate) -> void {
|
||||
wait(10 + negate);
|
||||
n8 al = AL;
|
||||
PSW.V = 0; // undefined
|
||||
if(PSW.AC || ((al & 0x0f) > 0x09)) {
|
||||
AL += negate ? -0x06 : 0x06;
|
||||
PSW.AC = 1;
|
||||
if(negate) PSW.V |= (al ^ 0x06) & (al ^ AL) & 0x80; // undefined
|
||||
else PSW.V |= (AL ^ al) & (AL ^ 0x06) & 0x80; // undefined
|
||||
} else {
|
||||
PSW.AC = 0;
|
||||
}
|
||||
if(PSW.CY || (al > 0x99)) {
|
||||
al = AL;
|
||||
AL += negate ? -0x60 : 0x60;
|
||||
PSW.CY = 1;
|
||||
if(negate) PSW.V |= (al ^ 0x06) & (al ^ AL) & 0x80; // undefined
|
||||
else PSW.V |= (AL ^ al) & (AL ^ 0x60) & 0x80; // undefined
|
||||
} else {
|
||||
PSW.CY = 0;
|
||||
}
|
||||
PSW.S = AL & 0x80;
|
||||
PSW.Z = AL == 0;
|
||||
@@ -21,19 +31,25 @@ auto V30MZ::instructionAsciiAdjust(bool negate) -> void {
|
||||
AH += negate ? -0x01 : 0x01;
|
||||
PSW.AC = 1;
|
||||
PSW.CY = 1;
|
||||
PSW.S = 0; // undefined
|
||||
PSW.Z = 1; // undefined
|
||||
} else {
|
||||
AL &= 0x0f;
|
||||
PSW.AC = 0;
|
||||
PSW.CY = 0;
|
||||
PSW.S = 1; // undefined
|
||||
PSW.Z = 0; // undefined
|
||||
}
|
||||
AL &= 0x0f;
|
||||
PSW.V = 0; // undefined
|
||||
PSW.P = 1; // undefined
|
||||
}
|
||||
|
||||
auto V30MZ::instructionAdjustAfterMultiply() -> void {
|
||||
wait(16);
|
||||
auto imm = fetch<Byte>();
|
||||
if(imm == 0) return interrupt(0);
|
||||
//NEC CPUs do not honor the immediate and always use (base) 10
|
||||
AH = AL / 10;
|
||||
if(imm == 0) { interrupt(0, InterruptSource::CPU); return; }
|
||||
AH = AL / imm;
|
||||
AL %= imm;
|
||||
PSW.P = parity(AL);
|
||||
PSW.S = AW & 0x8000;
|
||||
@@ -43,10 +59,6 @@ auto V30MZ::instructionAdjustAfterMultiply() -> void {
|
||||
auto V30MZ::instructionAdjustAfterDivide() -> void {
|
||||
wait(6);
|
||||
auto imm = fetch<Byte>();
|
||||
//NEC CPUs do not honor the immediate and always use (base) 10
|
||||
AL += AH * 10;
|
||||
AL = ADD<Byte>(AL, MULU<Byte>(AH, imm) & 0xFF, 0);
|
||||
AH = 0;
|
||||
PSW.P = parity(AL);
|
||||
PSW.S = AW & 0x8000;
|
||||
PSW.Z = AW == 0;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ template<u32 size> auto V30MZ::instructionTestMemReg() -> void {
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionMultiplySignedRegMemImm() -> void {
|
||||
wait(5);
|
||||
wait(3);
|
||||
modRM();
|
||||
setRegister<Word>(MULI<Word>(getMemory<Word>(), size == Word ? (s16)fetch<Word>() : (s8)fetch<Byte>()));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ auto V30MZ::instructionJumpIf(bool condition) -> void {
|
||||
wait(1);
|
||||
auto offset = (i8)fetch<Byte>();
|
||||
if(condition) {
|
||||
wait(3);
|
||||
wait(2);
|
||||
PC += offset;
|
||||
flush();
|
||||
}
|
||||
@@ -51,7 +51,7 @@ auto V30MZ::instructionJumpFar() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionCallNear() -> void {
|
||||
wait(4);
|
||||
wait(2);
|
||||
auto offset = (i16)fetch<Word>();
|
||||
push(PC);
|
||||
PC += offset;
|
||||
@@ -59,7 +59,7 @@ auto V30MZ::instructionCallNear() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionCallFar() -> void {
|
||||
wait(9);
|
||||
wait(6);
|
||||
auto pc = fetch<Word>();
|
||||
auto ps = fetch<Word>();
|
||||
push(PS);
|
||||
@@ -70,13 +70,13 @@ auto V30MZ::instructionCallFar() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionReturn() -> void {
|
||||
wait(5);
|
||||
wait(4);
|
||||
PC = pop();
|
||||
flush();
|
||||
}
|
||||
|
||||
auto V30MZ::instructionReturnImm() -> void {
|
||||
wait(5);
|
||||
wait(4);
|
||||
auto offset = fetch<Word>();
|
||||
PC = pop();
|
||||
SP += offset;
|
||||
@@ -84,14 +84,14 @@ auto V30MZ::instructionReturnImm() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionReturnFar() -> void {
|
||||
wait(7);
|
||||
wait(5);
|
||||
PC = pop();
|
||||
PS = pop();
|
||||
flush();
|
||||
}
|
||||
|
||||
auto V30MZ::instructionReturnFarImm() -> void {
|
||||
wait(8);
|
||||
wait(6);
|
||||
auto offset = fetch<Word>();
|
||||
PC = pop();
|
||||
PS = pop();
|
||||
@@ -100,7 +100,7 @@ auto V30MZ::instructionReturnFarImm() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionReturnInt() -> void {
|
||||
wait(9);
|
||||
wait(6);
|
||||
PC = pop();
|
||||
PS = pop();
|
||||
PSW = pop();
|
||||
@@ -109,18 +109,21 @@ auto V30MZ::instructionReturnInt() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionInt3() -> void {
|
||||
wait(8);
|
||||
interrupt(3);
|
||||
wait(9);
|
||||
interrupt(3, InterruptSource::CPU);
|
||||
}
|
||||
|
||||
auto V30MZ::instructionIntImm() -> void {
|
||||
wait(9);
|
||||
interrupt(fetch<Byte>());
|
||||
wait(10);
|
||||
interrupt(fetch<Byte>(), InterruptSource::CPU);
|
||||
}
|
||||
|
||||
auto V30MZ::instructionInto() -> void {
|
||||
wait(5);
|
||||
interrupt(4);
|
||||
wait(6);
|
||||
if(PSW.V) {
|
||||
wait(7);
|
||||
interrupt(4, InterruptSource::CPU);
|
||||
}
|
||||
}
|
||||
|
||||
auto V30MZ::instructionEnter() -> void {
|
||||
@@ -143,13 +146,15 @@ auto V30MZ::instructionEnter() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionLeave() -> void {
|
||||
wait(1);
|
||||
wait(2);
|
||||
SP = BP;
|
||||
BP = pop();
|
||||
}
|
||||
|
||||
auto V30MZ::instructionPushReg(u16& reg) -> void {
|
||||
push(reg);
|
||||
// Emulate the 8086/80186 "PUSH SP" bug.
|
||||
if(® == &SP) push(reg - 2);
|
||||
else push(reg);
|
||||
}
|
||||
|
||||
auto V30MZ::instructionPushSeg(u16& seg) -> void {
|
||||
|
||||
@@ -30,7 +30,7 @@ template<u32 size> auto V30MZ::instructionGroup2MemImm(u8 clocks, maybe<u8> imm)
|
||||
case 3: setMemory<size>(RCR<size>(mem, *imm)); break;
|
||||
case 4: setMemory<size>(SHL<size>(mem, *imm)); break;
|
||||
case 5: setMemory<size>(SHR<size>(mem, *imm)); break;
|
||||
case 6: setMemory<size>(SAL<size>(mem, *imm)); break;
|
||||
case 6: setMemory<size>(0); break; // undefined opcode
|
||||
case 7: setMemory<size>(SAR<size>(mem, *imm)); break;
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ template<u32 size> auto V30MZ::instructionGroup3MemImm() -> void {
|
||||
auto mem = getMemory<size>();
|
||||
switch(modrm.reg) {
|
||||
case 0: wait(1); AND<size>(mem, fetch<size>()); break; //TEST
|
||||
case 1: wait(1); AND<size>(mem, fetch<size>()); break; //TEST (undocumented mirror)
|
||||
case 1: wait(1); break; // undefined (acts as NOP)
|
||||
case 2: wait(1); setMemory<size>(NOT<size>(mem)); break;
|
||||
case 3: wait(1); setMemory<size>(NEG<size>(mem)); break;
|
||||
case 4: wait(3); setAccumulator<size * 2>(MULU<size>(getAccumulator<size>(), mem)); break;
|
||||
@@ -62,13 +62,13 @@ template<u32 size> auto V30MZ::instructionGroup4MemImm() -> void {
|
||||
setMemory<size>(DEC<size>(getMemory<size>()));
|
||||
break;
|
||||
case 2: //CALL
|
||||
wait(5);
|
||||
wait(3);
|
||||
push(PC);
|
||||
PC = getMemory<Word>();
|
||||
flush();
|
||||
break;
|
||||
case 3: //CALLF
|
||||
wait(11);
|
||||
wait(7);
|
||||
push(PS);
|
||||
push(PC);
|
||||
PC = getMemory<Word>(0);
|
||||
@@ -89,8 +89,8 @@ template<u32 size> auto V30MZ::instructionGroup4MemImm() -> void {
|
||||
case 6: //PUSH
|
||||
push(getMemory<Word>());
|
||||
break;
|
||||
case 7: //PUSH (undocumented mirror)
|
||||
push(getMemory<Word>());
|
||||
case 7: //undefined opcode
|
||||
wait(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,11 @@ auto V30MZ::instructionLock() -> void {
|
||||
}
|
||||
|
||||
auto V30MZ::instructionWait() -> void {
|
||||
wait(1);
|
||||
wait(10);
|
||||
}
|
||||
|
||||
auto V30MZ::instructionHalt() -> void {
|
||||
wait(8);
|
||||
wait(9);
|
||||
state.halt = 1;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,15 @@ auto V30MZ::instructionNop() -> void {
|
||||
wait(1);
|
||||
}
|
||||
|
||||
auto V30MZ::instructionUndefined() -> void {
|
||||
wait(1);
|
||||
}
|
||||
|
||||
auto V30MZ::instructionUndefined1() -> void {
|
||||
wait(1);
|
||||
fetch<Byte>();
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionIn() -> void {
|
||||
wait(6);
|
||||
setAccumulator<size>(in<size>(fetch<Byte>()));
|
||||
@@ -44,17 +53,22 @@ template<u32 size> auto V30MZ::instructionOut() -> void {
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionInDW() -> void {
|
||||
wait(4);
|
||||
wait(5);
|
||||
setAccumulator<size>(in<size>(DW));
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionOutDW() -> void {
|
||||
wait(4);
|
||||
wait(5);
|
||||
out<size>(DW, getAccumulator<size>());
|
||||
}
|
||||
|
||||
auto V30MZ::instructionTranslate(u8 clocks) -> void {
|
||||
wait(clocks);
|
||||
auto V30MZ::instructionSetALCarry() -> void {
|
||||
wait(8);
|
||||
AL = PSW.CY ? 0xFF : 0x00;
|
||||
}
|
||||
|
||||
auto V30MZ::instructionTranslate() -> void {
|
||||
wait(4);
|
||||
AL = read<Byte>(segment(DS0), BW + AL);
|
||||
}
|
||||
|
||||
@@ -64,5 +78,5 @@ auto V30MZ::instructionBound() -> void {
|
||||
auto lo = getMemory<Word>(0);
|
||||
auto hi = getMemory<Word>(2);
|
||||
auto reg = getRegister<Word>();
|
||||
if(reg < lo || reg > hi) interrupt(5);
|
||||
if(reg < lo || reg > hi) interrupt(5, InterruptSource::CPU);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
template<u32 size> auto V30MZ::instructionInString() -> void {
|
||||
wait(5);
|
||||
wait(3);
|
||||
if(!repeat() || CW) {
|
||||
auto data = in<size>(DW);
|
||||
write<size>(DS1, IY, data);
|
||||
@@ -14,7 +14,7 @@ template<u32 size> auto V30MZ::instructionInString() -> void {
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionOutString() -> void {
|
||||
wait(6);
|
||||
wait(3);
|
||||
if(!repeat() || CW) {
|
||||
auto data = read<size>(segment(DS0), IX);
|
||||
out<size>(DW, data);
|
||||
|
||||
@@ -1,36 +1,41 @@
|
||||
template<> auto V30MZ::read<Byte>(u16 segment, u16 address) -> u32 {
|
||||
step(1);
|
||||
step(speed(segment * 16 + address));
|
||||
u32 data = 0;
|
||||
data |= read(segment * 16 + address++) << 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
template<> auto V30MZ::read<Word>(u16 segment, u16 address) -> u32 {
|
||||
step(1 + (address & 1));
|
||||
u32 data = 0;
|
||||
step(speed(segment * 16 + address));
|
||||
data |= read(segment * 16 + address++) << 0;
|
||||
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
|
||||
data |= read(segment * 16 + address++) << 8;
|
||||
return data;
|
||||
}
|
||||
|
||||
template<> auto V30MZ::read<Long>(u16 segment, u16 address) -> u32 {
|
||||
step(2 + (address & 1));
|
||||
u32 data = 0;
|
||||
step(speed(segment * 16 + address));
|
||||
data |= read(segment * 16 + address++) << 0;
|
||||
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
|
||||
data |= read(segment * 16 + address++) << 8;
|
||||
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
|
||||
data |= read(segment * 16 + address++) << 16;
|
||||
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
|
||||
data |= read(segment * 16 + address++) << 24;
|
||||
return data;
|
||||
}
|
||||
|
||||
template<> auto V30MZ::write<Byte>(u16 segment, u16 address, u16 data) -> void {
|
||||
step(1);
|
||||
step(speed(segment * 16 + address));
|
||||
write(segment * 16 + address++, data >> 0);
|
||||
}
|
||||
|
||||
template<> auto V30MZ::write<Word>(u16 segment, u16 address, u16 data) -> void {
|
||||
step(1 + (address & 1));
|
||||
step(speed(segment * 16 + address));
|
||||
write(segment * 16 + address++, data >> 0);
|
||||
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
|
||||
write(segment * 16 + address++, data >> 8);
|
||||
}
|
||||
|
||||
@@ -42,9 +47,10 @@ template<> auto V30MZ::in<Byte>(u16 address) -> u16 {
|
||||
}
|
||||
|
||||
template<> auto V30MZ::in<Word>(u16 address) -> u16 {
|
||||
step(1 + (address & 1));
|
||||
u16 data = 0;
|
||||
step(1);
|
||||
data |= in(address++) << 0;
|
||||
if(!(address & 1)) step(1);
|
||||
data |= in(address++) << 8;
|
||||
return data;
|
||||
}
|
||||
@@ -55,8 +61,9 @@ template<> auto V30MZ::out<Byte>(u16 address, u16 data) -> void {
|
||||
}
|
||||
|
||||
template<> auto V30MZ::out<Word>(u16 address, u16 data) -> void {
|
||||
step(1 + (address & 1));
|
||||
step(1);
|
||||
out(address++, data >> 0);
|
||||
if(!(address & 1)) step(1);
|
||||
out(address++, data >> 8);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,16 @@ auto V30MZ::modRM() -> void {
|
||||
modrm.reg = data >> 3 & 7;
|
||||
modrm.mod = data >> 6 & 3;
|
||||
|
||||
if(modrm.mod == 3) return;
|
||||
if(modrm.mod == 0 && modrm.mem == 6) {
|
||||
modrm.segment = segment(DS0);
|
||||
modrm.address = fetch<Word>();
|
||||
} else {
|
||||
switch(modrm.mem) {
|
||||
case 0: modrm.segment = segment(DS0); modrm.address = BW + IX; break;
|
||||
case 1: modrm.segment = segment(DS0); modrm.address = BW + IY; break;
|
||||
case 2: modrm.segment = segment(SS ); modrm.address = BP + IX; break;
|
||||
case 3: modrm.segment = segment(SS ); modrm.address = BP + IY; break;
|
||||
case 0: modrm.segment = segment(DS0); modrm.address = BW + IX; wait(1); break;
|
||||
case 1: modrm.segment = segment(DS0); modrm.address = BW + IY; wait(1); break;
|
||||
case 2: modrm.segment = segment(SS ); modrm.address = BP + IX; wait(1); break;
|
||||
case 3: modrm.segment = segment(SS ); modrm.address = BP + IY; wait(1); break;
|
||||
case 4: modrm.segment = segment(DS0); modrm.address = IX; break;
|
||||
case 5: modrm.segment = segment(DS0); modrm.address = IY; break;
|
||||
case 6: modrm.segment = segment(SS ); modrm.address = BP; break;
|
||||
|
||||
@@ -15,25 +15,30 @@ auto V30MZ::loop() -> void {
|
||||
auto V30MZ::flush() -> void {
|
||||
PF.flush();
|
||||
PFP = PC;
|
||||
if(PFP & 1) step(1);
|
||||
PFW = 0;
|
||||
}
|
||||
|
||||
auto V30MZ::prefetch() -> void {
|
||||
step(1);
|
||||
switch(PFP & 1) {
|
||||
case 0: if(PF.full()) break; PF.write(read(PS * 16 + PFP++)); //fallthrough
|
||||
case 1: if(PF.full()) break; PF.write(read(PS * 16 + PFP++));
|
||||
}
|
||||
auto address = PS * 16 + PFP;
|
||||
auto size = width(address);
|
||||
auto wait = speed(address);
|
||||
if(++PFW < wait) return;
|
||||
PFW -= wait;
|
||||
if(size == Word && !(PFP & 1)) if(!PF.full()) PF.write(read(PS * 16 + PFP++));
|
||||
if(!PF.full()) PF.write(read(PS * 16 + PFP++));
|
||||
}
|
||||
|
||||
template<> auto V30MZ::fetch<Byte>() -> u16 {
|
||||
PC++;
|
||||
if(PF.empty()) prefetch();
|
||||
while(PF.size() < 2) prefetch();
|
||||
return PF.read(0);
|
||||
}
|
||||
|
||||
template<> auto V30MZ::fetch<Word>() -> u16 {
|
||||
u8 lo = fetch<Byte>();
|
||||
u8 hi = fetch<Byte>();
|
||||
PC += 2;
|
||||
while(PF.size() < 2) prefetch();
|
||||
u8 lo = PF.read(0);
|
||||
u8 hi = PF.read(0);
|
||||
return lo << 0 | hi << 8;
|
||||
}
|
||||
@@ -1,45 +1,14 @@
|
||||
//NEC V30MZ (reduced functionality NEC V30 for embedded use)
|
||||
//NEC V30MZ (optimized and more 80186-compatible NEC V30)
|
||||
|
||||
//V30 missing instructions:
|
||||
// 0f 10,11,18,19 test1
|
||||
// 0f 12,13,1a,1b clr1
|
||||
// 0f 14,15,1c,1d set1
|
||||
// 0f 16,17,1e,1f not1
|
||||
// 0f 20 add4s
|
||||
// 0f 22 sub4s
|
||||
// 0f 26 cmp4s
|
||||
// 0f 28 rol4
|
||||
// 0f 2a ror4
|
||||
// 0f 31,39 ins
|
||||
// 0f 33,3b ext
|
||||
// 0f ff brkem (8080 emulation mode) [retem, calln]
|
||||
// 64 repnc
|
||||
// 65 repc
|
||||
// 66,67 fpo2
|
||||
// d8-df fpo1
|
||||
|
||||
//x86 variant instructions:
|
||||
// 8f c0-c7 pop reg [CPU bug: pops from stack; fails to set register]
|
||||
// d4 xx aam [ignores the immediate; always uses (base) 10]
|
||||
// d5 xx aad [ignores the immediate; always uses (base) 10]
|
||||
// d6 xlat (mirror of d7) [this is salc on x86 CPUs]
|
||||
// f1 ??? [this is int 0x1 on x86 CPUs; said to be a two-byte NOP on V20; unknown on V30/V30MZ]
|
||||
// ff f8-ff push (mirror of ff f0-f7)
|
||||
//does not contain V20/V30 extended instructions
|
||||
|
||||
//x86 unemulated variation:
|
||||
// after interrupts, NEC V20/V30 CPUs resume string instructions with prefixes intact. unlike x86 CPUs
|
||||
// I need more information on this behavior in order to emulate it ...
|
||||
// also, the opcode f1 behavior is not currently known
|
||||
|
||||
//V30 opcode prefix functionality:
|
||||
//V30MZ opcode prefix functionality:
|
||||
// there is a seven-level stack for opcode prefixes. once full, older prefixes are pushed off the stack
|
||||
|
||||
//other notes:
|
||||
// 0f pop cs (not nop) [on the V20; the V30 uses this for instruction extensions; unsure on the V30MZ]
|
||||
// 8e xx mov cs,modRM (works as expected; able to set CS)
|
||||
|
||||
//I currently emulate opcode 0f as pop cs, although it's unknown if that is correct.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
@@ -57,6 +26,8 @@ struct V30MZ {
|
||||
};
|
||||
|
||||
virtual auto step(u32 clocks = 1) -> void = 0;
|
||||
virtual auto width(n20 address) -> u32 = 0;
|
||||
virtual auto speed(n20 address) -> n32 = 0;
|
||||
virtual auto read(n20 address) -> n8 = 0;
|
||||
virtual auto write(n20 address, n8 data) -> void = 0;
|
||||
virtual auto in(n16 port) -> n8 = 0;
|
||||
@@ -66,7 +37,8 @@ struct V30MZ {
|
||||
auto power() -> void;
|
||||
|
||||
//instruction.cpp
|
||||
auto interrupt(u8 vector) -> void;
|
||||
auto interrupt(u8 vector) -> bool;
|
||||
auto nonMaskableInterrupt() -> bool;
|
||||
auto instruction() -> void;
|
||||
|
||||
//registers.cpp
|
||||
@@ -121,9 +93,8 @@ struct V30MZ {
|
||||
template<u32> auto OR (u16, u16) -> u16;
|
||||
template<u32> auto RCL (u16, u5 ) -> u16;
|
||||
template<u32> auto RCR (u16, u5 ) -> u16;
|
||||
template<u32> auto ROL (u16, u4 ) -> u16;
|
||||
template<u32> auto ROR (u16, u4 ) -> u16;
|
||||
template<u32> auto SAL (u16, u5 ) -> u16;
|
||||
template<u32> auto ROL (u16, u5 ) -> u16;
|
||||
template<u32> auto ROR (u16, u5 ) -> u16;
|
||||
template<u32> auto SAR (u16, u5 ) -> u16;
|
||||
template<u32> auto SBB (u16, u16) -> u16;
|
||||
template<u32> auto SUB (u16, u16) -> u16;
|
||||
@@ -220,11 +191,14 @@ struct V30MZ {
|
||||
auto instructionWait() -> void;
|
||||
auto instructionHalt() -> void;
|
||||
auto instructionNop() -> void;
|
||||
auto instructionUndefined() -> void;
|
||||
auto instructionUndefined1() -> void;
|
||||
template<u32> auto instructionIn() -> void;
|
||||
template<u32> auto instructionOut() -> void;
|
||||
template<u32> auto instructionInDW() -> void;
|
||||
template<u32> auto instructionOutDW() -> void;
|
||||
auto instructionTranslate(u8) -> void;
|
||||
auto instructionTranslate() -> void;
|
||||
auto instructionSetALCarry() -> void;
|
||||
auto instructionBound() -> void;
|
||||
|
||||
//instructions-move.cpp
|
||||
@@ -292,6 +266,7 @@ struct V30MZ {
|
||||
u16 PC; //IP
|
||||
u16 PFP; //prefetch pointer
|
||||
queue<u8[16]> PF; //prefetch queue
|
||||
n8 PFW; //prefetch wait time
|
||||
|
||||
struct ProgramStatusWord {
|
||||
u16 data;
|
||||
@@ -316,6 +291,22 @@ struct V30MZ {
|
||||
u8* const RB[8]{&AL, &CL, &DL, &BL, &AH, &CH, &DH, &BH };
|
||||
u16* const RW[8]{&AW, &CW, &DW, &BW, &SP, &BP, &IX, &IY };
|
||||
u16* const RS[8]{&DS1, &PS, &SS, &DS0, &DS1, &PS, &SS, &DS0};
|
||||
|
||||
protected:
|
||||
// TODO: implement interrupt priorities
|
||||
enum class InterruptSource : u32 {
|
||||
CPU = 1, // internal request
|
||||
NMI = 2, // external NMI
|
||||
INT = 3, // external interrupt request
|
||||
SingleStep = 4 // internal request - single step
|
||||
};
|
||||
|
||||
// algorithms.cpp
|
||||
template<u32> auto ADD (u16, u16, u16) -> u16;
|
||||
template<u32> auto SUB (u16, u16, u16) -> u16;
|
||||
|
||||
// instruction.cpp
|
||||
auto interrupt(u8 vector, InterruptSource source) -> bool;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -17,9 +17,10 @@ auto Z80::instruction() -> void {
|
||||
|
||||
if(code == 0xcb && prefix != Prefix::hl) {
|
||||
WZ = HL + (i8)operand();
|
||||
wait(2); //+1 fetch, +1 memory read
|
||||
n8 opcd = operand(); // pseudo opcode fetch (3 cycles)
|
||||
wait(2);
|
||||
//R is not incremented here
|
||||
instructionCBd(WZ, opcode());
|
||||
instructionCBd(WZ, opcd);
|
||||
} else if(code == 0xcb) {
|
||||
R.bit(0,6)++;
|
||||
instructionCB(opcode());
|
||||
@@ -242,7 +243,7 @@ auto Z80::instruction(n8 code) -> void {
|
||||
op(0xca, JP_c_nn, ZF == 1)
|
||||
//op(0xcb, cb:)
|
||||
op(0xcc, CALL_c_nn, ZF == 1)
|
||||
op(0xcd, CALL_nn)
|
||||
op(0xcd, CALL_c_nn, true)
|
||||
op(0xce, ADC_a_n)
|
||||
op(0xcf, RST_o, 1)
|
||||
op(0xd0, RET_c, CF == 0)
|
||||
@@ -297,6 +298,8 @@ auto Z80::instruction(n8 code) -> void {
|
||||
}
|
||||
|
||||
auto Z80::instructionCB(n8 code) -> void {
|
||||
n8 _;
|
||||
|
||||
switch(code) {
|
||||
op(0x00, RLC_r, B)
|
||||
op(0x01, RLC_r, C)
|
||||
@@ -304,7 +307,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x03, RLC_r, E)
|
||||
op(0x04, RLC_r, H)
|
||||
op(0x05, RLC_r, L)
|
||||
op(0x06, RLC_irr, _HL)
|
||||
op(0x06, RLC_irr_r, _HL, _)
|
||||
op(0x07, RLC_r, A)
|
||||
op(0x08, RRC_r, B)
|
||||
op(0x09, RRC_r, C)
|
||||
@@ -312,7 +315,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x0b, RRC_r, E)
|
||||
op(0x0c, RRC_r, H)
|
||||
op(0x0d, RRC_r, L)
|
||||
op(0x0e, RRC_irr, _HL)
|
||||
op(0x0e, RRC_irr_r, _HL, _)
|
||||
op(0x0f, RRC_r, A)
|
||||
op(0x10, RL_r, B)
|
||||
op(0x11, RL_r, C)
|
||||
@@ -320,7 +323,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x13, RL_r, E)
|
||||
op(0x14, RL_r, H)
|
||||
op(0x15, RL_r, L)
|
||||
op(0x16, RL_irr, _HL)
|
||||
op(0x16, RL_irr_r, _HL, _)
|
||||
op(0x17, RL_r, A)
|
||||
op(0x18, RR_r, B)
|
||||
op(0x19, RR_r, C)
|
||||
@@ -328,7 +331,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x1b, RR_r, E)
|
||||
op(0x1c, RR_r, H)
|
||||
op(0x1d, RR_r, L)
|
||||
op(0x1e, RR_irr, _HL)
|
||||
op(0x1e, RR_irr_r, _HL, _)
|
||||
op(0x1f, RR_r, A)
|
||||
op(0x20, SLA_r, B)
|
||||
op(0x21, SLA_r, C)
|
||||
@@ -336,7 +339,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x23, SLA_r, E)
|
||||
op(0x24, SLA_r, H)
|
||||
op(0x25, SLA_r, L)
|
||||
op(0x26, SLA_irr, _HL)
|
||||
op(0x26, SLA_irr_r, _HL, _)
|
||||
op(0x27, SLA_r, A)
|
||||
op(0x28, SRA_r, B)
|
||||
op(0x29, SRA_r, C)
|
||||
@@ -344,7 +347,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x2b, SRA_r, E)
|
||||
op(0x2c, SRA_r, H)
|
||||
op(0x2d, SRA_r, L)
|
||||
op(0x2e, SRA_irr, _HL)
|
||||
op(0x2e, SRA_irr_r, _HL, _)
|
||||
op(0x2f, SRA_r, A)
|
||||
op(0x30, SLL_r, B)
|
||||
op(0x31, SLL_r, C)
|
||||
@@ -352,7 +355,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x33, SLL_r, E)
|
||||
op(0x34, SLL_r, H)
|
||||
op(0x35, SLL_r, L)
|
||||
op(0x36, SLL_irr, _HL)
|
||||
op(0x36, SLL_irr_r, _HL, _)
|
||||
op(0x37, SLL_r, A)
|
||||
op(0x38, SRL_r, B)
|
||||
op(0x39, SRL_r, C)
|
||||
@@ -360,7 +363,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x3b, SRL_r, E)
|
||||
op(0x3c, SRL_r, H)
|
||||
op(0x3d, SRL_r, L)
|
||||
op(0x3e, SRL_irr, _HL)
|
||||
op(0x3e, SRL_irr_r, _HL, _)
|
||||
op(0x3f, SRL_r, A)
|
||||
op(0x40, BIT_o_r, 0, B)
|
||||
op(0x41, BIT_o_r, 0, C)
|
||||
@@ -368,7 +371,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x43, BIT_o_r, 0, E)
|
||||
op(0x44, BIT_o_r, 0, H)
|
||||
op(0x45, BIT_o_r, 0, L)
|
||||
op(0x46, BIT_o_irr, 0, _HL)
|
||||
op(0x46, BIT_o_irr_r, 0, _HL, _)
|
||||
op(0x47, BIT_o_r, 0, A)
|
||||
op(0x48, BIT_o_r, 1, B)
|
||||
op(0x49, BIT_o_r, 1, C)
|
||||
@@ -376,7 +379,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x4b, BIT_o_r, 1, E)
|
||||
op(0x4c, BIT_o_r, 1, H)
|
||||
op(0x4d, BIT_o_r, 1, L)
|
||||
op(0x4e, BIT_o_irr, 1, _HL)
|
||||
op(0x4e, BIT_o_irr_r, 1, _HL, _)
|
||||
op(0x4f, BIT_o_r, 1, A)
|
||||
op(0x50, BIT_o_r, 2, B)
|
||||
op(0x51, BIT_o_r, 2, C)
|
||||
@@ -384,7 +387,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x53, BIT_o_r, 2, E)
|
||||
op(0x54, BIT_o_r, 2, H)
|
||||
op(0x55, BIT_o_r, 2, L)
|
||||
op(0x56, BIT_o_irr, 2, _HL)
|
||||
op(0x56, BIT_o_irr_r, 2, _HL, _)
|
||||
op(0x57, BIT_o_r, 2, A)
|
||||
op(0x58, BIT_o_r, 3, B)
|
||||
op(0x59, BIT_o_r, 3, C)
|
||||
@@ -392,7 +395,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x5b, BIT_o_r, 3, E)
|
||||
op(0x5c, BIT_o_r, 3, H)
|
||||
op(0x5d, BIT_o_r, 3, L)
|
||||
op(0x5e, BIT_o_irr, 3, _HL)
|
||||
op(0x5e, BIT_o_irr_r, 3, _HL, _)
|
||||
op(0x5f, BIT_o_r, 3, A)
|
||||
op(0x60, BIT_o_r, 4, B)
|
||||
op(0x61, BIT_o_r, 4, C)
|
||||
@@ -400,7 +403,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x63, BIT_o_r, 4, E)
|
||||
op(0x64, BIT_o_r, 4, H)
|
||||
op(0x65, BIT_o_r, 4, L)
|
||||
op(0x66, BIT_o_irr, 4, _HL)
|
||||
op(0x66, BIT_o_irr_r, 4, _HL, _)
|
||||
op(0x67, BIT_o_r, 4, A)
|
||||
op(0x68, BIT_o_r, 5, B)
|
||||
op(0x69, BIT_o_r, 5, C)
|
||||
@@ -408,7 +411,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x6b, BIT_o_r, 5, E)
|
||||
op(0x6c, BIT_o_r, 5, H)
|
||||
op(0x6d, BIT_o_r, 5, L)
|
||||
op(0x6e, BIT_o_irr, 5, _HL)
|
||||
op(0x6e, BIT_o_irr_r, 5, _HL, _)
|
||||
op(0x6f, BIT_o_r, 5, A)
|
||||
op(0x70, BIT_o_r, 6, B)
|
||||
op(0x71, BIT_o_r, 6, C)
|
||||
@@ -416,7 +419,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x73, BIT_o_r, 6, E)
|
||||
op(0x74, BIT_o_r, 6, H)
|
||||
op(0x75, BIT_o_r, 6, L)
|
||||
op(0x76, BIT_o_irr, 6, _HL)
|
||||
op(0x76, BIT_o_irr_r, 6, _HL, _)
|
||||
op(0x77, BIT_o_r, 6, A)
|
||||
op(0x78, BIT_o_r, 7, B)
|
||||
op(0x79, BIT_o_r, 7, C)
|
||||
@@ -424,7 +427,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x7b, BIT_o_r, 7, E)
|
||||
op(0x7c, BIT_o_r, 7, H)
|
||||
op(0x7d, BIT_o_r, 7, L)
|
||||
op(0x7e, BIT_o_irr, 7, _HL)
|
||||
op(0x7e, BIT_o_irr_r, 7, _HL, _)
|
||||
op(0x7f, BIT_o_r, 7, A)
|
||||
op(0x80, RES_o_r, 0, B)
|
||||
op(0x81, RES_o_r, 0, C)
|
||||
@@ -432,7 +435,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x83, RES_o_r, 0, E)
|
||||
op(0x84, RES_o_r, 0, H)
|
||||
op(0x85, RES_o_r, 0, L)
|
||||
op(0x86, RES_o_irr, 0, _HL)
|
||||
op(0x86, RES_o_irr_r, 0, _HL, _)
|
||||
op(0x87, RES_o_r, 0, A)
|
||||
op(0x88, RES_o_r, 1, B)
|
||||
op(0x89, RES_o_r, 1, C)
|
||||
@@ -440,7 +443,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x8b, RES_o_r, 1, E)
|
||||
op(0x8c, RES_o_r, 1, H)
|
||||
op(0x8d, RES_o_r, 1, L)
|
||||
op(0x8e, RES_o_irr, 1, _HL)
|
||||
op(0x8e, RES_o_irr_r, 1, _HL, _)
|
||||
op(0x8f, RES_o_r, 1, A)
|
||||
op(0x90, RES_o_r, 2, B)
|
||||
op(0x91, RES_o_r, 2, C)
|
||||
@@ -448,7 +451,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x93, RES_o_r, 2, E)
|
||||
op(0x94, RES_o_r, 2, H)
|
||||
op(0x95, RES_o_r, 2, L)
|
||||
op(0x96, RES_o_irr, 2, _HL)
|
||||
op(0x96, RES_o_irr_r, 2, _HL, _)
|
||||
op(0x97, RES_o_r, 2, A)
|
||||
op(0x98, RES_o_r, 3, B)
|
||||
op(0x99, RES_o_r, 3, C)
|
||||
@@ -456,7 +459,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0x9b, RES_o_r, 3, E)
|
||||
op(0x9c, RES_o_r, 3, H)
|
||||
op(0x9d, RES_o_r, 3, L)
|
||||
op(0x9e, RES_o_irr, 3, _HL)
|
||||
op(0x9e, RES_o_irr_r, 3, _HL, _)
|
||||
op(0x9f, RES_o_r, 3, A)
|
||||
op(0xa0, RES_o_r, 4, B)
|
||||
op(0xa1, RES_o_r, 4, C)
|
||||
@@ -464,7 +467,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xa3, RES_o_r, 4, E)
|
||||
op(0xa4, RES_o_r, 4, H)
|
||||
op(0xa5, RES_o_r, 4, L)
|
||||
op(0xa6, RES_o_irr, 4, _HL)
|
||||
op(0xa6, RES_o_irr_r, 4, _HL, _)
|
||||
op(0xa7, RES_o_r, 4, A)
|
||||
op(0xa8, RES_o_r, 5, B)
|
||||
op(0xa9, RES_o_r, 5, C)
|
||||
@@ -472,7 +475,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xab, RES_o_r, 5, E)
|
||||
op(0xac, RES_o_r, 5, H)
|
||||
op(0xad, RES_o_r, 5, L)
|
||||
op(0xae, RES_o_irr, 5, _HL)
|
||||
op(0xae, RES_o_irr_r, 5, _HL, _)
|
||||
op(0xaf, RES_o_r, 5, A)
|
||||
op(0xb0, RES_o_r, 6, B)
|
||||
op(0xb1, RES_o_r, 6, C)
|
||||
@@ -480,7 +483,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xb3, RES_o_r, 6, E)
|
||||
op(0xb4, RES_o_r, 6, H)
|
||||
op(0xb5, RES_o_r, 6, L)
|
||||
op(0xb6, RES_o_irr, 6, _HL)
|
||||
op(0xb6, RES_o_irr_r, 6, _HL, _)
|
||||
op(0xb7, RES_o_r, 6, A)
|
||||
op(0xb8, RES_o_r, 7, B)
|
||||
op(0xb9, RES_o_r, 7, C)
|
||||
@@ -488,7 +491,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xbb, RES_o_r, 7, E)
|
||||
op(0xbc, RES_o_r, 7, H)
|
||||
op(0xbd, RES_o_r, 7, L)
|
||||
op(0xbe, RES_o_irr, 7, _HL)
|
||||
op(0xbe, RES_o_irr_r, 7, _HL, _)
|
||||
op(0xbf, RES_o_r, 7, A)
|
||||
op(0xc0, SET_o_r, 0, B)
|
||||
op(0xc1, SET_o_r, 0, C)
|
||||
@@ -496,7 +499,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xc3, SET_o_r, 0, E)
|
||||
op(0xc4, SET_o_r, 0, H)
|
||||
op(0xc5, SET_o_r, 0, L)
|
||||
op(0xc6, SET_o_irr, 0, _HL)
|
||||
op(0xc6, SET_o_irr_r, 0, _HL, _)
|
||||
op(0xc7, SET_o_r, 0, A)
|
||||
op(0xc8, SET_o_r, 1, B)
|
||||
op(0xc9, SET_o_r, 1, C)
|
||||
@@ -504,7 +507,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xcb, SET_o_r, 1, E)
|
||||
op(0xcc, SET_o_r, 1, H)
|
||||
op(0xcd, SET_o_r, 1, L)
|
||||
op(0xce, SET_o_irr, 1, _HL)
|
||||
op(0xce, SET_o_irr_r, 1, _HL, _)
|
||||
op(0xcf, SET_o_r, 1, A)
|
||||
op(0xd0, SET_o_r, 2, B)
|
||||
op(0xd1, SET_o_r, 2, C)
|
||||
@@ -512,7 +515,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xd3, SET_o_r, 2, E)
|
||||
op(0xd4, SET_o_r, 2, H)
|
||||
op(0xd5, SET_o_r, 2, L)
|
||||
op(0xd6, SET_o_irr, 2, _HL)
|
||||
op(0xd6, SET_o_irr_r, 2, _HL, _)
|
||||
op(0xd7, SET_o_r, 2, A)
|
||||
op(0xd8, SET_o_r, 3, B)
|
||||
op(0xd9, SET_o_r, 3, C)
|
||||
@@ -520,7 +523,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xdb, SET_o_r, 3, E)
|
||||
op(0xdc, SET_o_r, 3, H)
|
||||
op(0xdd, SET_o_r, 3, L)
|
||||
op(0xde, SET_o_irr, 3, _HL)
|
||||
op(0xde, SET_o_irr_r, 3, _HL, _)
|
||||
op(0xdf, SET_o_r, 3, A)
|
||||
op(0xe0, SET_o_r, 4, B)
|
||||
op(0xe1, SET_o_r, 4, C)
|
||||
@@ -528,7 +531,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xe3, SET_o_r, 4, E)
|
||||
op(0xe4, SET_o_r, 4, H)
|
||||
op(0xe5, SET_o_r, 4, L)
|
||||
op(0xe6, SET_o_irr, 4, _HL)
|
||||
op(0xe6, SET_o_irr_r, 4, _HL, _)
|
||||
op(0xe7, SET_o_r, 4, A)
|
||||
op(0xe8, SET_o_r, 5, B)
|
||||
op(0xe9, SET_o_r, 5, C)
|
||||
@@ -536,7 +539,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xeb, SET_o_r, 5, E)
|
||||
op(0xec, SET_o_r, 5, H)
|
||||
op(0xed, SET_o_r, 5, L)
|
||||
op(0xee, SET_o_irr, 5, _HL)
|
||||
op(0xee, SET_o_irr_r, 5, _HL, _)
|
||||
op(0xef, SET_o_r, 5, A)
|
||||
op(0xf0, SET_o_r, 6, B)
|
||||
op(0xf1, SET_o_r, 6, C)
|
||||
@@ -544,7 +547,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xf3, SET_o_r, 6, E)
|
||||
op(0xf4, SET_o_r, 6, H)
|
||||
op(0xf5, SET_o_r, 6, L)
|
||||
op(0xf6, SET_o_irr, 6, _HL)
|
||||
op(0xf6, SET_o_irr_r, 6, _HL, _)
|
||||
op(0xf7, SET_o_r, 6, A)
|
||||
op(0xf8, SET_o_r, 7, B)
|
||||
op(0xf9, SET_o_r, 7, C)
|
||||
@@ -552,7 +555,7 @@ auto Z80::instructionCB(n8 code) -> void {
|
||||
op(0xfb, SET_o_r, 7, E)
|
||||
op(0xfc, SET_o_r, 7, H)
|
||||
op(0xfd, SET_o_r, 7, L)
|
||||
op(0xfe, SET_o_irr, 7, _HL)
|
||||
op(0xfe, SET_o_irr_r, 7, _HL, _)
|
||||
op(0xff, SET_o_r, 7, A)
|
||||
}
|
||||
}
|
||||
@@ -565,262 +568,264 @@ auto Z80::instructionCBd(n16 addr, n8 code) -> void {
|
||||
op(0x01, RLC_irr_r, addr, C)
|
||||
op(0x02, RLC_irr_r, addr, D)
|
||||
op(0x03, RLC_irr_r, addr, E)
|
||||
op(0x04, RLC_irr_r, addr, H)
|
||||
op(0x05, RLC_irr_r, addr, L)
|
||||
op(0x04, RLC_irr_r, addr, _H)
|
||||
op(0x05, RLC_irr_r, addr, _L)
|
||||
op(0x06, RLC_irr_r, addr, _)
|
||||
op(0x07, RLC_irr_r, addr, A)
|
||||
op(0x08, RRC_irr_r, addr, B)
|
||||
op(0x09, RRC_irr_r, addr, C)
|
||||
op(0x0a, RRC_irr_r, addr, D)
|
||||
op(0x0b, RRC_irr_r, addr, E)
|
||||
op(0x0c, RRC_irr_r, addr, H)
|
||||
op(0x0d, RRC_irr_r, addr, L)
|
||||
op(0x0c, RRC_irr_r, addr, _H)
|
||||
op(0x0d, RRC_irr_r, addr, _L)
|
||||
op(0x0e, RRC_irr_r, addr, _)
|
||||
op(0x0f, RRC_irr_r, addr, A)
|
||||
op(0x10, RL_irr_r, addr, B)
|
||||
op(0x11, RL_irr_r, addr, C)
|
||||
op(0x12, RL_irr_r, addr, D)
|
||||
op(0x13, RL_irr_r, addr, E)
|
||||
op(0x14, RL_irr_r, addr, H)
|
||||
op(0x15, RL_irr_r, addr, L)
|
||||
op(0x14, RL_irr_r, addr, _H)
|
||||
op(0x15, RL_irr_r, addr, _L)
|
||||
op(0x16, RL_irr_r, addr, _)
|
||||
op(0x17, RL_irr_r, addr, A)
|
||||
op(0x18, RR_irr_r, addr, B)
|
||||
op(0x19, RR_irr_r, addr, C)
|
||||
op(0x1a, RR_irr_r, addr, D)
|
||||
op(0x1b, RR_irr_r, addr, E)
|
||||
op(0x1c, RR_irr_r, addr, H)
|
||||
op(0x1d, RR_irr_r, addr, L)
|
||||
op(0x1c, RR_irr_r, addr, _H)
|
||||
op(0x1d, RR_irr_r, addr, _L)
|
||||
op(0x1e, RR_irr_r, addr, _)
|
||||
op(0x1f, RR_irr_r, addr, A)
|
||||
op(0x20, SLA_irr_r, addr, B)
|
||||
op(0x21, SLA_irr_r, addr, C)
|
||||
op(0x22, SLA_irr_r, addr, D)
|
||||
op(0x23, SLA_irr_r, addr, E)
|
||||
op(0x24, SLA_irr_r, addr, H)
|
||||
op(0x25, SLA_irr_r, addr, L)
|
||||
op(0x24, SLA_irr_r, addr, _H)
|
||||
op(0x25, SLA_irr_r, addr, _L)
|
||||
op(0x26, SLA_irr_r, addr, _)
|
||||
op(0x27, SLA_irr_r, addr, A)
|
||||
op(0x28, SRA_irr_r, addr, B)
|
||||
op(0x29, SRA_irr_r, addr, C)
|
||||
op(0x2a, SRA_irr_r, addr, D)
|
||||
op(0x2b, SRA_irr_r, addr, E)
|
||||
op(0x2c, SRA_irr_r, addr, H)
|
||||
op(0x2d, SRA_irr_r, addr, L)
|
||||
op(0x2c, SRA_irr_r, addr, _H)
|
||||
op(0x2d, SRA_irr_r, addr, _L)
|
||||
op(0x2e, SRA_irr_r, addr, _)
|
||||
op(0x2f, SRA_irr_r, addr, A)
|
||||
op(0x30, SLL_irr_r, addr, B)
|
||||
op(0x31, SLL_irr_r, addr, C)
|
||||
op(0x32, SLL_irr_r, addr, D)
|
||||
op(0x33, SLL_irr_r, addr, E)
|
||||
op(0x34, SLL_irr_r, addr, H)
|
||||
op(0x35, SLL_irr_r, addr, L)
|
||||
op(0x34, SLL_irr_r, addr, _H)
|
||||
op(0x35, SLL_irr_r, addr, _L)
|
||||
op(0x36, SLL_irr_r, addr, _)
|
||||
op(0x37, SLL_irr_r, addr, A)
|
||||
op(0x38, SRL_irr_r, addr, B)
|
||||
op(0x39, SRL_irr_r, addr, C)
|
||||
op(0x3a, SRL_irr_r, addr, D)
|
||||
op(0x3b, SRL_irr_r, addr, E)
|
||||
op(0x3c, SRL_irr_r, addr, H)
|
||||
op(0x3d, SRL_irr_r, addr, L)
|
||||
op(0x3c, SRL_irr_r, addr, _H)
|
||||
op(0x3d, SRL_irr_r, addr, _L)
|
||||
op(0x3e, SRL_irr_r, addr, _)
|
||||
op(0x3f, SRL_irr_r, addr, A)
|
||||
op(0x40, BIT_o_irr_r, 0, addr, B)
|
||||
op(0x41, BIT_o_irr_r, 0, addr, C)
|
||||
op(0x42, BIT_o_irr_r, 0, addr, D)
|
||||
op(0x43, BIT_o_irr_r, 0, addr, E)
|
||||
op(0x44, BIT_o_irr_r, 0, addr, H)
|
||||
op(0x45, BIT_o_irr_r, 0, addr, L)
|
||||
op(0x40, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x41, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x42, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x43, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x44, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x45, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x46, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x47, BIT_o_irr_r, 0, addr, A)
|
||||
op(0x48, BIT_o_irr_r, 1, addr, B)
|
||||
op(0x49, BIT_o_irr_r, 1, addr, C)
|
||||
op(0x4a, BIT_o_irr_r, 1, addr, D)
|
||||
op(0x4b, BIT_o_irr_r, 1, addr, E)
|
||||
op(0x4c, BIT_o_irr_r, 1, addr, H)
|
||||
op(0x4d, BIT_o_irr_r, 1, addr, L)
|
||||
op(0x47, BIT_o_irr_r, 0, addr, _)
|
||||
op(0x48, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x49, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x4a, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x4b, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x4c, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x4d, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x4e, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x4f, BIT_o_irr_r, 1, addr, A)
|
||||
op(0x50, BIT_o_irr_r, 2, addr, B)
|
||||
op(0x51, BIT_o_irr_r, 2, addr, C)
|
||||
op(0x52, BIT_o_irr_r, 2, addr, D)
|
||||
op(0x53, BIT_o_irr_r, 2, addr, E)
|
||||
op(0x54, BIT_o_irr_r, 2, addr, H)
|
||||
op(0x55, BIT_o_irr_r, 2, addr, L)
|
||||
op(0x4f, BIT_o_irr_r, 1, addr, _)
|
||||
op(0x50, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x51, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x52, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x53, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x54, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x55, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x56, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x57, BIT_o_irr_r, 2, addr, A)
|
||||
op(0x58, BIT_o_irr_r, 3, addr, B)
|
||||
op(0x59, BIT_o_irr_r, 3, addr, C)
|
||||
op(0x5a, BIT_o_irr_r, 3, addr, D)
|
||||
op(0x5b, BIT_o_irr_r, 3, addr, E)
|
||||
op(0x5c, BIT_o_irr_r, 3, addr, H)
|
||||
op(0x5d, BIT_o_irr_r, 3, addr, L)
|
||||
op(0x57, BIT_o_irr_r, 2, addr, _)
|
||||
op(0x58, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x59, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x5a, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x5b, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x5c, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x5d, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x5e, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x5f, BIT_o_irr_r, 3, addr, A)
|
||||
op(0x60, BIT_o_irr_r, 4, addr, B)
|
||||
op(0x61, BIT_o_irr_r, 4, addr, C)
|
||||
op(0x62, BIT_o_irr_r, 4, addr, D)
|
||||
op(0x63, BIT_o_irr_r, 4, addr, E)
|
||||
op(0x64, BIT_o_irr_r, 4, addr, H)
|
||||
op(0x65, BIT_o_irr_r, 4, addr, L)
|
||||
op(0x5f, BIT_o_irr_r, 3, addr, _)
|
||||
op(0x60, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x61, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x62, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x63, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x64, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x65, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x66, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x67, BIT_o_irr_r, 4, addr, A)
|
||||
op(0x68, BIT_o_irr_r, 5, addr, B)
|
||||
op(0x69, BIT_o_irr_r, 5, addr, C)
|
||||
op(0x6a, BIT_o_irr_r, 5, addr, D)
|
||||
op(0x6b, BIT_o_irr_r, 5, addr, E)
|
||||
op(0x6c, BIT_o_irr_r, 5, addr, H)
|
||||
op(0x6d, BIT_o_irr_r, 5, addr, L)
|
||||
op(0x67, BIT_o_irr_r, 4, addr, _)
|
||||
op(0x68, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x69, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x6a, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x6b, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x6c, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x6d, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x6e, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x6f, BIT_o_irr_r, 5, addr, A)
|
||||
op(0x70, BIT_o_irr_r, 6, addr, B)
|
||||
op(0x71, BIT_o_irr_r, 6, addr, C)
|
||||
op(0x72, BIT_o_irr_r, 6, addr, D)
|
||||
op(0x73, BIT_o_irr_r, 6, addr, E)
|
||||
op(0x74, BIT_o_irr_r, 6, addr, H)
|
||||
op(0x75, BIT_o_irr_r, 6, addr, L)
|
||||
op(0x6f, BIT_o_irr_r, 5, addr, _)
|
||||
op(0x70, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x71, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x72, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x73, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x74, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x75, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x76, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x77, BIT_o_irr_r, 6, addr, A)
|
||||
op(0x78, BIT_o_irr_r, 7, addr, B)
|
||||
op(0x79, BIT_o_irr_r, 7, addr, C)
|
||||
op(0x7a, BIT_o_irr_r, 7, addr, D)
|
||||
op(0x7b, BIT_o_irr_r, 7, addr, E)
|
||||
op(0x7c, BIT_o_irr_r, 7, addr, H)
|
||||
op(0x7d, BIT_o_irr_r, 7, addr, L)
|
||||
op(0x77, BIT_o_irr_r, 6, addr, _)
|
||||
op(0x78, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x79, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x7a, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x7b, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x7c, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x7d, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x7e, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x7f, BIT_o_irr_r, 7, addr, A)
|
||||
op(0x7f, BIT_o_irr_r, 7, addr, _)
|
||||
op(0x80, RES_o_irr_r, 0, addr, B)
|
||||
op(0x81, RES_o_irr_r, 0, addr, C)
|
||||
op(0x82, RES_o_irr_r, 0, addr, D)
|
||||
op(0x83, RES_o_irr_r, 0, addr, E)
|
||||
op(0x84, RES_o_irr_r, 0, addr, H)
|
||||
op(0x85, RES_o_irr_r, 0, addr, L)
|
||||
op(0x84, RES_o_irr_r, 0, addr, _H)
|
||||
op(0x85, RES_o_irr_r, 0, addr, _L)
|
||||
op(0x86, RES_o_irr_r, 0, addr, _)
|
||||
op(0x87, RES_o_irr_r, 0, addr, A)
|
||||
op(0x88, RES_o_irr_r, 1, addr, B)
|
||||
op(0x89, RES_o_irr_r, 1, addr, C)
|
||||
op(0x8a, RES_o_irr_r, 1, addr, D)
|
||||
op(0x8b, RES_o_irr_r, 1, addr, E)
|
||||
op(0x8c, RES_o_irr_r, 1, addr, H)
|
||||
op(0x8d, RES_o_irr_r, 1, addr, L)
|
||||
op(0x8c, RES_o_irr_r, 1, addr, _H)
|
||||
op(0x8d, RES_o_irr_r, 1, addr, _L)
|
||||
op(0x8e, RES_o_irr_r, 1, addr, _)
|
||||
op(0x8f, RES_o_irr_r, 1, addr, A)
|
||||
op(0x90, RES_o_irr_r, 2, addr, B)
|
||||
op(0x91, RES_o_irr_r, 2, addr, C)
|
||||
op(0x92, RES_o_irr_r, 2, addr, D)
|
||||
op(0x93, RES_o_irr_r, 2, addr, E)
|
||||
op(0x94, RES_o_irr_r, 2, addr, H)
|
||||
op(0x95, RES_o_irr_r, 2, addr, L)
|
||||
op(0x94, RES_o_irr_r, 2, addr, _H)
|
||||
op(0x95, RES_o_irr_r, 2, addr, _L)
|
||||
op(0x96, RES_o_irr_r, 2, addr, _)
|
||||
op(0x97, RES_o_irr_r, 2, addr, A)
|
||||
op(0x98, RES_o_irr_r, 3, addr, B)
|
||||
op(0x99, RES_o_irr_r, 3, addr, C)
|
||||
op(0x9a, RES_o_irr_r, 3, addr, D)
|
||||
op(0x9b, RES_o_irr_r, 3, addr, E)
|
||||
op(0x9c, RES_o_irr_r, 3, addr, H)
|
||||
op(0x9d, RES_o_irr_r, 3, addr, L)
|
||||
op(0x9c, RES_o_irr_r, 3, addr, _H)
|
||||
op(0x9d, RES_o_irr_r, 3, addr, _L)
|
||||
op(0x9e, RES_o_irr_r, 3, addr, _)
|
||||
op(0x9f, RES_o_irr_r, 3, addr, A)
|
||||
op(0xa0, RES_o_irr_r, 4, addr, B)
|
||||
op(0xa1, RES_o_irr_r, 4, addr, C)
|
||||
op(0xa2, RES_o_irr_r, 4, addr, D)
|
||||
op(0xa3, RES_o_irr_r, 4, addr, E)
|
||||
op(0xa4, RES_o_irr_r, 4, addr, H)
|
||||
op(0xa5, RES_o_irr_r, 4, addr, L)
|
||||
op(0xa4, RES_o_irr_r, 4, addr, _H)
|
||||
op(0xa5, RES_o_irr_r, 4, addr, _L)
|
||||
op(0xa6, RES_o_irr_r, 4, addr, _)
|
||||
op(0xa7, RES_o_irr_r, 4, addr, A)
|
||||
op(0xa8, RES_o_irr_r, 5, addr, B)
|
||||
op(0xa9, RES_o_irr_r, 5, addr, C)
|
||||
op(0xaa, RES_o_irr_r, 5, addr, D)
|
||||
op(0xab, RES_o_irr_r, 5, addr, E)
|
||||
op(0xac, RES_o_irr_r, 5, addr, H)
|
||||
op(0xad, RES_o_irr_r, 5, addr, L)
|
||||
op(0xac, RES_o_irr_r, 5, addr, _H)
|
||||
op(0xad, RES_o_irr_r, 5, addr, _L)
|
||||
op(0xae, RES_o_irr_r, 5, addr, _)
|
||||
op(0xaf, RES_o_irr_r, 5, addr, A)
|
||||
op(0xb0, RES_o_irr_r, 6, addr, B)
|
||||
op(0xb1, RES_o_irr_r, 6, addr, C)
|
||||
op(0xb2, RES_o_irr_r, 6, addr, D)
|
||||
op(0xb3, RES_o_irr_r, 6, addr, E)
|
||||
op(0xb4, RES_o_irr_r, 6, addr, H)
|
||||
op(0xb5, RES_o_irr_r, 6, addr, L)
|
||||
op(0xb4, RES_o_irr_r, 6, addr, _H)
|
||||
op(0xb5, RES_o_irr_r, 6, addr, _L)
|
||||
op(0xb6, RES_o_irr_r, 6, addr, _)
|
||||
op(0xb7, RES_o_irr_r, 6, addr, A)
|
||||
op(0xb8, RES_o_irr_r, 7, addr, B)
|
||||
op(0xb9, RES_o_irr_r, 7, addr, C)
|
||||
op(0xba, RES_o_irr_r, 7, addr, D)
|
||||
op(0xbb, RES_o_irr_r, 7, addr, E)
|
||||
op(0xbc, RES_o_irr_r, 7, addr, H)
|
||||
op(0xbd, RES_o_irr_r, 7, addr, L)
|
||||
op(0xbc, RES_o_irr_r, 7, addr, _H)
|
||||
op(0xbd, RES_o_irr_r, 7, addr, _L)
|
||||
op(0xbe, RES_o_irr_r, 7, addr, _)
|
||||
op(0xbf, RES_o_irr_r, 7, addr, A)
|
||||
op(0xc0, SET_o_irr_r, 0, addr, B)
|
||||
op(0xc1, SET_o_irr_r, 0, addr, C)
|
||||
op(0xc2, SET_o_irr_r, 0, addr, D)
|
||||
op(0xc3, SET_o_irr_r, 0, addr, E)
|
||||
op(0xc4, SET_o_irr_r, 0, addr, H)
|
||||
op(0xc5, SET_o_irr_r, 0, addr, L)
|
||||
op(0xc4, SET_o_irr_r, 0, addr, _H)
|
||||
op(0xc5, SET_o_irr_r, 0, addr, _L)
|
||||
op(0xc6, SET_o_irr_r, 0, addr, _)
|
||||
op(0xc7, SET_o_irr_r, 0, addr, A)
|
||||
op(0xc8, SET_o_irr_r, 1, addr, B)
|
||||
op(0xc9, SET_o_irr_r, 1, addr, C)
|
||||
op(0xca, SET_o_irr_r, 1, addr, D)
|
||||
op(0xcb, SET_o_irr_r, 1, addr, E)
|
||||
op(0xcc, SET_o_irr_r, 1, addr, H)
|
||||
op(0xcd, SET_o_irr_r, 1, addr, L)
|
||||
op(0xcc, SET_o_irr_r, 1, addr, _H)
|
||||
op(0xcd, SET_o_irr_r, 1, addr, _L)
|
||||
op(0xce, SET_o_irr_r, 1, addr, _)
|
||||
op(0xcf, SET_o_irr_r, 1, addr, A)
|
||||
op(0xd0, SET_o_irr_r, 2, addr, B)
|
||||
op(0xd1, SET_o_irr_r, 2, addr, C)
|
||||
op(0xd2, SET_o_irr_r, 2, addr, D)
|
||||
op(0xd3, SET_o_irr_r, 2, addr, E)
|
||||
op(0xd4, SET_o_irr_r, 2, addr, H)
|
||||
op(0xd5, SET_o_irr_r, 2, addr, L)
|
||||
op(0xd4, SET_o_irr_r, 2, addr, _H)
|
||||
op(0xd5, SET_o_irr_r, 2, addr, _L)
|
||||
op(0xd6, SET_o_irr_r, 2, addr, _)
|
||||
op(0xd7, SET_o_irr_r, 2, addr, A)
|
||||
op(0xd8, SET_o_irr_r, 3, addr, B)
|
||||
op(0xd9, SET_o_irr_r, 3, addr, C)
|
||||
op(0xda, SET_o_irr_r, 3, addr, D)
|
||||
op(0xdb, SET_o_irr_r, 3, addr, E)
|
||||
op(0xdc, SET_o_irr_r, 3, addr, H)
|
||||
op(0xdd, SET_o_irr_r, 3, addr, L)
|
||||
op(0xdc, SET_o_irr_r, 3, addr, _H)
|
||||
op(0xdd, SET_o_irr_r, 3, addr, _L)
|
||||
op(0xde, SET_o_irr_r, 3, addr, _)
|
||||
op(0xdf, SET_o_irr_r, 3, addr, A)
|
||||
op(0xe0, SET_o_irr_r, 4, addr, B)
|
||||
op(0xe1, SET_o_irr_r, 4, addr, C)
|
||||
op(0xe2, SET_o_irr_r, 4, addr, D)
|
||||
op(0xe3, SET_o_irr_r, 4, addr, E)
|
||||
op(0xe4, SET_o_irr_r, 4, addr, H)
|
||||
op(0xe5, SET_o_irr_r, 4, addr, L)
|
||||
op(0xe4, SET_o_irr_r, 4, addr, _H)
|
||||
op(0xe5, SET_o_irr_r, 4, addr, _L)
|
||||
op(0xe6, SET_o_irr_r, 4, addr, _)
|
||||
op(0xe7, SET_o_irr_r, 4, addr, A)
|
||||
op(0xe8, SET_o_irr_r, 5, addr, B)
|
||||
op(0xe9, SET_o_irr_r, 5, addr, C)
|
||||
op(0xea, SET_o_irr_r, 5, addr, D)
|
||||
op(0xeb, SET_o_irr_r, 5, addr, E)
|
||||
op(0xec, SET_o_irr_r, 5, addr, H)
|
||||
op(0xed, SET_o_irr_r, 5, addr, L)
|
||||
op(0xec, SET_o_irr_r, 5, addr, _H)
|
||||
op(0xed, SET_o_irr_r, 5, addr, _L)
|
||||
op(0xee, SET_o_irr_r, 5, addr, _)
|
||||
op(0xef, SET_o_irr_r, 5, addr, A)
|
||||
op(0xf0, SET_o_irr_r, 6, addr, B)
|
||||
op(0xf1, SET_o_irr_r, 6, addr, C)
|
||||
op(0xf2, SET_o_irr_r, 6, addr, D)
|
||||
op(0xf3, SET_o_irr_r, 6, addr, E)
|
||||
op(0xf4, SET_o_irr_r, 6, addr, H)
|
||||
op(0xf5, SET_o_irr_r, 6, addr, L)
|
||||
op(0xf4, SET_o_irr_r, 6, addr, _H)
|
||||
op(0xf5, SET_o_irr_r, 6, addr, _L)
|
||||
op(0xf6, SET_o_irr_r, 6, addr, _)
|
||||
op(0xf7, SET_o_irr_r, 6, addr, A)
|
||||
op(0xf8, SET_o_irr_r, 7, addr, B)
|
||||
op(0xf9, SET_o_irr_r, 7, addr, C)
|
||||
op(0xfa, SET_o_irr_r, 7, addr, D)
|
||||
op(0xfb, SET_o_irr_r, 7, addr, E)
|
||||
op(0xfc, SET_o_irr_r, 7, addr, H)
|
||||
op(0xfd, SET_o_irr_r, 7, addr, L)
|
||||
op(0xfc, SET_o_irr_r, 7, addr, _H)
|
||||
op(0xfd, SET_o_irr_r, 7, addr, _L)
|
||||
op(0xfe, SET_o_irr_r, 7, addr, _)
|
||||
op(0xff, SET_o_irr_r, 7, addr, A)
|
||||
}
|
||||
}
|
||||
|
||||
auto Z80::instructionED(n8 code) -> void {
|
||||
n8 _;
|
||||
|
||||
switch(code) {
|
||||
op(0x40, IN_r_ic, B)
|
||||
op(0x41, OUT_ic_r, B)
|
||||
@@ -870,7 +875,7 @@ auto Z80::instructionED(n8 code) -> void {
|
||||
op(0x6d, RETI)
|
||||
op(0x6e, IM_o, 0)
|
||||
op(0x6f, RLD)
|
||||
op(0x70, IN_ic)
|
||||
op(0x70, IN_r_ic, _)
|
||||
op(0x71, OUT_ic)
|
||||
op(0x72, SBC_hl_rr, SP)
|
||||
op(0x73, LD_inn_rr, SP)
|
||||
|
||||
@@ -24,9 +24,9 @@ auto Z80::instructionADC_a_r(n8& x) -> void { Q = 1;
|
||||
|
||||
auto Z80::instructionADC_hl_rr(n16& x) -> void { Q = 1;
|
||||
WZ = HL + 1;
|
||||
wait(4);
|
||||
auto lo = ADD(HL >> 0, x >> 0, CF);
|
||||
wait(3);
|
||||
auto lo = ADD(HL >> 0, x >> 0, CF);
|
||||
wait(4);
|
||||
auto hi = ADD(HL >> 8, x >> 8, CF);
|
||||
HL = hi << 8 | lo << 0;
|
||||
ZF = HL == 0;
|
||||
@@ -47,9 +47,9 @@ auto Z80::instructionADD_a_r(n8& x) -> void { Q = 1;
|
||||
auto Z80::instructionADD_hl_rr(n16& x) -> void { Q = 1;
|
||||
WZ = HL + 1;
|
||||
bool vf = VF, zf = ZF, sf = SF;
|
||||
wait(4);
|
||||
auto lo = ADD(HL >> 0, x >> 0);
|
||||
wait(3);
|
||||
auto lo = ADD(HL >> 0, x >> 0);
|
||||
wait(4);
|
||||
auto hi = ADD(HL >> 8, x >> 8, CF);
|
||||
HL = hi << 8 | lo << 0;
|
||||
VF = vf, ZF = zf, SF = sf; //restore unaffected flags
|
||||
@@ -67,14 +67,9 @@ auto Z80::instructionAND_a_r(n8& x) -> void { Q = 1;
|
||||
A = AND(A, x);
|
||||
}
|
||||
|
||||
auto Z80::instructionBIT_o_irr(n3 bit, n16& addr) -> void { Q = 1;
|
||||
BIT(bit, read(addr));
|
||||
XF = WZH.bit(3);
|
||||
YF = WZH.bit(5);
|
||||
}
|
||||
|
||||
auto Z80::instructionBIT_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 1;
|
||||
x = BIT(bit, read(addr));
|
||||
wait(1);
|
||||
XF = WZH.bit(3);
|
||||
YF = WZH.bit(5);
|
||||
}
|
||||
@@ -91,13 +86,6 @@ auto Z80::instructionCALL_c_nn(bool c) -> void { Q = 0;
|
||||
PC = WZ;
|
||||
}
|
||||
|
||||
auto Z80::instructionCALL_nn() -> void { Q = 0;
|
||||
WZ = operands();
|
||||
wait(1);
|
||||
push(PC);
|
||||
PC = WZ;
|
||||
}
|
||||
|
||||
auto Z80::instructionCCF() -> void {
|
||||
if(Q) XF = 0, YF = 0;
|
||||
HF = CF;
|
||||
@@ -140,6 +128,8 @@ auto Z80::instructionCPDR() -> void { Q = 1;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
WZ = PC + 1;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
}
|
||||
|
||||
auto Z80::instructionCPI() -> void { Q = 1;
|
||||
@@ -162,6 +152,8 @@ auto Z80::instructionCPIR() -> void { Q = 1;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
WZ = PC + 1;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
}
|
||||
|
||||
auto Z80::instructionCPL() -> void { Q = 1;
|
||||
@@ -225,8 +217,10 @@ auto Z80::instructionEI() -> void { Q = 0;
|
||||
auto Z80::instructionEX_irr_rr(n16& x, n16& y) -> void { Q = 0;
|
||||
WZL = read(x + 0);
|
||||
WZH = read(x + 1);
|
||||
wait(1);
|
||||
write(x + 0, y >> 0);
|
||||
write(x + 1, y >> 8);
|
||||
wait(2);
|
||||
y = WZ;
|
||||
}
|
||||
|
||||
@@ -245,7 +239,6 @@ auto Z80::instructionHALT() -> void { Q = 0;
|
||||
}
|
||||
|
||||
auto Z80::instructionIM_o(n2 code) -> void { Q = 0;
|
||||
wait(4);
|
||||
IM = code;
|
||||
}
|
||||
|
||||
@@ -260,11 +253,6 @@ auto Z80::instructionIN_r_ic(n8& x) -> void { Q = 1;
|
||||
WZ = BC + 1;
|
||||
}
|
||||
|
||||
auto Z80::instructionIN_ic() -> void { Q = 1;
|
||||
IN(in(BC));
|
||||
WZ = BC + 1;
|
||||
}
|
||||
|
||||
auto Z80::instructionINC_irr(n16& x) -> void { Q = 1;
|
||||
auto addr = displace(x);
|
||||
auto data = read(addr);
|
||||
@@ -302,6 +290,20 @@ auto Z80::instructionINDR() -> void { Q = 1;
|
||||
if(!B) return;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
|
||||
if(CF && NF) {
|
||||
PF = PF == parity(B-1 & 7);
|
||||
HF = (B & 0xf) == 0;
|
||||
}
|
||||
if(CF && !NF) {
|
||||
PF = PF == parity(B+1 & 7);
|
||||
HF = (B & 0xf) == 0xf;
|
||||
}
|
||||
if(!CF) {
|
||||
PF = PF == parity(B+0 & 7);
|
||||
}
|
||||
}
|
||||
|
||||
auto Z80::instructionINI() -> void { Q = 1;
|
||||
@@ -325,6 +327,20 @@ auto Z80::instructionINIR() -> void { Q = 1;
|
||||
if(!B) return;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
|
||||
if(CF && NF) {
|
||||
PF = PF == parity(B-1 & 7);
|
||||
HF = (B & 0xf) == 0;
|
||||
}
|
||||
if(CF && !NF) {
|
||||
PF = PF == parity(B+1 & 7);
|
||||
HF = (B & 0xf) == 0xf;
|
||||
}
|
||||
if(!CF) {
|
||||
PF = PF == parity(B+0 & 7);
|
||||
}
|
||||
}
|
||||
|
||||
auto Z80::instructionJP_c_nn(bool c) -> void { Q = 0;
|
||||
@@ -351,7 +367,7 @@ auto Z80::instructionLD_a_inn() -> void { Q = 0;
|
||||
|
||||
auto Z80::instructionLD_a_irr(n16& x) -> void { Q = 0;
|
||||
WZ = x;
|
||||
A = read(displace(WZ));
|
||||
A = read(x);
|
||||
WZ++;
|
||||
}
|
||||
|
||||
@@ -370,14 +386,16 @@ auto Z80::instructionLD_inn_rr(n16& x) -> void { Q = 0;
|
||||
|
||||
auto Z80::instructionLD_irr_a(n16& x) -> void { Q = 0;
|
||||
WZ = x;
|
||||
write(displace(WZ), A);
|
||||
write(x, A);
|
||||
WZL++;
|
||||
WZH = A;
|
||||
}
|
||||
|
||||
auto Z80::instructionLD_irr_n(n16& x) -> void { Q = 0;
|
||||
auto addr = displace(x);
|
||||
write(addr, operand());
|
||||
auto addr = displace(x,0); // special case: defer wait cycles (overlap with n fetch)
|
||||
auto data = operand();
|
||||
if(&x == &ix.word || &x == &iy.word) wait(2);
|
||||
write(addr, data);
|
||||
}
|
||||
|
||||
auto Z80::instructionLD_irr_r(n16& x, n8& y) -> void { Q = 0;
|
||||
@@ -417,9 +435,10 @@ auto Z80::instructionLD_r_r2(n8& x, n8& y) -> void { Q = 1;
|
||||
}
|
||||
|
||||
auto Z80::instructionLD_rr_inn(n16& x) -> void { Q = 0;
|
||||
auto addr = operands();
|
||||
x.byte(0) = read(addr + 0);
|
||||
x.byte(1) = read(addr + 1);
|
||||
WZ = operands();
|
||||
x.byte(0) = read(WZ);
|
||||
WZ++;
|
||||
x.byte(1) = read(WZ);
|
||||
}
|
||||
|
||||
auto Z80::instructionLD_rr_nn(n16& x) -> void { Q = 0;
|
||||
@@ -448,6 +467,8 @@ auto Z80::instructionLDDR() -> void { Q = 1;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
WZ = PC + 1;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
}
|
||||
|
||||
auto Z80::instructionLDI() -> void { Q = 1;
|
||||
@@ -467,6 +488,8 @@ auto Z80::instructionLDIR() -> void { Q = 1;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
WZ = PC + 1;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
}
|
||||
|
||||
auto Z80::instructionNEG() -> void { Q = 1;
|
||||
@@ -493,6 +516,20 @@ auto Z80::instructionOTDR() -> void { Q = 1;
|
||||
if(!B) return;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
|
||||
if(CF && NF) {
|
||||
PF = PF == parity(B-1 & 7);
|
||||
HF = (B & 0xf) == 0;
|
||||
}
|
||||
if(CF && !NF) {
|
||||
PF = PF == parity(B+1 & 7);
|
||||
HF = (B & 0xf) == 0xf;
|
||||
}
|
||||
if(!CF) {
|
||||
PF = PF == parity(B+0 & 7);
|
||||
}
|
||||
}
|
||||
|
||||
auto Z80::instructionOTIR() -> void { Q = 1;
|
||||
@@ -500,6 +537,20 @@ auto Z80::instructionOTIR() -> void { Q = 1;
|
||||
if(!B) return;
|
||||
wait(5);
|
||||
PC -= 2;
|
||||
XF = PC.bit(11);
|
||||
YF = PC.bit(13);
|
||||
|
||||
if(CF && NF) {
|
||||
PF = PF == parity(B-1 & 7);
|
||||
HF = (B & 0xf) == 0;
|
||||
}
|
||||
if(CF && !NF) {
|
||||
PF = PF == parity(B+1 & 7);
|
||||
HF = (B & 0xf) == 0xf;
|
||||
}
|
||||
if(!CF) {
|
||||
PF = PF == parity(B+0 & 7);
|
||||
}
|
||||
}
|
||||
|
||||
auto Z80::instructionOUT_ic_r(n8& x) -> void { Q = 0;
|
||||
@@ -510,6 +561,7 @@ auto Z80::instructionOUT_ic_r(n8& x) -> void { Q = 0;
|
||||
auto Z80::instructionOUT_ic() -> void { Q = 0;
|
||||
if(mosfet == MOSFET::NMOS) out(BC, 0x00);
|
||||
if(mosfet == MOSFET::CMOS) out(BC, 0xff);
|
||||
WZ = BC + 1;
|
||||
}
|
||||
|
||||
auto Z80::instructionOUT_in_a() -> void { Q = 0;
|
||||
@@ -561,20 +613,17 @@ auto Z80::instructionPUSH_rr(n16& x) -> void { Q = 0;
|
||||
push(x);
|
||||
}
|
||||
|
||||
auto Z80::instructionRES_o_irr(n3 bit, n16& addr) -> void { Q = 1;
|
||||
write(addr, RES(bit, read(addr)));
|
||||
auto Z80::instructionRES_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 0;
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = RES(bit, data));
|
||||
}
|
||||
|
||||
auto Z80::instructionRES_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = RES(bit, read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionRES_o_r(n3 bit, n8& x) -> void { Q = 1;
|
||||
auto Z80::instructionRES_o_r(n3 bit, n8& x) -> void { Q = 0;
|
||||
x = RES(bit, x);
|
||||
}
|
||||
|
||||
auto Z80::instructionRET() -> void { Q = 0;
|
||||
wait(1);
|
||||
WZ = pop();
|
||||
PC = WZ;
|
||||
}
|
||||
@@ -598,12 +647,10 @@ auto Z80::instructionRETN() -> void { Q = 0;
|
||||
IFF1 = IFF2;
|
||||
}
|
||||
|
||||
auto Z80::instructionRL_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, RL(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionRL_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = RL(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = RL(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionRL_r(n8& x) -> void { Q = 1;
|
||||
@@ -621,12 +668,10 @@ auto Z80::instructionRLA() -> void { Q = 1;
|
||||
YF = A.bit(5);
|
||||
}
|
||||
|
||||
auto Z80::instructionRLC_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, RLC(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionRLC_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = RLC(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = RLC(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionRLC_r(n8& x) -> void { Q = 1;
|
||||
@@ -647,9 +692,8 @@ auto Z80::instructionRLCA() -> void { Q = 1;
|
||||
auto Z80::instructionRLD() -> void { Q = 1;
|
||||
WZ = HL + 1;
|
||||
auto data = read(HL);
|
||||
wait(1);
|
||||
wait(4);
|
||||
write(HL, (data << 4) | (A & 0x0f));
|
||||
wait(3);
|
||||
A = (A & 0xf0) | (data >> 4);
|
||||
|
||||
NF = 0;
|
||||
@@ -661,12 +705,10 @@ auto Z80::instructionRLD() -> void { Q = 1;
|
||||
SF = A.bit(7);
|
||||
}
|
||||
|
||||
auto Z80::instructionRR_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, RR(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionRR_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = RR(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = RR(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionRR_r(n8& x) -> void { Q = 1;
|
||||
@@ -684,12 +726,10 @@ auto Z80::instructionRRA() -> void { Q = 1;
|
||||
YF = A.bit(5);
|
||||
}
|
||||
|
||||
auto Z80::instructionRRC_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, RRC(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionRRC_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = RRC(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = RRC(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionRRC_r(n8& x) -> void { Q = 1;
|
||||
@@ -710,9 +750,8 @@ auto Z80::instructionRRCA() -> void { Q = 1;
|
||||
auto Z80::instructionRRD() -> void { Q = 1;
|
||||
WZ = HL + 1;
|
||||
auto data = read(HL);
|
||||
wait(1);
|
||||
wait(4);
|
||||
write(HL, (data >> 4) | (A << 4));
|
||||
wait(3);
|
||||
A = (A & 0xf0) | (data & 0x0f);
|
||||
|
||||
NF = 0;
|
||||
@@ -745,9 +784,9 @@ auto Z80::instructionSBC_a_r(n8& x) -> void { Q = 1;
|
||||
|
||||
auto Z80::instructionSBC_hl_rr(n16& x) -> void { Q = 1;
|
||||
WZ = HL + 1;
|
||||
wait(4);
|
||||
auto lo = SUB(HL >> 0, x >> 0, CF);
|
||||
wait(3);
|
||||
auto lo = SUB(HL >> 0, x >> 0, CF);
|
||||
wait(4);
|
||||
auto hi = SUB(HL >> 8, x >> 8, CF);
|
||||
HL = hi << 8 | lo << 0;
|
||||
ZF = HL == 0;
|
||||
@@ -763,60 +802,50 @@ auto Z80::instructionSCF() -> void {
|
||||
Q = 1;
|
||||
}
|
||||
|
||||
auto Z80::instructionSET_o_irr(n3 bit, n16& addr) -> void { Q = 1;
|
||||
write(addr, SET(bit, read(addr)));
|
||||
auto Z80::instructionSET_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 0;
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = SET(bit, data));
|
||||
}
|
||||
|
||||
auto Z80::instructionSET_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = SET(bit, read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionSET_o_r(n3 bit, n8& x) -> void { Q = 1;
|
||||
auto Z80::instructionSET_o_r(n3 bit, n8& x) -> void { Q = 0;
|
||||
x = SET(bit, x);
|
||||
}
|
||||
|
||||
auto Z80::instructionSLA_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, SLA(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionSLA_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = SLA(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = SLA(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionSLA_r(n8& x) -> void { Q = 1;
|
||||
x = SLA(x);
|
||||
}
|
||||
|
||||
auto Z80::instructionSLL_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, SLL(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionSLL_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = SLL(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = SLL(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionSLL_r(n8& x) -> void { Q = 1;
|
||||
x = SLL(x);
|
||||
}
|
||||
|
||||
auto Z80::instructionSRA_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, SRA(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionSRA_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = SRA(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = SRA(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionSRA_r(n8& x) -> void { Q = 1;
|
||||
x = SRA(x);
|
||||
}
|
||||
|
||||
auto Z80::instructionSRL_irr(n16& addr) -> void { Q = 1;
|
||||
write(addr, SRL(read(addr)));
|
||||
}
|
||||
|
||||
auto Z80::instructionSRL_irr_r(n16& addr, n8& x) -> void { Q = 1;
|
||||
write(addr, x = SRL(read(addr)));
|
||||
auto data = read(addr);
|
||||
wait(1);
|
||||
write(addr, x = SRL(data));
|
||||
}
|
||||
|
||||
auto Z80::instructionSRL_r(n8& x) -> void { Q = 1;
|
||||
|
||||
@@ -27,10 +27,10 @@ auto Z80::pop() -> n16 {
|
||||
return data | read(SP++) << 8;
|
||||
}
|
||||
|
||||
auto Z80::displace(n16& x) -> n16 {
|
||||
auto Z80::displace(n16& x, u32 wclocks) -> n16 {
|
||||
if(&x != &ix.word && &x != &iy.word) return x;
|
||||
auto d = operand();
|
||||
wait(5);
|
||||
wait(wclocks);
|
||||
WZ = x + (i8)d;
|
||||
return WZ;
|
||||
}
|
||||
|
||||
@@ -31,29 +31,31 @@ auto Z80::power(MOSFET mosfet) -> void {
|
||||
HALT = 0;
|
||||
IFF1 = 0;
|
||||
IFF2 = 0;
|
||||
IM = 1;
|
||||
IM = 0;
|
||||
}
|
||||
|
||||
auto Z80::irq(bool maskable, n16 pc, n8 extbus) -> bool {
|
||||
auto Z80::reset() -> void {
|
||||
prefix = Prefix::hl;
|
||||
ir.word = 0x0000;
|
||||
WZ = PC = 0x0000;
|
||||
EI = 0;
|
||||
HALT = 0;
|
||||
IFF1 = 0;
|
||||
IFF2 = 0;
|
||||
IM = 0;
|
||||
}
|
||||
|
||||
auto Z80::irq(n8 extbus) -> bool {
|
||||
//do not execute maskable interrupts if disabled or immediately after EI instruction
|
||||
if(maskable && (!IFF1 || EI)) return false;
|
||||
if(!IFF1 || EI) return false;
|
||||
R.bit(0,6)++;
|
||||
|
||||
push(PC);
|
||||
|
||||
switch(maskable ? IM : (n2)1) {
|
||||
|
||||
switch(IM) {
|
||||
case 1: extbus = 0xff; [[fallthrough]];
|
||||
case 0: {
|
||||
//external data bus ($ff = RST $38)
|
||||
WZ = extbus;
|
||||
wait(extbus | 0x38 == 0xff ? 6 : 7);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
//constant address
|
||||
WZ = pc;
|
||||
wait(maskable ? 7 : 5);
|
||||
wait(6);
|
||||
instruction(WZ);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -63,18 +65,37 @@ auto Z80::irq(bool maskable, n16 pc, n8 extbus) -> bool {
|
||||
WZL = read(address + 0);
|
||||
WZH = read(address + 1);
|
||||
wait(7);
|
||||
push(PC);
|
||||
PC = WZ;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PC = WZ;
|
||||
IFF1 = 0;
|
||||
if(maskable) IFF2 = 0;
|
||||
IFF2 = 0;
|
||||
HALT = 0;
|
||||
if(P) PF = 0;
|
||||
P = 0;
|
||||
Q = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Z80::nmi() -> bool {
|
||||
R.bit(0,6)++;
|
||||
|
||||
push(PC);
|
||||
WZ = 0x66;
|
||||
wait(5);
|
||||
PC = WZ;
|
||||
|
||||
IFF1 = 0;
|
||||
HALT = 0;
|
||||
if(P) PF = 0;
|
||||
P = 0;
|
||||
Q = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,10 @@ struct Z80 {
|
||||
|
||||
//z80.cpp
|
||||
auto power(MOSFET = MOSFET::NMOS) -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto irq(bool maskable, n16 vector = 0x0000, n8 extbus = 0xff) -> bool;
|
||||
auto irq(n8 extbus = 0xff) -> bool;
|
||||
auto nmi() -> bool;
|
||||
auto parity(n8) const -> bool;
|
||||
|
||||
//memory.cpp
|
||||
@@ -33,7 +35,7 @@ struct Z80 {
|
||||
auto operands() -> n16;
|
||||
auto push(n16) -> void;
|
||||
auto pop() -> n16;
|
||||
auto displace(n16&) -> n16;
|
||||
auto displace(n16&, u32 wclocks = 5) -> n16;
|
||||
auto read(n16 address) -> n8;
|
||||
auto write(n16 address, n8 data) -> void;
|
||||
auto in(n16 address) -> n8;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
auto V9938::Background::setup(n8 y) -> void {
|
||||
latch.vscroll = io.vscroll;
|
||||
|
||||
}
|
||||
|
||||
auto V9938::Background::run(n8 x, n8 y) -> void {
|
||||
output = {};
|
||||
|
||||
switch(self.videoMode()) {
|
||||
case 0b00000: return graphic1(x, y);
|
||||
case 0b00001: return text1(x, y);
|
||||
@@ -19,7 +20,26 @@ auto V9938::Background::run(n8 x, n8 y) -> void {
|
||||
}
|
||||
|
||||
auto V9938::Background::text1(n8 hoffset, n8 voffset) -> void {
|
||||
debug(unimplemented, "[V9938::Background::text1]");
|
||||
// Offset by 6px and blank the last 10px to centre the display
|
||||
i32 x = hoffset - 6;
|
||||
if (x < 0) return;
|
||||
if (hoffset > 246) return;
|
||||
|
||||
n14 nameAddress = (voffset.bit(3,7) * 40) + (x / 6);
|
||||
nameAddress.bit(10,16) = io.nameTableAddress.bit(10,16);
|
||||
|
||||
n8 pattern = self.vram.read(nameAddress);
|
||||
|
||||
n14 patternAddress;
|
||||
patternAddress.bit( 0, 2) = voffset.bit(0,2);
|
||||
patternAddress.bit( 3,10) = pattern;
|
||||
patternAddress.bit(11,13) = io.patternTableAddress.bit(11,13);
|
||||
|
||||
n3 index = 7 - (x % 6);
|
||||
if(self.vram.read(patternAddress).bit(index)) {
|
||||
output.color[0] = self.io.colorForeground;
|
||||
output.color[1] = self.io.colorForeground;
|
||||
}
|
||||
}
|
||||
|
||||
auto V9938::Background::text2(n8 hoffset, n8 voffset) -> void {
|
||||
@@ -30,7 +50,7 @@ auto V9938::Background::graphic1(n8 hoffset, n8 voffset) -> void {
|
||||
n14 patternLayout;
|
||||
patternLayout.bit( 0, 4) = hoffset.bit(3,7);
|
||||
patternLayout.bit( 5, 9) = voffset.bit(3,7);
|
||||
patternLayout.bit(10,13) = io.nameTableAddress.bit(10,13);
|
||||
patternLayout.bit(10,16) = io.nameTableAddress.bit(10,16);
|
||||
n8 pattern = self.vram.read(patternLayout);
|
||||
|
||||
n14 patternGenerator;
|
||||
@@ -44,14 +64,15 @@ auto V9938::Background::graphic1(n8 hoffset, n8 voffset) -> void {
|
||||
|
||||
n8 color = self.vram.read(colorAddress);
|
||||
if(self.vram.read(patternGenerator).bit(~hoffset & 7)) color >>= 4;
|
||||
output.color = color.bit(0,3);
|
||||
output.color[0] = color.bit(0,3);
|
||||
output.color[1] = color.bit(0,3);
|
||||
}
|
||||
|
||||
auto V9938::Background::graphic2(n8 hoffset, n8 voffset) -> void {
|
||||
n14 patternLayout;
|
||||
patternLayout.bit( 0, 4) = hoffset.bit(3,7);
|
||||
patternLayout.bit( 5, 9) = voffset.bit(3,7);
|
||||
patternLayout.bit(10,13) = io.nameTableAddress.bit(10,13);
|
||||
patternLayout.bit(10,16) = io.nameTableAddress.bit(10,16);
|
||||
n8 pattern = self.vram.read(patternLayout);
|
||||
|
||||
n14 patternGenerator;
|
||||
@@ -67,7 +88,8 @@ auto V9938::Background::graphic2(n8 hoffset, n8 voffset) -> void {
|
||||
n8 colorMask = io.colorTableAddress.bit(6,12) << 1 | 1;
|
||||
n8 color = self.vram.read(colorAddress);
|
||||
if(self.vram.read(patternGenerator).bit(~hoffset & 7)) color >>= 4;
|
||||
output.color = color.bit(0,3);
|
||||
output.color[0] = color.bit(0,3);
|
||||
output.color[1] = color.bit(0,3);
|
||||
}
|
||||
|
||||
auto V9938::Background::graphic3(n8 hoffset, n8 voffset) -> void {
|
||||
@@ -82,11 +104,19 @@ auto V9938::Background::graphic4(n8 hoffset, n8 voffset) -> void {
|
||||
address += hoffset >> 1;
|
||||
auto data = self.vram.read(address);
|
||||
auto shift = !hoffset.bit(0) ? 4 : 0;
|
||||
output.color = n4(data >> shift);
|
||||
output.color[0] = n4(data >> shift);
|
||||
output.color[1] = n4(data >> shift);
|
||||
}
|
||||
|
||||
auto V9938::Background::graphic5(n8 hoffset, n8 voffset) -> void {
|
||||
debug(unimplemented, "[V9938::Background::graphic5]");
|
||||
n17 address = io.nameTableAddress & 0x18000;
|
||||
address += voffset << 7;
|
||||
address += hoffset >> 1;
|
||||
auto data = self.vram.read(address);
|
||||
auto shift = !hoffset.bit(0) ? 4 : 0;
|
||||
|
||||
output.color[0] = n2(data >> (shift + 2));
|
||||
output.color[1] = n2(data >> (shift + 0));
|
||||
}
|
||||
|
||||
auto V9938::Background::graphic6(n8 hoffset, n8 voffset) -> void {
|
||||
|
||||
@@ -5,13 +5,21 @@ auto V9938::DAC::setup(n8 voffset) -> void {
|
||||
}
|
||||
|
||||
auto V9938::DAC::run(n8 hoffset, n8 voffset) -> void {
|
||||
n4 color = self.io.colorBackground;
|
||||
n4 color[2];
|
||||
color[0] = self.io.colorBackground;
|
||||
color[1] = self.io.colorBackground;
|
||||
|
||||
if(io.enable) {
|
||||
if(self.background.output.color) color = self.background.output.color;
|
||||
if(self.sprite.output.color) color = self.sprite.output.color;
|
||||
if(self.background.output.color[0]) color[0] = self.background.output.color[0];
|
||||
if(self.background.output.color[1]) color[1] = self.background.output.color[1];
|
||||
|
||||
if(self.sprite.output.color) {
|
||||
color[0] = self.sprite.output.color;
|
||||
color[1] = self.sprite.output.color;
|
||||
}
|
||||
}
|
||||
*output++ = self.pram[color];
|
||||
*output++ = self.pram[color];
|
||||
*output++ = self.pram[color[0]];
|
||||
*output++ = self.pram[color[1]];
|
||||
}
|
||||
|
||||
auto V9938::DAC::power() -> void {
|
||||
|
||||
@@ -219,7 +219,7 @@ auto V9938::register(n6 register, n8 data) -> void {
|
||||
return;
|
||||
|
||||
case 0x17:
|
||||
background.io.vscroll = data;
|
||||
io.vscroll = data;
|
||||
return;
|
||||
|
||||
case 0x20: op.sx.bit(0,7) = data.bit(0,7); return;
|
||||
|
||||
Loaded 100 of 1457 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user