mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-08 17:03:47 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f533120df6 | ||
|
|
ec37caccfb | ||
|
|
d0b9669c50 | ||
|
|
dfb355495a | ||
|
|
0f618995f4 | ||
|
|
35ead94515 | ||
|
|
6c8ccc1c7e | ||
|
|
361fb49fd0 | ||
|
|
90139d028d | ||
|
|
d03915bde9 | ||
|
|
8a7549fb21 | ||
|
|
6003e6933b | ||
|
|
35671b2f8d | ||
|
|
43686810d2 | ||
|
|
9bd2afee61 | ||
|
|
7bcb9ae39f | ||
|
|
f39eac9b87 | ||
|
|
f370521a55 | ||
|
|
c763218430 | ||
|
|
2df5b97e5e | ||
|
|
0a7e1c5e4c | ||
|
|
2d80fca221 | ||
|
|
3b8baddfba | ||
|
|
5319fe68f0 | ||
|
|
6b11b281c4 | ||
|
|
c79a73e88c | ||
|
|
53a63d6ae2 | ||
|
|
c95ddfe754 | ||
|
|
bfed5a56f0 | ||
|
|
41275f4a8a | ||
|
|
9fcb4f93e4 | ||
|
|
11a7827eef | ||
|
|
b7de9976a6 | ||
|
|
9671ec7c3d | ||
|
|
cb4aec479f | ||
|
|
44f34f9bb2 | ||
|
|
90b6c0902d | ||
|
|
445cfacb10 | ||
|
|
7989498177 | ||
|
|
b38cacbab8 | ||
|
|
4b121c28d0 | ||
|
|
4e1b4b79ef | ||
|
|
18500e679b | ||
|
|
174eb5bcf2 | ||
|
|
8d32ab3f4f | ||
|
|
5cc3a8118f | ||
|
|
753ba2af6a | ||
|
|
757f326c33 | ||
|
|
fc36600a6a | ||
|
|
038bcb91c2 | ||
|
|
0b1714c8f6 | ||
|
|
76141ba703 | ||
|
|
064b2120e4 | ||
|
|
732d03f3af | ||
|
|
81d0f131c4 | ||
|
|
5d0ff02cb3 | ||
|
|
ba41375179 | ||
|
|
fe7f05fc1e | ||
|
|
cbe2b7be32 | ||
|
|
0d1152de1c | ||
|
|
eaf5e06683 | ||
|
|
0921eb8038 | ||
|
|
64c8354511 | ||
|
|
cd21ca7bf4 | ||
|
|
ded925451b | ||
|
|
b0d5be69d0 | ||
|
|
2f7fa79b07 | ||
|
|
4fd5318e52 | ||
|
|
810c508489 | ||
|
|
383a0870f1 | ||
|
|
9e4a00b968 | ||
|
|
a57cce6b94 | ||
|
|
74a561f62e | ||
|
|
52acac2933 | ||
|
|
9830daef91 | ||
|
|
2f9f7670da | ||
|
|
808aaaf053 | ||
|
|
1044d0ad37 | ||
|
|
0ebd9e3bbe | ||
|
|
57d1a2ef9a | ||
|
|
eeacac8749 | ||
|
|
9e1ff7b479 | ||
|
|
32d2f3d2b2 | ||
|
|
c64aff5992 | ||
|
|
3390d66a7e | ||
|
|
e388299f05 | ||
|
|
f31fa5c99f | ||
|
|
fec8d9029c | ||
|
|
c4bc76b219 | ||
|
|
7d91e5f38a | ||
|
|
907ccf6494 | ||
|
|
c7fabe82d6 | ||
|
|
9f9ff6bf09 | ||
|
|
f60c003826 | ||
|
|
6a30f98145 | ||
|
|
7855c8b469 | ||
|
|
ee85afd30c | ||
|
|
09932f11d5 | ||
|
|
85afab5b36 | ||
|
|
75ef6810e2 | ||
|
|
66db5eb88c | ||
|
|
d5c3a4805b | ||
|
|
82c777e7c2 | ||
|
|
cdbc88f92e | ||
|
|
970a019476 | ||
|
|
9c9ba5d6f4 | ||
|
|
86790da2ec | ||
|
|
7fff423649 | ||
|
|
d258228cc0 | ||
|
|
9bf3ffc3ae | ||
|
|
7168f2e411 | ||
|
|
c75ad74ce0 | ||
|
|
7ed8d6feac | ||
|
|
e2bf15a6ce | ||
|
|
29139b104c | ||
|
|
0b2a85f803 | ||
|
|
a55688a95d | ||
|
|
f39ca5e3a7 | ||
|
|
1a2aedcf00 | ||
|
|
05e9c3a6c9 | ||
|
|
0d9ce81d20 | ||
|
|
eed44e0012 | ||
|
|
93073f2700 | ||
|
|
53a08c9101 | ||
|
|
6540059a28 | ||
|
|
48c816f2f9 | ||
|
|
1edb30d1ea | ||
|
|
797c798787 | ||
|
|
2c3341dfdf | ||
|
|
31357eb4e5 | ||
|
|
3401322e6e | ||
|
|
50ed2ba9bc | ||
|
|
ff8bdbcdc6 | ||
|
|
935802da1a | ||
|
|
1dffa3d974 | ||
|
|
78144f5fab | ||
|
|
47aa5dc1df | ||
|
|
bf7a1a205c | ||
|
|
96bd51471d | ||
|
|
bbd9fcca0c | ||
|
|
f263e89f06 | ||
|
|
698ea74132 | ||
|
|
766fc1ece2 | ||
|
|
247dd180ce | ||
|
|
23ed3de93c | ||
|
|
c0791baa3d | ||
|
|
9ad89d134e | ||
|
|
84ce0e3d9f | ||
|
|
92fe0d2e44 | ||
|
|
864ca3d91e | ||
|
|
8729c5f591 | ||
|
|
89be74aab5 | ||
|
|
24c5e367cc | ||
|
|
5004ca4a33 | ||
|
|
799d0ce726 | ||
|
|
47348d9002 | ||
|
|
3eeecf1cc2 | ||
|
|
31380a1976 | ||
|
|
6974764393 | ||
|
|
0e73ba0cc1 | ||
|
|
5bb5a70b0c | ||
|
|
2830ab92f7 | ||
|
|
2eb0e677a8 | ||
|
|
a5f5eccdbe | ||
|
|
82ff8dbf6b | ||
|
|
c9d8fc525c | ||
|
|
3854a4561d | ||
|
|
cf4afeb7f0 | ||
|
|
755e15c3e1 | ||
|
|
7f0d020466 | ||
|
|
5a2be88f41 | ||
|
|
be570117bb | ||
|
|
640fe5722c | ||
|
|
dff1ad01a6 | ||
|
|
e7a00354dc | ||
|
|
f042f7a51a | ||
|
|
4d92a5b433 | ||
|
|
4aed87bf45 | ||
|
|
a5e76e2e4e | ||
|
|
c7277c964e | ||
|
|
846b622c80 | ||
|
|
abcdff3e60 | ||
|
|
4fcfe3a485 | ||
|
|
76b0204d91 | ||
|
|
cac6f0534a | ||
|
|
f66bb568df | ||
|
|
cc4556824e | ||
|
|
c6f7efb797 | ||
|
|
6a2fcb21dc | ||
|
|
2b347c65de | ||
|
|
f1823630be | ||
|
|
41d1b7e57d | ||
|
|
c28ba81684 | ||
|
|
1561a1d0b4 | ||
|
|
0a302dcf0e | ||
|
|
07051ab738 | ||
|
|
973030ab67 | ||
|
|
67716bcedf | ||
|
|
e06b748516 | ||
|
|
02dac5b4b7 | ||
|
|
a4b8571b61 | ||
|
|
a3fa22b5fc | ||
|
|
9e9b6f8642 | ||
|
|
5f6a0983bd | ||
|
|
2fcab5ca5f | ||
|
|
778a32700d | ||
|
|
a6577318b6 | ||
|
|
badd476d3b | ||
|
|
5a3548402b | ||
|
|
c1f0307a8d | ||
|
|
77c0718df4 | ||
|
|
30bff8dd06 | ||
|
|
b1cf9bf4e5 | ||
|
|
bafc2b6ef4 | ||
|
|
565591568f | ||
|
|
9df891606f | ||
|
|
eea666317b | ||
|
|
ceff1d47a6 | ||
|
|
81dea4cf7e | ||
|
|
17fa3b58a6 | ||
|
|
70fa70fff4 | ||
|
|
137afe5b5b | ||
|
|
545790f048 | ||
|
|
807ef03005 | ||
|
|
ce89a31749 | ||
|
|
3e7675cafb | ||
|
|
4132375f26 | ||
|
|
5e0bd5b3b8 | ||
|
|
d00c84ff1b | ||
|
|
97f3a7a6fb | ||
|
|
8c656cdfd3 | ||
|
|
bea395b24b | ||
|
|
6992197fb8 | ||
|
|
097698ab63 | ||
|
|
46abceebf5 | ||
|
|
06130778b7 | ||
|
|
85b8d6c5a5 | ||
|
|
8436634bc1 | ||
|
|
5972b4e1aa | ||
|
|
426606bd02 | ||
|
|
f9604e29e6 | ||
|
|
7d7b8ea4b2 | ||
|
|
2ed529d564 | ||
|
|
73148db456 | ||
|
|
2fbc9c391c | ||
|
|
12f3d6d89d | ||
|
|
78c13dddef | ||
|
|
be19b58307 | ||
|
|
bca80dc784 | ||
|
|
e6fe07b084 | ||
|
|
c28e47cb93 | ||
|
|
c217662211 | ||
|
|
975a35e7a7 | ||
|
|
2e9233e534 | ||
|
|
4c6d151f7f | ||
|
|
383931bde9 | ||
|
|
1ac8c602c9 | ||
|
|
d5135ca35f | ||
|
|
8265726879 | ||
|
|
5261757f3c | ||
|
|
c099be2b85 | ||
|
|
de8143ef47 | ||
|
|
b80f08956b | ||
|
|
a3088f6d4c | ||
|
|
fdaf0b65a1 | ||
|
|
71e0ad1f5b | ||
|
|
c87be1b4f0 | ||
|
|
625df94505 | ||
|
|
0dc80ee4a2 | ||
|
|
f373fdc165 | ||
|
|
68f2c94658 | ||
|
|
11750b9600 | ||
|
|
135cadd32f | ||
|
|
f015fffd69 | ||
|
|
aa7260a58d | ||
|
|
cdd551f122 | ||
|
|
f3ce7952f6 | ||
|
|
9b1eb2e2f9 | ||
|
|
c337ba258f | ||
|
|
6f16c5c17e | ||
|
|
b494705ad7 | ||
|
|
371ba7b136 | ||
|
|
fb685afa70 | ||
|
|
f3ff75feb1 | ||
|
|
5211e6c56d | ||
|
|
e3c5cfb44d | ||
|
|
c95b48d95f | ||
|
|
136afead52 | ||
|
|
0865680da1 | ||
|
|
08811ee3cb | ||
|
|
b79ed895ff | ||
|
|
ece74e44e4 | ||
|
|
b1c69c9f3f | ||
|
|
4c42273a07 | ||
|
|
ac58451996 | ||
|
|
325c0ed876 | ||
|
|
f89777d8cc | ||
|
|
f0fd4c0bd2 | ||
|
|
a3d8db1c2a | ||
|
|
073d7a5375 | ||
|
|
264a1baafa | ||
|
|
645be6ab9b | ||
|
|
67fc2b1073 | ||
|
|
46b1991f8f | ||
|
|
c9dfe8a1b9 | ||
|
|
af07e1f863 | ||
|
|
b624fadd75 | ||
|
|
46209710d7 | ||
|
|
90eb0df7d7 | ||
|
|
64c9751dc5 | ||
|
|
54e3479708 | ||
|
|
9186ec0201 | ||
|
|
64196caef8 | ||
|
|
1d0d6177a5 | ||
|
|
421b7abf96 | ||
|
|
7e9df5858d | ||
|
|
69381f7c54 | ||
|
|
8f55894d65 | ||
|
|
4e1435be8a | ||
|
|
cf0c21e15a | ||
|
|
e10ce79153 | ||
|
|
ad7b83b604 | ||
|
|
53f3b6a2a2 | ||
|
|
b630377ddc | ||
|
|
24a9c00ae7 | ||
|
|
b5488aad82 | ||
|
|
5f782419ae | ||
|
|
7d5c6d2561 | ||
|
|
585e43a94c | ||
|
|
28ab75242f | ||
|
|
4dd7a1f5fe | ||
|
|
756ea5b704 | ||
|
|
7c051bae0b | ||
|
|
edfc6b5fb0 | ||
|
|
cdc0633fdd | ||
|
|
71facd2e14 | ||
|
|
af95d2b760 | ||
|
|
f4f48eb4b9 | ||
|
|
667827ab00 | ||
|
|
70480452a8 | ||
|
|
a70acad605 | ||
|
|
dca8745f83 | ||
|
|
fabbdc8d8f | ||
|
|
1a79a0aae0 | ||
|
|
de066b1ea2 | ||
|
|
c185fbd66e | ||
|
|
dae8db9883 | ||
|
|
4c4b2a5e5a | ||
|
|
510ccf01d7 | ||
|
|
aab2fdf9b2 | ||
|
|
e2d7106a6c | ||
|
|
1598f67506 | ||
|
|
5d3f614c63 | ||
|
|
8ef16dfbd9 | ||
|
|
701cfb7b13 | ||
|
|
ae121d7377 | ||
|
|
ed1e34c74e | ||
|
|
728105b28e | ||
|
|
3d88e24559 | ||
|
|
a61ce6449f | ||
|
|
63aa9ec5e4 | ||
|
|
50e42627e2 | ||
|
|
3a46652b15 | ||
|
|
7528feabe8 | ||
|
|
e57a80ea1b | ||
|
|
4c0a03b35a | ||
|
|
a247271e35 | ||
|
|
d61cfa905a | ||
|
|
9987bf18b2 | ||
|
|
8a80d32519 | ||
|
|
5d0de5fbb3 | ||
|
|
f06168e3f5 | ||
|
|
828f847efe | ||
|
|
d8c997ca8a | ||
|
|
93137b76b4 | ||
|
|
b889aff3d4 | ||
|
|
70f3bfa00c | ||
|
|
d942746f74 | ||
|
|
1c05456bec | ||
|
|
240363d31a | ||
|
|
ebb3bcb37b | ||
|
|
ab14fb1d10 | ||
|
|
7ba94fe7e4 | ||
|
|
69ea086d95 | ||
|
|
a510ac7e55 | ||
|
|
ac98fd8d9c | ||
|
|
122820753e | ||
|
|
e355fbe88c | ||
|
|
c1efa05d65 | ||
|
|
da071246fe | ||
|
|
cca0ecf202 | ||
|
|
17aee9071d | ||
|
|
b92ae8a14c | ||
|
|
4ae42b2d44 | ||
|
|
2a11da200d | ||
|
|
cbf4a939aa | ||
|
|
d10a8498e2 | ||
|
|
2eb6bf6df8 | ||
|
|
35ede44b80 | ||
|
|
0c011fb2d4 | ||
|
|
a006ef97e7 | ||
|
|
14a4f32997 | ||
|
|
25c1e281cc | ||
|
|
3ee7556bb7 | ||
|
|
a5b11b13d0 | ||
|
|
01e6cc1443 | ||
|
|
f5dace0a0f | ||
|
|
6b5ebb2882 | ||
|
|
140782662b | ||
|
|
3daec1184a | ||
|
|
7e4386c1bf | ||
|
|
8eba8ad784 | ||
|
|
08377d02e2 | ||
|
|
ea4ad6890a | ||
|
|
50be2e4e63 | ||
|
|
effc5614bc | ||
|
|
5f81464857 | ||
|
|
bd8442605e | ||
|
|
da312032de | ||
|
|
c509dd3964 | ||
|
|
10a4d480de | ||
|
|
8c3ead7cb0 | ||
|
|
1b36d47554 | ||
|
|
2c940b03a1 | ||
|
|
7a5174a712 | ||
|
|
274d6eb9a5 | ||
|
|
de0cb099cb | ||
|
|
32fd70f7c7 | ||
|
|
b2251305c0 | ||
|
|
25a2602300 | ||
|
|
4480f7adec | ||
|
|
4197502402 | ||
|
|
fb96de3eef | ||
|
|
54c898f199 | ||
|
|
e48b208de2 | ||
|
|
a9f9fd90e7 | ||
|
|
deb8830c82 | ||
|
|
58af8cb64b | ||
|
|
c9285b5289 | ||
|
|
4fc09438d2 | ||
|
|
a0a7a53b32 | ||
|
|
90f1425b8e | ||
|
|
9f4446061d | ||
|
|
32e58943f0 | ||
|
|
bc116e70e1 | ||
|
|
992e1c08cb | ||
|
|
9dcc1a39d3 | ||
|
|
9bbcf638dd | ||
|
|
d6c8d36770 | ||
|
|
c19cf47803 | ||
|
|
1d5a5aef83 | ||
|
|
64ec01bd57 | ||
|
|
82b1e88ec1 | ||
|
|
a592dc24d2 | ||
|
|
976b9828b6 | ||
|
|
7f625b6348 | ||
|
|
23a9d66924 | ||
|
|
e4e9044097 | ||
|
|
04a51df859 | ||
|
|
0c80c1e56b | ||
|
|
6f7618dc81 | ||
|
|
fdd7acb76b | ||
|
|
7ce2ffd010 | ||
|
|
bb22386f5f | ||
|
|
b372f65691 | ||
|
|
048d0e331d | ||
|
|
1323a627b3 | ||
|
|
b4ef96e4d6 | ||
|
|
8d2f88b745 | ||
|
|
ca7eee17a9 | ||
|
|
9ef81df3cf | ||
|
|
68af829f8e | ||
|
|
56862e0026 | ||
|
|
09d8af1c18 | ||
|
|
d20bc3c1b0 | ||
|
|
97c82119b5 | ||
|
|
b78228c5c0 | ||
|
|
5107ed00cb | ||
|
|
aeff8ec8f9 | ||
|
|
7640e1598c | ||
|
|
04c608a21e | ||
|
|
8a75015d7e | ||
|
|
330a329abc | ||
|
|
a21f8c074c | ||
|
|
c899461cf1 | ||
|
|
512b53f808 | ||
|
|
2fb2da047c | ||
|
|
cdbd9e0d2c | ||
|
|
745e41a6ee | ||
|
|
ab40ecbb9b | ||
|
|
72ead4d2a6 | ||
|
|
aef110f35d | ||
|
|
e99c9c57b0 | ||
|
|
9c273abec3 | ||
|
|
6cc9f5a416 | ||
|
|
69c20711fc | ||
|
|
539aa9b7d6 | ||
|
|
5d7dbb7eed | ||
|
|
6176287392 | ||
|
|
ce2e6f8c19 | ||
|
|
76ab41c69c | ||
|
|
928d76b0b5 | ||
|
|
c1949d8eb5 | ||
|
|
6946437115 | ||
|
|
76a5f8e1da | ||
|
|
bf9aae53d0 | ||
|
|
1a5559a24b | ||
|
|
af5fa1a1c8 | ||
|
|
4c367fd32f | ||
|
|
2d714d1a9c | ||
|
|
8dbd2135b7 | ||
|
|
c62e2a254c | ||
|
|
dfcd7d4fce | ||
|
|
fa1c21ba3d | ||
|
|
a584782a86 | ||
|
|
6185edc43b | ||
|
|
7772fdbf0a | ||
|
|
fd8bcad5a1 | ||
|
|
da7a79b21e | ||
|
|
639ebe6285 | ||
|
|
9be2f9bb92 | ||
|
|
ce71fff00c | ||
|
|
a91b24acf1 | ||
|
|
c5d316274a | ||
|
|
8444f52843 | ||
|
|
d775c0968b | ||
|
|
c76b87cdb2 | ||
|
|
2197df8cca | ||
|
|
324a192109 | ||
|
|
4a9b77a5e1 | ||
|
|
a27c2a2b3a | ||
|
|
34124fd1cc | ||
|
|
f6b58b076b | ||
|
|
b4b026db28 | ||
|
|
05898a6a04 | ||
|
|
331c4956b0 | ||
|
|
d6c42e59e4 | ||
|
|
58661451ed | ||
|
|
e808d2c5ab | ||
|
|
445acba894 | ||
|
|
07fa6bc265 | ||
|
|
3e5ed40801 | ||
|
|
10b747c305 | ||
|
|
2ed2ed34bc | ||
|
|
41b61ee6d5 | ||
|
|
a960aeef52 | ||
|
|
1eb0a1659a | ||
|
|
c19a2ac1b2 | ||
|
|
8642d35e5f | ||
|
|
80db392140 | ||
|
|
a2400ad43a | ||
|
|
e8cd9b3e04 | ||
|
|
e04922c4d5 | ||
|
|
69795d578a | ||
|
|
8433666dc2 | ||
|
|
ecdce5e92b | ||
|
|
0b4fea8ce5 | ||
|
|
5bcef4741a | ||
|
|
3b18a3f808 | ||
|
|
7d327a2c8a | ||
|
|
07bafb6a51 | ||
|
|
1bb1669b03 | ||
|
|
a752b85d6f | ||
|
|
a02c0f80de | ||
|
|
50ceb088ef | ||
|
|
65618ce1e2 | ||
|
|
4691971416 | ||
|
|
98d9eb7786 | ||
|
|
431aba5a1a | ||
|
|
78e5332361 | ||
|
|
687bfe8efc | ||
|
|
7cc6d517a2 | ||
|
|
3bd385e4a8 | ||
|
|
de2d7d86c9 | ||
|
|
a0d8ce25c5 | ||
|
|
557ecb5319 | ||
|
|
8cc98f94ae | ||
|
|
7e5d749adc | ||
|
|
675d57b6fa | ||
|
|
28cfa89970 | ||
|
|
8668f98fa5 | ||
|
|
8f772cdb01 | ||
|
|
229e16df98 | ||
|
|
36290b9705 | ||
|
|
014d0130f5 | ||
|
|
d6465d0daa | ||
|
|
802a902cd3 | ||
|
|
2bf4e28db5 | ||
|
|
1469299363 |
No files matched your search
@@ -0,0 +1,8 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/BlankSpruce/gersemi/master/gersemi/configuration.schema.json
|
||||
|
||||
definitions: [ares/CMakeLists.txt]
|
||||
line_length: 120
|
||||
indent: 2
|
||||
list_expansion: favour-inlining
|
||||
unsafe: false
|
||||
warn_about_unknown_commands: false
|
||||
@@ -0,0 +1,2 @@
|
||||
# When archiving, export a version file containing tag/commit information
|
||||
cmake/common/.archive-version.json export-subst
|
||||
@@ -0,0 +1,31 @@
|
||||
# dummy GitHub target used to enable editing of GitHub files within generated IDE projects
|
||||
|
||||
add_library(.github INTERFACE)
|
||||
|
||||
set(.github_sources
|
||||
ISSUE_TEMPLATE/bug_report.md
|
||||
ISSUE_TEMPLATE/feature_request.md
|
||||
ISSUE_TEMPLATE/game-issue-report.md
|
||||
scripts/build_macos.sh
|
||||
scripts/build_ubuntu.sh
|
||||
scripts/build_windows.sh
|
||||
scripts/package_artifacts.sh
|
||||
workflows/build-aux.yml
|
||||
workflows/build.yml
|
||||
workflows/pr.yml
|
||||
workflows/push.yml
|
||||
workflows/release.yml
|
||||
)
|
||||
|
||||
target_sources(
|
||||
.github
|
||||
PRIVATE
|
||||
${.github_sources}
|
||||
../.gitignore
|
||||
../.gitattributes
|
||||
../README.md
|
||||
../LICENSE
|
||||
)
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${.github_sources})
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env sh
|
||||
set -euo pipefail
|
||||
|
||||
# configure
|
||||
cmake --preset $TARGET_PRESET
|
||||
|
||||
# change into the build directory
|
||||
pushd build
|
||||
|
||||
# build; pipe output to render warnings neatly
|
||||
xcodebuild -configuration RelWithDebInfo \
|
||||
DEBUG_INFORMATION_FORMAT="dwarf-with-dsym" \
|
||||
-parallelizeTargets \
|
||||
2>&1 | xcbeautify --renderer github-actions
|
||||
|
||||
popd
|
||||
|
||||
# package debug symbols
|
||||
|
||||
# move dependency dSYMs to build output directory
|
||||
ditto .deps/ares-deps-macos-universal/lib/*.dSYM build/desktop-ui/RelWithDebInfo
|
||||
|
||||
mkdir build/dsyms
|
||||
|
||||
# ares.app.dSYM already exists alongside ares.app; package it with the rest
|
||||
mv build/desktop-ui/RelWithDebInfo/*.dSYM build/dSYMs/
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# configure
|
||||
cmake --preset $TARGET_PRESET
|
||||
|
||||
# change into the build directory
|
||||
pushd build
|
||||
|
||||
ninja
|
||||
|
||||
popd
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env sh
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$CROSS_COMPILE" = true ]; then
|
||||
cmake --preset $NATIVE_PRESET -B build_native
|
||||
pushd build_native
|
||||
# build sourcery natively so it may be invoked during cross-compilation
|
||||
cmake --build . --target sourcery --config RelWithDebInfo
|
||||
popd
|
||||
fi
|
||||
|
||||
cmake --preset $TARGET_PRESET
|
||||
pushd build
|
||||
cmake --build . --config RelWithDebInfo
|
||||
|
||||
if [ "$CROSS_COMPILE" = true ] || [ "$ARES_PLATFORM_NAME" = "windows-arm64" ]; then
|
||||
cp ../.deps/ares-deps-windows-arm64/lib/*.pdb desktop-ui/rundir/
|
||||
else
|
||||
cp ../.deps/ares-deps-windows-x64/lib/*.pdb desktop-ui/rundir/
|
||||
fi
|
||||
|
||||
mkdir PDBs
|
||||
mv desktop-ui/rundir/*.pdb PDBs/
|
||||
popd
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
set -eu
|
||||
case ${GITHUB_REF} in
|
||||
refs/tags/*) suffix="-${GITHUB_REF#refs/tags/}" ;;
|
||||
refs/heads/master) suffix="-nightly" ;;
|
||||
*) suffix="" ;;
|
||||
esac
|
||||
|
||||
bindir="${GITHUB_WORKSPACE}/bin"
|
||||
|
||||
# Hack: Workaround for GitHub artifacts losing attributes.
|
||||
chmod +x ${bindir}/ares-macos-universal/ares.app/Contents/MacOS/ares
|
||||
|
||||
for package in macos-universal
|
||||
do
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
|
||||
# Package ares.
|
||||
outdir=ares${suffix}
|
||||
mkdir ${outdir}
|
||||
mkdir ${outdir}-dSYMs
|
||||
cp -a ${bindir}/ares-${package}-dSYMs/*.dSYM ${outdir}-dSYMs
|
||||
cp -a ${bindir}/ares-${package}/*.app ${outdir}
|
||||
zip -r -y ../ares-${package}.zip ${outdir}
|
||||
zip -r -y ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
|
||||
cd -
|
||||
done
|
||||
|
||||
for package in windows-x64 windows-clang-cl-arm64
|
||||
do
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
|
||||
# Package ares.
|
||||
outdir=ares${suffix}
|
||||
mkdir ${outdir}
|
||||
mkdir ${outdir}-PDBs
|
||||
cp -a ${bindir}/ares-${package}-PDBs/*.pdb ${outdir}-PDBs
|
||||
zip -r ../ares-${package}-PDBs.zip ${outdir}-PDBs
|
||||
rm -rf ${bindir}/ares-${package}/PDBs
|
||||
cp -a ${bindir}/ares-${package}/* ${outdir}
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
cd -
|
||||
done
|
||||
|
||||
# Package the source archive
|
||||
pushd src
|
||||
git archive --format=tar.gz -o ../ares-source.tar.gz HEAD
|
||||
popd
|
||||
@@ -0,0 +1,132 @@
|
||||
name: Build (Auxiliary)
|
||||
on:
|
||||
workflow_call
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
program:
|
||||
- ares
|
||||
config:
|
||||
- RelWithDebInfo
|
||||
platform:
|
||||
- name: windows-x64-gcc
|
||||
os: windows-latest
|
||||
shell: 'msys2 {0}'
|
||||
msystem: mingw64
|
||||
install: make git cmake ccache ninja mingw-w64-x86_64-toolchain
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-clang-cl-x64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-cl-native
|
||||
- name: windows-arm64
|
||||
os: windows-11-arm
|
||||
compiler: clang++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clangarm64
|
||||
install: mingw-w64-clang-aarch64-make git mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ccache mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-clang
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-msvc-x64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-msvc-native
|
||||
- name: windows-msvc-arm64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-msvc-cross
|
||||
native-cmake-preset: windows-ci-msvc-native
|
||||
- name: ubuntu-gcc-x64
|
||||
os: ubuntu-24.04
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci
|
||||
- name: ubuntu-gcc-arm64
|
||||
os: ubuntu-24.04-arm
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci
|
||||
- name: ubuntu-clang-x64
|
||||
os: ubuntu-24.04
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-clang
|
||||
- name: ubuntu-clang-arm64
|
||||
os: ubuntu-24.04-arm
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-clang
|
||||
- name: ubuntu-gcc-arm64-qt
|
||||
os: ubuntu-24.04-arm
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-qt
|
||||
- name: freebsd
|
||||
os: ubuntu-24.04
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-clang
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.platform.shell }}
|
||||
steps:
|
||||
- name: Install MSYS2 Dependencies
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: ${{ matrix.platform.install }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
- name: Setup MSYS2 Git Environment
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
run: |
|
||||
git config core.autocrlf true
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux' && matrix.platform.name != 'freebsd'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev qt6-base-dev
|
||||
- name: "Build: Linux"
|
||||
if: runner.os == 'Linux' && matrix.platform.name != 'freebsd'
|
||||
run: .github/scripts/build_ubuntu.sh
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Build: Windows"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: .github/scripts/build_windows.sh
|
||||
env:
|
||||
ARES_PLATFORM_NAME: ${{ matrix.platform.name }}
|
||||
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
|
||||
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Build: FreeBSD"
|
||||
if: matrix.platform.name == 'freebsd'
|
||||
uses: cross-platform-actions/action@e8a7b572196ff79ded1979dc2bb9ee67d1ddb252
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: 14.3
|
||||
environment_variables: TARGET_PRESET
|
||||
run: |
|
||||
sudo pkg install -y cmake pkgconf ccache ninja gtk3 libX11 libXext libXrandr libXrender libglvnd alsa-lib libao libudev-devd librashader openal-soft pulseaudio sdl3 vulkan-loader
|
||||
.github/scripts/build_ubuntu.sh
|
||||
- name: "Compress Build Artifacts (Windows)"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: |
|
||||
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/rundir/ .
|
||||
- name: Upload Build
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: ares-${{ matrix.platform.name }}.tar.xz
|
||||
- name: Upload Debug Symbols (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
|
||||
path: build/PDBs/*
|
||||
+85
-285
@@ -1,10 +1,17 @@
|
||||
name: Build
|
||||
name: Build (Primary)
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags: [ 'v*' ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_call:
|
||||
inputs:
|
||||
codesign:
|
||||
description: Enable codesigning
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
official:
|
||||
description: Use official version strings
|
||||
required: true
|
||||
default: true
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -12,57 +19,28 @@ jobs:
|
||||
matrix:
|
||||
program:
|
||||
- ares
|
||||
config:
|
||||
- RelWithDebInfo
|
||||
platform:
|
||||
- name: windows
|
||||
- name: windows-x64
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
windres: windres
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-pkgconf mingw-w64-clang-x86_64-SDL2
|
||||
- name: windows-arm64
|
||||
install: make git cmake ccache ninja mingw-w64-clang-x86_64-clang
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-clang-cl-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 mingw-w64-clang-aarch64-pkgconf mingw-w64-clang-aarch64-SDL2
|
||||
- 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-compat
|
||||
os: macos-12
|
||||
target-cmake-preset: windows-ci-cl-cross
|
||||
native-cmake-preset: windows-ci-cl-native
|
||||
- name: macos-universal
|
||||
os: macos-15
|
||||
compiler: clang++
|
||||
shell: sh
|
||||
- name: macos-latest
|
||||
os: macos-latest
|
||||
compiler: clang++
|
||||
shell: sh
|
||||
- name: ubuntu
|
||||
os: ubuntu-latest
|
||||
compiler: g++
|
||||
shell: sh
|
||||
install: cmake ccache xcbeautify
|
||||
target-cmake-preset: macos-ci-universal
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
defaults:
|
||||
@@ -71,264 +49,86 @@ jobs:
|
||||
steps:
|
||||
- name: Install MSYS2 Dependencies
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
uses: msys2/setup-msys2@v2
|
||||
uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: make ${{ matrix.platform.install }}
|
||||
install: ${{ matrix.platform.install }}
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && inputs.codesign
|
||||
uses: apple-actions/import-codesign-certs@65cfbc37e1464d733524cb555b724878f278b8c3
|
||||
continue-on-error: ${{ secrets.MACOS_CERTIFICATE_NAME == '' }}
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
- name: Setup MSYS2 Git Environment
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
run: |
|
||||
git config core.autocrlf true
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
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'
|
||||
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
|
||||
uses: wpilibsuite/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@v4
|
||||
- name: Install Windows Dependencies
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
export PATH="/c/Users/runneradmin/.cargo/bin:$PATH" # correct on windows-latest as of 2024-02-19
|
||||
if [[ ${{ matrix.platform.name }} == *-arm64 ]]; then
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
rustup target add aarch64-pc-windows-msvc
|
||||
pushd thirdparty/librashader
|
||||
./build-librashader.sh aarch64-pc-windows-msvc
|
||||
popd
|
||||
else
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
pushd thirdparty/librashader
|
||||
./build-librashader.sh
|
||||
popd
|
||||
fi
|
||||
- name: "macOS: recover MoltenVK cache"
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: moltenvk
|
||||
with:
|
||||
path: thirdparty/MoltenVK/MoltenVK
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('thirdparty/MoltenVK/HEAD') }}
|
||||
sudo apt-get install ${{ matrix.platform.install }}
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
if [ $ImageOS == "macos14" ]; then
|
||||
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.13
|
||||
echo "Set Xcode version to 15.2 for macos-latest build."
|
||||
elif [ $ImageOS == "macos12" ]; then
|
||||
sudo xcode-select -s /Applications/Xcode_13.4.app/Contents/Developer
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
echo "Set Xcode version to 13.4 for macos-compat build."
|
||||
fi
|
||||
brew install make ninja cmake
|
||||
pip install --no-input setuptools
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
rustup target add x86_64-apple-darwin
|
||||
rustup target add aarch64-apple-darwin
|
||||
echo "MAKE=gmake" >> $GITHUB_ENV
|
||||
pushd thirdparty/SDL
|
||||
./build-SDL.sh
|
||||
popd
|
||||
pushd thirdparty/MoltenVK
|
||||
./build-moltenvk.sh
|
||||
popd
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
pushd thirdparty/librashader
|
||||
./build-librashader.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
|
||||
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 build=optimized local=false
|
||||
brew uninstall --ignore-dependencies cmake
|
||||
brew install ${{ matrix.platform.install }}
|
||||
- name: "Build: Windows"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: .github/scripts/build_windows.sh
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_KEYCHAIN_NAME: ares-macos-keychain
|
||||
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
ARES_BUILD_OFFICIAL: ${{ inputs.official }}
|
||||
ARES_PLATFORM_NAME: ${{ matrix.platform.name }}
|
||||
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
|
||||
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Windows: sign"
|
||||
if: runner.os == 'Windows' && github.event_name != 'pull_request'
|
||||
if: runner.os == 'Windows' && inputs.codesign
|
||||
continue-on-error: true
|
||||
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'
|
||||
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
|
||||
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
|
||||
folder: 'build/desktop-ui/rundir/'
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
- name: "Build: macOS"
|
||||
if: runner.os == 'macOS'
|
||||
run: .github/scripts/build_macos.sh
|
||||
env:
|
||||
MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
|
||||
MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
|
||||
ARES_BUILD_OFFICIAL: ${{ inputs.official }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: "Compress Build Artifact (macOS)"
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/RelWithDebInfo/ .
|
||||
- name: "Compress Build Artifacts (Windows)"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: |
|
||||
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/rundir/ .
|
||||
- name: Upload Build
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: desktop-ui/out/*
|
||||
|
||||
|
||||
release:
|
||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
path: ares-${{ matrix.platform.name }}.tar.xz
|
||||
- name: Upload Debug Symbols (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
path: 'src'
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
|
||||
path: build/PDBs/*
|
||||
- name: Upload Debug Symbols (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
path: 'bin'
|
||||
- name: Package Artifacts
|
||||
run: |
|
||||
set -eu
|
||||
case ${GITHUB_REF} in
|
||||
refs/tags/*) suffix="-${GITHUB_REF#refs/tags/}" ;;
|
||||
refs/heads/master) suffix="-nightly" ;;
|
||||
*) suffix="" ;;
|
||||
esac
|
||||
|
||||
srcdir="${GITHUB_WORKSPACE}/src"
|
||||
bindir="${GITHUB_WORKSPACE}/bin"
|
||||
|
||||
# Hack: Workaround for GitHub artifacts losing attributes.
|
||||
chmod +x ${bindir}/ares-macos-latest/ares.app/Contents/MacOS/ares
|
||||
chmod +x ${bindir}/ares-macos-compat/ares.app/Contents/MacOS/ares
|
||||
|
||||
for package in windows windows-msvc-arm64 macos-latest macos-compat
|
||||
do
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
|
||||
# Package ares.
|
||||
outdir=ares${suffix}
|
||||
mkdir ${outdir}
|
||||
cp -ar ${bindir}/ares-${package}/* ${outdir}
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
|
||||
cd -
|
||||
done
|
||||
- name: Create Release
|
||||
id: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -eu
|
||||
github_rest()
|
||||
{
|
||||
local method="${1}"
|
||||
local url="https://api.github.com${2}"
|
||||
shift 2
|
||||
>&2 echo "${method} ${url}"
|
||||
curl \
|
||||
--fail \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||
-X "${method}" \
|
||||
"${url}" \
|
||||
"$@"
|
||||
}
|
||||
github_get_release_id_for_tag()
|
||||
{
|
||||
payload=$(github_rest GET "/repos/${GITHUB_REPOSITORY}/releases/tags/${1}") || return
|
||||
echo "${payload}" | jq .id
|
||||
}
|
||||
github_delete_release_by_id()
|
||||
{
|
||||
github_rest DELETE "/repos/${GITHUB_REPOSITORY}/releases/${1}"
|
||||
}
|
||||
github_create_release()
|
||||
{
|
||||
local payload="{
|
||||
\"tag_name\": \"${1}\",
|
||||
\"target_commitish\": \"${2}\",
|
||||
\"name\": \"${3}\",
|
||||
\"body\": \"${4}\",
|
||||
\"draft\": ${5},
|
||||
\"prerelease\": ${6}
|
||||
}"
|
||||
github_rest POST "/repos/${GITHUB_REPOSITORY}/releases" -d "${payload}"
|
||||
}
|
||||
make_nightly_release()
|
||||
{
|
||||
github_create_release \
|
||||
nightly \
|
||||
"${GITHUB_SHA}" \
|
||||
"ares nightly $(date +"%Y-%m-%d")" \
|
||||
"Auto-generated nightly release on $(date -u +"%Y-%m-%d %T %Z")" \
|
||||
false \
|
||||
true
|
||||
}
|
||||
make_version_release()
|
||||
{
|
||||
github_create_release \
|
||||
"${1}" \
|
||||
"${GITHUB_SHA}" \
|
||||
"ares ${1}" \
|
||||
"This is ares ${1}, released on $(date +"%Y-%m-%d")." \
|
||||
false \
|
||||
false
|
||||
}
|
||||
case ${GITHUB_REF} in
|
||||
refs/tags/*)
|
||||
# Create a new version release using the current revision.
|
||||
echo "UPLOAD_URL=$(make_version_release ${GITHUB_REF#refs/tags/} | jq -r .upload_url)" >> $GITHUB_ENV
|
||||
;;
|
||||
refs/heads/master)
|
||||
# Check for an existing nightly release.
|
||||
{ release_id=$(github_get_release_id_for_tag nightly); status=$?; } || true
|
||||
# Delete existing nightly release if it exists.
|
||||
case ${status} in
|
||||
0) github_delete_release_by_id "${release_id}" ;;
|
||||
22) >&2 echo "No current nightly release; skipping tag deletion." ;;
|
||||
*) >&2 echo "API call failed unexpectedly." && exit 1 ;;
|
||||
esac
|
||||
# Create a new nightly release using the current revision.
|
||||
echo "UPLOAD_URL=$(make_nightly_release | jq -r .upload_url)" >> $GITHUB_ENV
|
||||
;;
|
||||
esac
|
||||
- name: Upload ares-windows
|
||||
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-latest
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-latest.zip', asset_name: 'ares-macos-latest.zip', asset_content_type: 'application/zip' }
|
||||
- name: Upload ares-macos-compat
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-compat.zip', asset_name: 'ares-macos-compat.zip', asset_content_type: 'application/zip' }
|
||||
# - name: Upload ares-ubuntu
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
# with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-ubuntu.zip', asset_name: 'ares-ubuntu.zip', asset_content_type: 'application/zip' }
|
||||
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
|
||||
path: build/dSYMs/*
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Pull Request
|
||||
run-name: ${{ github.event.pull_request.title }} PR run
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
types: [ opened, synchronize, reopened ]
|
||||
permissions:
|
||||
contents: read
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
build-project:
|
||||
name: Build ares (primary)
|
||||
uses: ./.github/workflows/build.yml
|
||||
permissions:
|
||||
contents: read
|
||||
with:
|
||||
official: false
|
||||
build-aux:
|
||||
name: Build ares (auxiliary)
|
||||
uses: ./.github/workflows/build-aux.yml
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Push
|
||||
on:
|
||||
push
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
name: Build ares (primary)
|
||||
uses: ./.github/workflows/build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
codesign: true
|
||||
official: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }}
|
||||
build-aux:
|
||||
name: Build ares (auxiliary)
|
||||
uses: ./.github/workflows/build-aux.yml
|
||||
secrets: inherit
|
||||
release:
|
||||
name: Release
|
||||
needs: build
|
||||
secrets: inherit
|
||||
uses: ./.github/workflows/release.yml
|
||||
with:
|
||||
notarize: true
|
||||
@@ -0,0 +1,82 @@
|
||||
name: Release
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
notarize:
|
||||
description: Notarize build (macOS only)
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
jobs:
|
||||
release:
|
||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
path: 'src'
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
path: 'bin'
|
||||
- name: "Decompress Build Artifacts"
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
for package in macos-universal windows-x64 windows-clang-cl-arm64; do
|
||||
pushd bin/ares-${package}
|
||||
tar -xJf ares-${package}.tar.xz
|
||||
rm -f ares-${package}.tar.xz
|
||||
popd
|
||||
done
|
||||
- name: "macOS: notarize"
|
||||
if: inputs.notarize
|
||||
run: |
|
||||
ditto -c -k --keepParent ${{ github.workspace }}/bin/ares-macos-universal/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 ${{ github.workspace }}/bin/ares-macos-universal/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: Package Artifacts
|
||||
run: src/.github/scripts/package_artifacts.sh
|
||||
- name: Check Release Tag ☑️
|
||||
id: check
|
||||
run: |
|
||||
now=$(date +'%Y-%m-%d')
|
||||
subject=$(git -C src log -1 --pretty=%s)
|
||||
if [[ ${GITHUB_REF_NAME} == master ]];
|
||||
then
|
||||
echo "tag=nightly" >> $GITHUB_OUTPUT
|
||||
versionName="nightly ${now}"
|
||||
echo "versionName=${versionName}" >> $GITHUB_OUTPUT
|
||||
echo "description=${subject}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "tag=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
|
||||
echo "versionName=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
|
||||
description="This is ares ${GITHUB_REF_NAME}, released on ${now}."
|
||||
echo "description=${description}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Update Git Tag
|
||||
if: steps.check.outputs.tag == 'nightly'
|
||||
id: update-tag
|
||||
run: |
|
||||
git -C src tag -f ${{ steps.check.outputs.tag }}
|
||||
git -C src push -f origin ${{ steps.check.outputs.tag }}
|
||||
|
||||
- name: Create Release 🛫
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
|
||||
with:
|
||||
prerelease: ${{ steps.check.outputs.tag == 'nightly' }}
|
||||
tag_name: ${{ steps.check.outputs.tag }}
|
||||
name: ares ${{ steps.check.outputs.versionName }}
|
||||
body: ${{ steps.check.outputs.description }}
|
||||
files: |
|
||||
${{ github.workspace }}/ares-source.tar.gz
|
||||
${{ github.workspace }}/ares-macos-universal.zip
|
||||
${{ github.workspace }}/ares-macos-universal-dSYMs.zip
|
||||
${{ github.workspace }}/ares-windows-x64.zip
|
||||
${{ github.workspace }}/ares-windows-x64-PDBs.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-arm64.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-arm64-PDBs.zip
|
||||
+50
-18
@@ -1,18 +1,50 @@
|
||||
*.moc
|
||||
*.user
|
||||
*.xcuserdata
|
||||
.vs/
|
||||
.vscode/
|
||||
.idea/
|
||||
cmake-*/
|
||||
obj/
|
||||
out/
|
||||
obj-amd64/
|
||||
obj-arm64/
|
||||
out-amd64/
|
||||
out-arm64/
|
||||
thirdparty/SDL/SDL
|
||||
thirdparty/SDL/libSDL2-2.0.0.dylib
|
||||
macos-xcode/
|
||||
.swiftpm
|
||||
*.xcodeproj
|
||||
# Exclude everything
|
||||
/*
|
||||
|
||||
# Except for default project files
|
||||
!/.github
|
||||
!/ares
|
||||
!/desktop-ui
|
||||
!/hiro
|
||||
!/cmake
|
||||
!/libco
|
||||
!/mia
|
||||
!/nall
|
||||
!/ruby
|
||||
!/scripts
|
||||
!/tests
|
||||
!/thirdparty
|
||||
!/tools
|
||||
!/GNUMakefile
|
||||
!/LICENSE
|
||||
!/README.md
|
||||
!.editorconfig
|
||||
!.gitignore
|
||||
!.gitattributes
|
||||
!.gersemirc
|
||||
!deps.json
|
||||
!CMakeLists.txt
|
||||
!CMakePresets.json
|
||||
|
||||
# Exclude old macOS Finder metadata
|
||||
.DS_Store
|
||||
|
||||
# Exclude generated sources that still reside in-tree
|
||||
ruby/video/metal/shaders.metallib
|
||||
ruby/video/metal/shaders.ir
|
||||
ares/ares/resource/resource.cpp
|
||||
ares/ares/resource/resource.hpp
|
||||
hiro/resource/resource.cpp
|
||||
hiro/resource/resource.hpp
|
||||
desktop-ui/resource/resource.cpp
|
||||
desktop-ui/resource/resource.hpp
|
||||
mia/resource/resource.cpp
|
||||
mia/resource/resource.hpp
|
||||
|
||||
# Exclude fetched third-party processor test binaries
|
||||
tests/arm7tdmi/tests
|
||||
tests/m68000/tests
|
||||
|
||||
# Exclude unused legacy zlib header that is renamed by CMake
|
||||
thirdparty/libchdr/deps/zlib-*/zconf.h
|
||||
thirdparty/libchdr/deps/zlib-*/zconf.h.included
|
||||
@@ -0,0 +1,56 @@
|
||||
cmake_minimum_required(VERSION 3.28...4.1)
|
||||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE)
|
||||
|
||||
project(ares VERSION ${ARES_VERSION_CANONICAL})
|
||||
|
||||
include(compilerconfig)
|
||||
include(defaults)
|
||||
include(helpers)
|
||||
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
add_subdirectory(nall/nall)
|
||||
add_subdirectory(libco)
|
||||
add_subdirectory(ruby)
|
||||
add_subdirectory(hiro)
|
||||
|
||||
# gersemi: off
|
||||
set(
|
||||
ARES_CORES
|
||||
a26 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
|
||||
CACHE STRING "List of systems to be built by the project"
|
||||
)
|
||||
# gersemi: on
|
||||
|
||||
add_subdirectory(ares)
|
||||
add_subdirectory(mia)
|
||||
add_subdirectory(desktop-ui)
|
||||
|
||||
option(ARES_BUILD_OPTIONAL_TARGETS "Include supplemental tools and tests" OFF)
|
||||
|
||||
if(ARES_BUILD_OPTIONAL_TARGETS)
|
||||
add_subdirectory(tests/arm7tdmi)
|
||||
add_subdirectory(tests/i8080)
|
||||
add_subdirectory(tests/m68000)
|
||||
if(HIRO_BACKEND STREQUAL "GTK3")
|
||||
add_subdirectory(tools/genius)
|
||||
else()
|
||||
target_disable_subproject(genius "genius (database editor)")
|
||||
endif()
|
||||
add_subdirectory(tools/mame2bml)
|
||||
else()
|
||||
target_disable_subproject(arm7tdmi "arm7tdmi processor test harness")
|
||||
target_disable_subproject(i8080 "i8080 processor test harness")
|
||||
target_disable_subproject(m68000 "m68000 processor test harness")
|
||||
target_disable_subproject(mame2bml "mame2bml (MAME manifest converter)")
|
||||
target_disable_subproject(genius "genius (database editor)")
|
||||
endif()
|
||||
|
||||
add_subdirectory(tools/sourcery)
|
||||
|
||||
message_configuration()
|
||||
|
||||
add_subdirectory(.github)
|
||||
add_subdirectory(cmake)
|
||||
return()
|
||||
@@ -0,0 +1,200 @@
|
||||
{
|
||||
"version": 3,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 28,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "baseCacheVars",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"ARES_PROFILE_ACCURACY": false,
|
||||
"ARES_BUILD_LOCAL": true,
|
||||
"ENABLE_CCACHE": true,
|
||||
"ARES_BUILD_OFFICIAL": {"type": "BOOL", "value": "$penv{ARES_BUILD_OFFICIAL}"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos",
|
||||
"displayName": "macOS",
|
||||
"description": "Xcode project (host architecture by default)",
|
||||
"inherits": ["baseCacheVars"],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
},
|
||||
"generator": "Xcode",
|
||||
"binaryDir": "${sourceDir}/build_macos",
|
||||
"cacheVariables": {
|
||||
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{CODESIGN_IDENT}"},
|
||||
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{CODESIGN_TEAM}"},
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true,
|
||||
"ENABLE_CCACHE": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows",
|
||||
"displayName": "Windows (Visual Studio, ClangCL)",
|
||||
"description": "Visual Studio project using ClangCL (host architecture)",
|
||||
"inherits": ["baseCacheVars"],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"binaryDir": "${sourceDir}/build_vsclang",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"toolset": "ClangCL",
|
||||
"cacheVariables": {
|
||||
"ENABLE_CCACHE": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc",
|
||||
"displayName": "Windows (Visual Studio, MSVC)",
|
||||
"description": "Visual Studio project using MSVC (host architecture)",
|
||||
"inherits": ["baseCacheVars"],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"binaryDir": "${sourceDir}/build_msvc",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"cacheVariables": {
|
||||
"ENABLE_CCACHE": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-ci-universal",
|
||||
"displayName": "macOS for CI",
|
||||
"description": "Universal binary for building on Github Actions",
|
||||
"inherits": ["baseCacheVars"],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
},
|
||||
"generator": "Xcode",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_OSX_ARCHITECTURES": {"type": "STRING", "value": "x86_64;arm64"},
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "11.0"},
|
||||
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{MACOS_CERTIFICATE_NAME}"},
|
||||
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{MACOS_NOTARIZATION_TEAMID}"},
|
||||
"ENABLE_CCACHE": true,
|
||||
"ARES_BUILD_LOCAL": false,
|
||||
"ARES_UNITY_CORES": true,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-ci-base",
|
||||
"hidden": true,
|
||||
"inherits": ["baseCacheVars"],
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": {"type": "STRING", "value": "RelWithDebInfo"},
|
||||
"ENABLE_CCACHE": true,
|
||||
"ARES_BUILD_LOCAL": false,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true,
|
||||
"ARES_UNITY_CORES": true,
|
||||
"ARES_PRECOMPILE_HEADERS": true,
|
||||
"CMAKE_MSVC_RUNTIME_LIBRARY": {"type": "STRING", "value": "MultiThreaded"},
|
||||
"CMAKE_IGNORE_PATH": {"type": "STRING", "value": "C:/Strawberry/c/bin/"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-ci-mingw-native",
|
||||
"displayName": "Windows for CI (x64 MSYS2/MinGW Clang)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"inherits": ["windows-ci-base"],
|
||||
"generator": "Ninja"
|
||||
},
|
||||
{
|
||||
"name": "windows-ci-cl-native",
|
||||
"displayName": "Windows for CI (x64 ClangCL)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"inherits": ["windows-ci-base"],
|
||||
"toolset": "ClangCL"
|
||||
},
|
||||
{
|
||||
"name": "windows-ci-cl-cross",
|
||||
"displayName": "Windows for CI (arm64 ClangCL)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"inherits": ["windows-ci-base"],
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"architecture": "arm64",
|
||||
"toolset": "ClangCL",
|
||||
"cacheVariables": {
|
||||
"ARES_CROSSCOMPILING": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-ci-msvc-native",
|
||||
"displayName": "Windows for CI (x64 MSVC)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"inherits": ["windows-ci-base"]
|
||||
},
|
||||
{
|
||||
"name": "windows-ci-msvc-cross",
|
||||
"displayName": "Windows for CI (arm64 MSVC)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"architecture": "arm64",
|
||||
"inherits": ["windows-ci-base"],
|
||||
"cacheVariables": {
|
||||
"ARES_CROSSCOMPILING": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ubuntu-ci",
|
||||
"displayName": "Ubuntu CI (x64 gcc)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": {"type": "STRING", "value": "RelWithDebInfo"},
|
||||
"ENABLE_CCACHE": true,
|
||||
"ENABLE_IPO": false,
|
||||
"ARES_BUILD_LOCAL": false,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true,
|
||||
"ARES_PRECOMPILE_HEADERS": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ubuntu-ci-clang",
|
||||
"displayName": "Ubuntu CI (clang)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"inherits": ["ubuntu-ci"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ubuntu-ci-qt",
|
||||
"displayName": "Ubuntu CI (arm64, gcc, Qt)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"inherits": ["ubuntu-ci"],
|
||||
"cacheVariables": {
|
||||
"USE_QT6": true,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "windows",
|
||||
"configurePreset": "windows",
|
||||
"displayName": "Windows build (host architecture)",
|
||||
"description": "Windows build (host architecture)",
|
||||
"configuration": "RelWithDebInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
targets = all clean install uninstall verbose
|
||||
|
||||
$(targets):
|
||||
@$(MAKE) -C desktop-ui $@
|
||||
|
||||
.PHONY: $(targets)
|
||||
@@ -1,7 +1,7 @@
|
||||
----------------------------------------------------------------------
|
||||
ares
|
||||
|
||||
Copyright (c) 2004-2021 ares team, Near et al
|
||||
Copyright (c) 2004-2025 ares team, Near et al
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -828,4 +828,32 @@ You may add additional accurate notices of copyright ownership.
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
qoi/qon
|
||||
|
||||
Copyright (c) 2025, Roger Sanders
|
||||
Revised QOI format, achieving higher compression with equivalent performance.
|
||||
|
||||
Based on the "Quite OK Image" format for fast, lossless image compression
|
||||
Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
|
||||
|
||||
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,10 +1,12 @@
|
||||

|
||||
<img src="https://github.com/ares-emulator/ares/blob/master/ares/ares/resource/logo@2x.png" width="350"/>
|
||||
|
||||
[](https://github.com/higan-emu/ares/blob/master/LICENSE)
|
||||
|
||||
**ares** is a multi-system emulator that began development on October 14th, 2004.
|
||||
It is a descendant of [higan](https://github.com/higan-emu/higan) and [bsnes](https://github.com/bsnes-emu/bsnes/), and focuses on accuracy and preservation.
|
||||
|
||||
It's worth noting that ares takes some uncommon design approaches that essentially trade speed for code clarity. We avoid state machines and bitmasks (when possible). Most cores end up being half the amount of code, but slower. The code is clearer and less spaghettified, especially for systems with lots of processors. C bitfields being non-portable incurs a speedhit. Windows also has a speedhit over Linux due to its ABI needing more instructions to switch contexts.
|
||||
|
||||
Official Releases
|
||||
-----------------
|
||||
|
||||
@@ -14,130 +16,18 @@ Official releases are available from
|
||||
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).
|
||||
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/ares-emulator/ares/releases/tag/nightly).
|
||||
Only the latest nightly build is kept.
|
||||
|
||||
Prerequisites
|
||||
Building ares
|
||||
-------------
|
||||
|
||||
### *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 (e.g. for using a controller), you will need to install the `libsdl2-dev` and `libsdl2-2.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 clang is detected on Windows/macOS/BSD, it will be selected by default. On Linux and other platforms, g++ remains the default if present. To build 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++]`
|
||||
|
||||
##### Librashader Support
|
||||
If you do not want to include librashader support, you can pass the following option to the `make` command to skip these requirements using: `librashader=false`
|
||||
|
||||
Librashader requires rust in order to build. You can install it with the following command:
|
||||
```
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source ~/.cargo/env
|
||||
rustup toolchain install nightly
|
||||
```
|
||||
|
||||
In order to build librashader, change into the `ares/thirdparty/librashader` directory and run the script `build-librashader.sh`
|
||||
Note that once the build completes, it will instruct you to run three copy commands to install the library on your system. These paths may be different depending on Linux distribution.
|
||||
|
||||
--------------
|
||||
|
||||
### 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 mingw-w64-x86_64-SDL2
|
||||
```
|
||||
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 mingw-w64-clang-x86_64-SDL2
|
||||
```
|
||||
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`
|
||||
|
||||
###### Librashader Support
|
||||
ares has introduced support for the [librashader](https://github.com/SnowflakePowered/librashader) library, which is a preprocessor, compiler, and runtime for RetroArch 'slang' shaders. If you are not interested in working with librashaders, you can pass the following option to the `make` command to skip these requirements using: `librashader=false`
|
||||
|
||||
Building the librashader library on Windows requires Rust. Follow these steps to prepare your system and build the librashader library:
|
||||
|
||||
1. Download and execute the rustup-init.exe installer from: https://rustup.rs/
|
||||
2. Open a new Windows terminal and run the following commands:
|
||||
```
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
```
|
||||
3. With Rust successfully installed, you will need to update your PATH environment variable within your MSYS2 environment. In an MSYS2 shell, open $HOME/.bash_profile and append something like the following (note you will need to replace both instances of %USER_NAME% with the real user name you used to install Rust):
|
||||
```
|
||||
if [ -d "/C/Users/%USER_NAME%/.cargo/bin" ] ; then
|
||||
PATH="/C/Users/%USER_NAME%/.cargo/bin:${PATH}"
|
||||
fi
|
||||
```
|
||||
4. Open a new MSYS2 based shell for the compiler you are using (MinGW64|CLANG64|UCRT64), execute `rustup` to validate the path is set properly within your MSYS2 environment.
|
||||
5. In your MSYS2 compiler shell, `cd` into the `ares/thirdparty/librashader` directory
|
||||
6. Execute the build script, build should complete successfully:
|
||||
```
|
||||
./build-librashader.sh
|
||||
```
|
||||
|
||||
This only needs to be done once, or anytime the librashader library is updated. Once built, ares will build with librashader support by default requiring no additional flags.
|
||||
|
||||
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 myvision 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 `thirdparty/slang-shaders/*` into a `Shader` directory, and by copying `mia/Database/*`
|
||||
ares supports building on Windows, macOS, and various Linux/BSD distributions. See build instructions for:
|
||||
|
||||
* [Windows](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-Windows)
|
||||
* [macOS](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-macOS)
|
||||
* [Linux](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-Linux)
|
||||
* [BSD](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-BSD)
|
||||
|
||||
Command-line options
|
||||
--------------------
|
||||
@@ -150,7 +40,7 @@ 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)
|
||||
--shader shader Specify a slang shader to load (requires OpenGL or Metal)
|
||||
--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)
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
add_library(ares STATIC ares/ares.cpp ares/memory/fixed-allocator.cpp)
|
||||
|
||||
configure_file(ares/ares.cpp.in ares/ares.cpp @ONLY)
|
||||
|
||||
add_library(ares::ares ALIAS ares)
|
||||
|
||||
option(ARES_PROFILE_ACCURACY "Build to prefer emulation accuracy over performance in certain specific areas" OFF)
|
||||
option(ARES_PRECOMPILE_HEADERS "Precompile ares/ares.hpp header for performance" OFF)
|
||||
option(
|
||||
ARES_UNITY_CORES
|
||||
"\
|
||||
Build each core as one translation unit. Decreases cold build times but increases incremental build times. Slightly \
|
||||
increases performance.
|
||||
"
|
||||
OFF
|
||||
)
|
||||
|
||||
add_sourcery_command(ares ares/resource)
|
||||
|
||||
if(ARES_PRECOMPILE_HEADERS)
|
||||
target_precompile_headers(ares PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:ares/ares.hpp>")
|
||||
endif()
|
||||
|
||||
target_link_libraries(ares PRIVATE libco ares::nall::headers $<$<BOOL:${ARES_ENABLE_CHD}>:chdr-static> PUBLIC sljit)
|
||||
|
||||
if(ARES_PROFILE_ACCURACY)
|
||||
target_compile_definitions(ares PUBLIC PROFILE_ACCURACY)
|
||||
else()
|
||||
target_compile_definitions(ares PUBLIC PROFILE_PERFORMANCE)
|
||||
endif()
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE ares/ares.cpp ares/ares.cpp.in ares/ares.hpp ares/inline.hpp ares/platform.hpp ares/random.hpp ares/types.hpp
|
||||
)
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE
|
||||
ares/debug/debug.cpp
|
||||
ares/debug/debug.hpp
|
||||
ares/memory/fixed-allocator.cpp
|
||||
ares/memory/fixed-allocator.hpp
|
||||
ares/memory/memory.hpp
|
||||
ares/memory/readable.hpp
|
||||
ares/memory/writable.hpp
|
||||
)
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE ares/scheduler/scheduler.cpp ares/scheduler/scheduler.hpp ares/scheduler/thread.cpp ares/scheduler/thread.hpp
|
||||
)
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE
|
||||
ares/node/attribute.hpp
|
||||
ares/node/class.hpp
|
||||
ares/node/node.cpp
|
||||
ares/node/node.hpp
|
||||
ares/node/object.hpp
|
||||
ares/node/peripheral.hpp
|
||||
ares/node/port.hpp
|
||||
ares/node/system.hpp
|
||||
)
|
||||
|
||||
target_sources(ares PRIVATE ares/node/audio/audio.hpp ares/node/audio/stream.cpp ares/node/audio/stream.hpp)
|
||||
|
||||
target_sources(ares PRIVATE ares/node/component/component.hpp ares/node/component/real-time-clock.hpp)
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE
|
||||
ares/node/input/axis.hpp
|
||||
ares/node/input/button.hpp
|
||||
ares/node/input/input.hpp
|
||||
ares/node/input/rumble.hpp
|
||||
ares/node/input/trigger.hpp
|
||||
)
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE
|
||||
ares/node/setting/boolean.hpp
|
||||
ares/node/setting/integer.hpp
|
||||
ares/node/setting/natural.hpp
|
||||
ares/node/setting/real.hpp
|
||||
ares/node/setting/setting.hpp
|
||||
ares/node/setting/string.hpp
|
||||
)
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE
|
||||
ares/node/video/screen.cpp
|
||||
ares/node/video/screen.hpp
|
||||
ares/node/video/sprite.cpp
|
||||
ares/node/video/sprite.hpp
|
||||
ares/node/video/video.hpp
|
||||
)
|
||||
|
||||
if(OS_WINDOWS)
|
||||
include(cmake/os-windows.cmake)
|
||||
elseif(OS_MACOS)
|
||||
include(cmake/os-macos.cmake)
|
||||
elseif(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD)
|
||||
include(cmake/os-linux.cmake)
|
||||
endif()
|
||||
|
||||
macro(ares_components)
|
||||
list(APPEND ares.components ${ARGV})
|
||||
set(ares.components ${ares.components} PARENT_SCOPE)
|
||||
endmacro()
|
||||
|
||||
macro(ares_add_sources)
|
||||
set(options "")
|
||||
set(oneValueArgs CORE)
|
||||
set(multiValueArgs PRIMARY INCLUDED UNITY)
|
||||
cmake_parse_arguments(AAS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
target_sources(ares PRIVATE ${AAS_INCLUDED} ${AAS_PRIMARY})
|
||||
|
||||
if(ARES_UNITY_CORES)
|
||||
list(APPEND AAS_INCLUDED ${AAS_PRIMARY})
|
||||
target_sources(ares PRIVATE ${AAS_UNITY})
|
||||
endif()
|
||||
|
||||
foreach(arg IN ITEMS ${AAS_INCLUDED})
|
||||
list(APPEND ARES_HEADER_SOURCES "${AAS_CORE}/${arg}")
|
||||
endforeach()
|
||||
set(ARES_HEADER_SOURCES ${ARES_HEADER_SOURCES} PARENT_SCOPE)
|
||||
endmacro()
|
||||
|
||||
list(TRANSFORM ARES_CORES STRIP)
|
||||
|
||||
if(a26 IN_LIST ARES_CORES)
|
||||
enable_core("Atari 2600")
|
||||
add_subdirectory(a26)
|
||||
else()
|
||||
disable_core("Atari 2600")
|
||||
endif()
|
||||
|
||||
if(fc IN_LIST ARES_CORES)
|
||||
enable_core("NES / Famicom")
|
||||
add_subdirectory(fc)
|
||||
else()
|
||||
disable_core("NES / Famicom")
|
||||
endif()
|
||||
|
||||
if(sfc IN_LIST ARES_CORES)
|
||||
enable_core("SNES / Super Famicom")
|
||||
add_subdirectory(sfc)
|
||||
else()
|
||||
disable_core("SNES / Super Famicom")
|
||||
endif()
|
||||
|
||||
if(n64 IN_LIST ARES_CORES)
|
||||
enable_core("Nintendo 64")
|
||||
add_subdirectory(n64)
|
||||
else()
|
||||
disable_core("Nintendo 64")
|
||||
endif()
|
||||
|
||||
if(sg IN_LIST ARES_CORES)
|
||||
enable_core("Sega SG-1000")
|
||||
add_subdirectory(sg)
|
||||
else()
|
||||
disable_core("Sega SG-1000")
|
||||
endif()
|
||||
|
||||
if(ms IN_LIST ARES_CORES)
|
||||
enable_core("Sega Master System / Mark III")
|
||||
add_subdirectory(ms)
|
||||
else()
|
||||
disable_core("Sega Master System / Mark III")
|
||||
endif()
|
||||
|
||||
if(md IN_LIST ARES_CORES)
|
||||
enable_core("Sega Mega Drive / Genesis")
|
||||
add_subdirectory(md)
|
||||
else()
|
||||
disable_core("Sega Mega Drive / Genesis")
|
||||
endif()
|
||||
|
||||
if(saturn IN_LIST ARES_CORES)
|
||||
enable_core("Sega Saturn")
|
||||
add_subdirectory(saturn)
|
||||
else()
|
||||
disable_core("Sega Saturn")
|
||||
endif()
|
||||
|
||||
if(ps1 IN_LIST ARES_CORES)
|
||||
enable_core("PlayStation")
|
||||
add_subdirectory(ps1)
|
||||
else()
|
||||
disable_core("Playstation")
|
||||
endif()
|
||||
|
||||
if(pce IN_LIST ARES_CORES)
|
||||
enable_core("PC-Engine / TurboGrafx")
|
||||
add_subdirectory(pce)
|
||||
else()
|
||||
disable_core("PC-Engine / TurboGrafx")
|
||||
endif()
|
||||
|
||||
if(msx IN_LIST ARES_CORES)
|
||||
enable_core("Microsoft MSX")
|
||||
add_subdirectory(msx)
|
||||
else()
|
||||
disable_core("Microsoft MSX")
|
||||
endif()
|
||||
|
||||
if(cv IN_LIST ARES_CORES)
|
||||
enable_core("ColecoVision")
|
||||
add_subdirectory(cv)
|
||||
else()
|
||||
disable_core("ColecoVision")
|
||||
endif()
|
||||
|
||||
if(myvision IN_LIST ARES_CORES)
|
||||
enable_core("My Vision")
|
||||
add_subdirectory(myvision)
|
||||
else()
|
||||
disable_core("My Vision")
|
||||
endif()
|
||||
|
||||
if(gb IN_LIST ARES_CORES)
|
||||
enable_core("Game Boy / Game Boy Color")
|
||||
add_subdirectory(gb)
|
||||
else()
|
||||
disable_core("Game Boy / Game Boy Color")
|
||||
endif()
|
||||
|
||||
if(gba IN_LIST ARES_CORES)
|
||||
enable_core("Game Boy Advance")
|
||||
add_subdirectory(gba)
|
||||
else()
|
||||
disable_core("Game Boy Advance")
|
||||
endif()
|
||||
|
||||
if(ws IN_LIST ARES_CORES)
|
||||
enable_core("WonderSwan / WonderSwan Color")
|
||||
add_subdirectory(ws)
|
||||
else()
|
||||
disable_core("WonderSwan / WonderSwan Color")
|
||||
endif()
|
||||
|
||||
if(ng IN_LIST ARES_CORES)
|
||||
enable_core("Neo Geo (AES/MVS)")
|
||||
add_subdirectory(ng)
|
||||
else()
|
||||
disable_core("Neo Geo (AES/MVS)")
|
||||
endif()
|
||||
|
||||
if(ngp IN_LIST ARES_CORES)
|
||||
enable_core("Neo Geo Pocket / Neo Geo Pocket Color")
|
||||
add_subdirectory(ngp)
|
||||
else()
|
||||
disable_core("Neo Geo Pocket / Neo Geo Pocket Color")
|
||||
endif()
|
||||
|
||||
if(spec IN_LIST ARES_CORES)
|
||||
enable_core("ZX Spectrum")
|
||||
add_subdirectory(spec)
|
||||
else()
|
||||
disable_core("ZX Spectrum")
|
||||
endif()
|
||||
|
||||
add_subdirectory(component)
|
||||
|
||||
foreach(c IN LISTS ARES_CORES)
|
||||
# target_enable_feature(ares "${c} core" CORE_$<UPPER_CASE:${c}>)
|
||||
target_compile_definitions(ares PUBLIC CORE_$<UPPER_CASE:${c}>)
|
||||
endforeach()
|
||||
|
||||
get_target_property(ares_SOURCES ares SOURCES)
|
||||
|
||||
set_source_files_properties(
|
||||
ares
|
||||
ares/debug/debug.cpp
|
||||
ares/node/audio/stream.cpp
|
||||
ares/node/node.cpp
|
||||
ares/node/video/screen.cpp
|
||||
ares/node/video/sprite.cpp
|
||||
ares/scheduler/thread.cpp
|
||||
ares/scheduler/scheduler.cpp
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
n64/vulkan/parallel-rdp/vulkan/shader.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/descriptor_set.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/device.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/command_buffer.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/render_pass.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/context.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/memory_allocator.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/semaphore.cpp
|
||||
n64/vulkan/parallel-rdp/util/logging.cpp
|
||||
n64/vulkan/parallel-rdp/util/environment.cpp
|
||||
n64/vulkan/parallel-rdp/util/thread_name.cpp
|
||||
n64/vulkan/parallel-rdp/util/timer.cpp
|
||||
PROPERTIES SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
|
||||
target_sources(ares PRIVATE cmake/os-macos.cmake cmake/os-windows.cmake cmake/os-linux.cmake)
|
||||
|
||||
set_source_files_properties(ares ${ARES_HEADER_SOURCES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
set_source_files_properties(ares ares/ares.cpp ares/memory/fixed-allocator.cpp PROPERTIES HEADER_FILE_ONLY FALSE)
|
||||
|
||||
target_include_directories(ares INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${ares_SOURCES})
|
||||
@@ -1,108 +0,0 @@
|
||||
ifeq ($(platform),windows)
|
||||
options += $(call lib,uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32)
|
||||
else ifeq ($(platform),macos)
|
||||
else ifneq ($(filter $(platform),linux bsd),)
|
||||
options += -Wl,-export-dynamic
|
||||
options += -lX11 -lXext
|
||||
else
|
||||
$(error "ares is a library and cannot be built directly.")
|
||||
endif
|
||||
|
||||
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 ($(vulkan),true)
|
||||
flags += -DVULKAN
|
||||
endif
|
||||
|
||||
ifeq ($(profile),accuracy)
|
||||
flags += -DPROFILE_ACCURACY
|
||||
endif
|
||||
|
||||
ifeq ($(profile),performance)
|
||||
flags += -DPROFILE_PERFORMANCE
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),a26),)
|
||||
include $(ares.path)/a26/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),fc),)
|
||||
include $(ares.path)/fc/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),sfc),)
|
||||
include $(ares.path)/sfc/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),n64),)
|
||||
include $(ares.path)/n64/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),sg),)
|
||||
include $(ares.path)/sg/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ms),)
|
||||
include $(ares.path)/ms/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),md),)
|
||||
include $(ares.path)/md/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),saturn),)
|
||||
include $(ares.path)/saturn/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ps1),)
|
||||
include $(ares.path)/ps1/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),pce),)
|
||||
include $(ares.path)/pce/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),msx),)
|
||||
include $(ares.path)/msx/GNUmakefile
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
ifneq ($(filter $(cores),gba),)
|
||||
include $(ares.path)/gba/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ws),)
|
||||
include $(ares.path)/ws/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ng),)
|
||||
include $(ares.path)/ng/GNUmakefile
|
||||
endif
|
||||
|
||||
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)
|
||||
|
||||
ares.objects := $(ares.objects:%=$(object.path)/%.o)
|
||||
@@ -0,0 +1,98 @@
|
||||
ares_components(mos6502)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
UNITY #
|
||||
a26.cpp
|
||||
PRIMARY #
|
||||
system/system.cpp
|
||||
controller/controller.cpp
|
||||
cartridge/cartridge.cpp
|
||||
cpu/cpu.cpp
|
||||
tia/tia.cpp
|
||||
riot/riot.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
a26.hpp
|
||||
CMakeLists.txt
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
cartridge/cartridge.hpp
|
||||
cartridge/serialization.cpp
|
||||
cartridge/slot.cpp
|
||||
cartridge/slot.hpp
|
||||
cartridge/board/atari16k.cpp
|
||||
cartridge/board/atari32k.cpp
|
||||
cartridge/board/atari8k.cpp
|
||||
cartridge/board/board.cpp
|
||||
cartridge/board/board.hpp
|
||||
cartridge/board/commavid.cpp
|
||||
cartridge/board/linear.cpp
|
||||
cartridge/board/parker-bros.cpp
|
||||
cartridge/board/tigervision.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
controller/controller.hpp
|
||||
controller/port.cpp
|
||||
controller/port.hpp
|
||||
controller/gamepad/gamepad.cpp
|
||||
controller/gamepad/gamepad.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
cpu/cpu.hpp
|
||||
cpu/debugger.cpp
|
||||
cpu/memory.cpp
|
||||
cpu/serialization.cpp
|
||||
cpu/timing.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
riot/io.cpp
|
||||
riot/riot.hpp
|
||||
riot/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
system/controls.cpp
|
||||
system/serialization.cpp
|
||||
system/system.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
a26
|
||||
INCLUDED #
|
||||
tia/audio.cpp
|
||||
tia/ball.cpp
|
||||
tia/color.cpp
|
||||
tia/io.cpp
|
||||
tia/missile.cpp
|
||||
tia/player.cpp
|
||||
tia/playfield.cpp
|
||||
tia/serialization.cpp
|
||||
tia/tia.hpp
|
||||
tia/write-queue.cpp
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
ares.components += mos6502
|
||||
|
||||
ares.objects += ares-a26-system
|
||||
ares.objects += ares-a26-controller
|
||||
ares.objects += ares-a26-cartridge
|
||||
ares.objects += ares-a26-cpu
|
||||
ares.objects += ares-a26-tia
|
||||
ares.objects += ares-a26-riot
|
||||
|
||||
$(object.path)/ares-a26-system.o: $(ares.path)/a26/system/system.cpp
|
||||
$(object.path)/ares-a26-controller.o: $(ares.path)/a26/controller/controller.cpp
|
||||
$(object.path)/ares-a26-cartridge.o: $(ares.path)/a26/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-a26-cpu.o: $(ares.path)/a26/cpu/cpu.cpp
|
||||
$(object.path)/ares-a26-tia.o: $(ares.path)/a26/tia/tia.cpp
|
||||
$(object.path)/ares-a26-riot.o: $(ares.path)/a26/riot/riot.cpp
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
#include <a26/cartridge/cartridge.cpp>
|
||||
#include <a26/controller/controller.cpp>
|
||||
#include <a26/cpu/cpu.cpp>
|
||||
#include <a26/riot/riot.cpp>
|
||||
#include <a26/system/system.cpp>
|
||||
#include <a26/tia/tia.cpp>
|
||||
+2
-1
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ares/ares.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include <component/processor/mos6502/mos6502.hpp>
|
||||
|
||||
namespace ares::Atari2600 {
|
||||
#include <ares/inline.hpp>
|
||||
auto enumerate() -> vector<string>;
|
||||
auto enumerate() -> std::vector<string>;
|
||||
auto load(Node::System& node, string name) -> bool;
|
||||
|
||||
struct Region {
|
||||
|
||||
@@ -19,15 +19,15 @@ auto Cartridge::connect() -> void {
|
||||
information.region = pak->attribute("region");
|
||||
information.board = pak->attribute("board");
|
||||
|
||||
if(information.board == "Linear") board = new Board::Linear{*this};
|
||||
if(information.board == "Atari8k") board = new Board::Atari8k{*this};
|
||||
if(information.board == "Atari16k") board = new Board::Atari16k{*this};
|
||||
if(information.board == "Atari32k") board = new Board::Atari32k{*this};
|
||||
if(information.board == "Commavid") board = new Board::Commavid{*this};
|
||||
if(information.board == "ParkerBros8k") board = new Board::ParkerBros{*this};
|
||||
if(information.board == "Tigervision") board = new Board::Tigervision{*this};
|
||||
if(information.board == "Linear") board = std::make_unique<Board::Linear>(*this);
|
||||
if(information.board == "Atari8k") board = std::make_unique<Board::Atari8k>(*this);
|
||||
if(information.board == "Atari16k") board = std::make_unique<Board::Atari16k>(*this);
|
||||
if(information.board == "Atari32k") board = std::make_unique<Board::Atari32k>(*this);
|
||||
if(information.board == "Commavid") board = std::make_unique<Board::Commavid>(*this);
|
||||
if(information.board == "ParkerBros8k") board = std::make_unique<Board::ParkerBros>(*this);
|
||||
if(information.board == "Tigervision") board = std::make_unique<Board::Tigervision>(*this);
|
||||
|
||||
if(!board) board = new Board::Interface{*this};
|
||||
if(!board) board = std::make_unique<Board::Interface>(*this);
|
||||
board->pak = pak;
|
||||
board->load();
|
||||
power();
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Cartridge {
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
unique_pointer<Board::Interface> board;
|
||||
std::unique_ptr<Board::Interface> board;
|
||||
|
||||
//private:
|
||||
struct Information {
|
||||
|
||||
@@ -20,7 +20,7 @@ auto ControllerPort::unload() -> void {
|
||||
}
|
||||
|
||||
auto ControllerPort::allocate(string name) -> Node::Peripheral {
|
||||
if(name == "Gamepad") device = new Gamepad(port);
|
||||
if(name == "Gamepad") device = std::make_unique<Gamepad>(port);
|
||||
if(device) return device->node;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
struct ControllerPort {
|
||||
Node::Port port;
|
||||
unique_pointer<Controller> device;
|
||||
std::unique_ptr<Controller> device;
|
||||
|
||||
//port.cpp
|
||||
ControllerPort(string name);
|
||||
|
||||
@@ -32,7 +32,7 @@ auto CPU::step(u32 clocks) -> void {
|
||||
auto CPU::power(bool reset) -> void {
|
||||
MOS6502::BCD = 1;
|
||||
MOS6502::power();
|
||||
Thread::create(system.frequency() / 3, {&CPU::main, this});
|
||||
Thread::create(system.frequency() / 3, std::bind_front(&CPU::main, this));
|
||||
|
||||
io = {};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ auto RIOT::step(u32 clocks) -> void {
|
||||
}
|
||||
|
||||
auto RIOT::power(bool reset) -> void {
|
||||
Thread::create(system.frequency() / 3, {&RIOT::main, this});
|
||||
Thread::create(system.frequency() / 3, std::bind_front(&RIOT::main, this));
|
||||
timer = {};
|
||||
port[0] = {};
|
||||
port[0].data = 0xff;
|
||||
|
||||
+13
-10
@@ -1,8 +1,9 @@
|
||||
#include <a26/a26.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ares::Atari2600 {
|
||||
|
||||
auto enumerate() -> vector<string> {
|
||||
auto enumerate() -> std::vector<string> {
|
||||
return {
|
||||
"[Atari] Atari 2600 (NTSC)",
|
||||
"[Atari] Atari 2600 (PAL)",
|
||||
@@ -11,7 +12,8 @@ auto enumerate() -> vector<string> {
|
||||
}
|
||||
|
||||
auto load(Node::System& node, string name) -> bool {
|
||||
if(!enumerate().find(name)) return false;
|
||||
auto list = enumerate();
|
||||
if(std::find(list.begin(), list.end(), name) == list.end()) return false;
|
||||
return system.load(node, name);
|
||||
}
|
||||
|
||||
@@ -53,14 +55,15 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
information.frequency = 3546894;
|
||||
}
|
||||
|
||||
node = Node::System::create(information.name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
node->setSave({&System::save, this});
|
||||
node->setUnload({&System::unload, this});
|
||||
node->setSerialize({&System::serialize, this});
|
||||
node->setUnserialize({&System::unserialize, this});
|
||||
node = std::make_shared<Core::System>(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame(std::bind_front(&System::game, this));
|
||||
node->setRun(std::bind_front(&System::run, this));
|
||||
node->setPower(std::bind_front(&System::power, this));
|
||||
node->setSave(std::bind_front(&System::save, this));
|
||||
node->setUnload(std::bind_front(&System::unload, this));
|
||||
node->setSerialize([this](bool s){ return this->serialize(s); });
|
||||
node->setUnserialize([this](serializer& s){ return this->unserialize(s); });
|
||||
root = node;
|
||||
|
||||
scheduler.reset();
|
||||
|
||||
@@ -18,7 +18,7 @@ auto TIA::load(Node::Object parent) -> void {
|
||||
node = parent->append<Node::Object>("TIA");
|
||||
|
||||
screen = node->append<Node::Video::Screen>("Screen", 180, displayHeight());
|
||||
screen->colors(1 << 7, {&TIA::color, this});
|
||||
screen->colors(1 << 7, std::bind_front(&TIA::color, this));
|
||||
screen->setSize(180, displayHeight());
|
||||
screen->setScale(2.0, 1.0);
|
||||
Region::PAL() ? screen->setAspect(38.0, 45.0) : screen->setAspect(4.0, 5.0);
|
||||
@@ -123,7 +123,7 @@ auto TIA::step(u32 clocks) -> void {
|
||||
}
|
||||
|
||||
auto TIA::power(bool reset) -> void {
|
||||
Thread::create(system.frequency(), {&TIA::main, this});
|
||||
Thread::create(system.frequency(), std::bind_front(&TIA::main, this));
|
||||
screen->power();
|
||||
io = {};
|
||||
playfield = {};
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <ares/ares.hpp>
|
||||
#include <ares/debug/debug.cpp>
|
||||
#include <nall/gdb/server.cpp>
|
||||
#include <ares/node/node.cpp>
|
||||
#include <ares/resource/resource.cpp>
|
||||
|
||||
namespace ares {
|
||||
|
||||
Platform* platform = nullptr;
|
||||
bool _runAhead = false;
|
||||
|
||||
const string Name = "ares";
|
||||
const string Version = "141";
|
||||
const string Copyright = "ares team, Near";
|
||||
const string License = "ISC";
|
||||
const string LicenseURI = "https://opensource.org/licenses/ISC";
|
||||
const string Website = "ares-emu.net";
|
||||
const string WebsiteURI = "https://ares-emu.net/";
|
||||
const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <ares/ares.hpp>
|
||||
#include <ares/debug/debug.cpp>
|
||||
#include <nall/gdb/server.cpp>
|
||||
#include <ares/node/node.cpp>
|
||||
#include <ares/resource/resource.cpp>
|
||||
|
||||
namespace ares {
|
||||
|
||||
Platform* platform = nullptr;
|
||||
atomic<bool> _runAhead = false;
|
||||
|
||||
const string Name = "@ARES_NAME@";
|
||||
const string Version = "@ARES_VERSION@";
|
||||
const string Copyright = "@ARES_LEGAL_COPYRIGHT_SHORT@";
|
||||
const string License = "ISC";
|
||||
const string LicenseURI = "https://opensource.org/licenses/ISC";
|
||||
const string Website = "@ARES_WEBSITE@";
|
||||
const string WebsiteURI = "https://@ARES_WEBSITE@/";
|
||||
const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
|
||||
|
||||
}
|
||||
+22
-7
@@ -3,6 +3,10 @@
|
||||
#include <libco/libco.h>
|
||||
#include <sljit.h>
|
||||
|
||||
#include <vector>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/adaptive-array.hpp>
|
||||
#include <nall/any.hpp>
|
||||
@@ -15,20 +19,20 @@
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/hashset.hpp>
|
||||
#include <nall/image.hpp>
|
||||
#include <nall/instruction-set.hpp>
|
||||
#include <nall/literals.hpp>
|
||||
#include <nall/priority-queue.hpp>
|
||||
#include <nall/queue.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/set.hpp>
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/span-helpers.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/terminal.hpp>
|
||||
#include <nall/thread.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
#include <nall/unique-pointer.hpp>
|
||||
#include <memory>
|
||||
#include <nall/variant.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/vfs.hpp>
|
||||
#include <nall/cd.hpp>
|
||||
#include <nall/dsp/iir/one-pole.hpp>
|
||||
@@ -50,8 +54,8 @@ namespace ares {
|
||||
extern const u32 SerializerSignature;
|
||||
|
||||
namespace VFS {
|
||||
using Pak = shared_pointer<vfs::directory>;
|
||||
using File = shared_pointer<vfs::file>;
|
||||
using Pak = std::shared_ptr<vfs::directory>;
|
||||
using File = std::shared_ptr<vfs::file>;
|
||||
}
|
||||
|
||||
namespace Video {
|
||||
@@ -65,11 +69,23 @@ namespace ares {
|
||||
}
|
||||
}
|
||||
|
||||
extern bool _runAhead;
|
||||
extern atomic<bool> _runAhead;
|
||||
inline auto runAhead() -> bool { return _runAhead; }
|
||||
inline auto setRunAhead(bool runAhead) -> void { _runAhead = runAhead; }
|
||||
}
|
||||
|
||||
/// ares elects to use the reserved C++ `register` identifier liberally in a few different areas so that it can more
|
||||
/// freely describe hardware registers within emulated system components. This macro exists to prevent compilers
|
||||
/// exploding at the sight of the reserved identifier.
|
||||
///
|
||||
/// Perhaps unsurprisingly, this macro will conflict with certain system headers. MSVC headers will emit an error
|
||||
/// forbidding macroizing `register` if the identifier is defined, while the `clangarm64` system headers in MSYS2
|
||||
/// appear to try to make use of the obsolete keyword meaning of the identifier.
|
||||
///
|
||||
/// Defining this macro after all platform headers are included avoids these conflicts... for now. Removing this
|
||||
/// macro along with all uses of this identifier may inevitably become necessary in the future.
|
||||
#define register $register
|
||||
|
||||
#include <ares/types.hpp>
|
||||
#include <ares/random.hpp>
|
||||
#include <ares/debug/debug.hpp>
|
||||
@@ -78,4 +94,3 @@ namespace ares {
|
||||
#include <ares/memory/fixed-allocator.hpp>
|
||||
#include <ares/memory/readable.hpp>
|
||||
#include <ares/memory/writable.hpp>
|
||||
#include <ares/resource/resource.hpp>
|
||||
+12
-12
@@ -4,40 +4,40 @@ Debug _debug;
|
||||
|
||||
auto Debug::reset() -> void {
|
||||
_totalNotices = 0;
|
||||
_unhandledNotices.reset();
|
||||
_unimplementedNotices.reset();
|
||||
_unusualNotices.reset();
|
||||
_unverifiedNotices.reset();
|
||||
_unhandledNotices.clear();
|
||||
_unimplementedNotices.clear();
|
||||
_unusualNotices.clear();
|
||||
_unverifiedNotices.clear();
|
||||
}
|
||||
|
||||
auto Debug::_unhandled(const string& text) -> void {
|
||||
if(_unhandledNotices.find(text)) return;
|
||||
if(std::ranges::find(_unhandledNotices, text) != _unhandledNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unhandledNotices.append(text);
|
||||
_unhandledNotices.push_back(text);
|
||||
|
||||
print(terminal::color::yellow("[unhandled] "), text, "\n");
|
||||
}
|
||||
|
||||
auto Debug::_unimplemented(const string& text) -> void {
|
||||
if(_unimplementedNotices.find(text)) return;
|
||||
if(std::ranges::find(_unimplementedNotices, text) != _unimplementedNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unimplementedNotices.append(text);
|
||||
_unimplementedNotices.push_back(text);
|
||||
|
||||
print(terminal::color::magenta("[unimplemented] "), text, "\n");
|
||||
}
|
||||
|
||||
auto Debug::_unusual(const string& text) -> void {
|
||||
if(_unusualNotices.find(text)) return;
|
||||
if(std::ranges::find(_unusualNotices, text) != _unusualNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unusualNotices.append(text);
|
||||
_unusualNotices.push_back(text);
|
||||
|
||||
print(terminal::color::cyan("[unusual] "), text, "\n");
|
||||
}
|
||||
|
||||
auto Debug::_unverified(const string& text) -> void {
|
||||
if(_unverifiedNotices.find(text)) return;
|
||||
if(std::ranges::find(_unverifiedNotices, text) != _unverifiedNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unverifiedNotices.append(text);
|
||||
_unverifiedNotices.push_back(text);
|
||||
|
||||
print(terminal::color::gray("[unverified] "), text, "\n");
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ private:
|
||||
auto _unverified(const string&) -> void;
|
||||
|
||||
u64 _totalNotices = 0;
|
||||
vector<string> _unhandledNotices;
|
||||
vector<string> _unimplementedNotices;
|
||||
vector<string> _unusualNotices;
|
||||
vector<string> _unverifiedNotices;
|
||||
std::vector<string> _unhandledNotices;
|
||||
std::vector<string> _unimplementedNotices;
|
||||
std::vector<string> _unusualNotices;
|
||||
std::vector<string> _unverifiedNotices;
|
||||
};
|
||||
|
||||
extern Debug _debug;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
constexpr u32 fixedBufferSize = 128_MiB;
|
||||
constexpr u32 fixedBufferSize = 64_MiB;
|
||||
|
||||
#if defined(STATIC_ALLOCATION)
|
||||
u8 fixedBuffer[fixedBufferSize + 64_KiB];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ares/memory/memory.hpp>
|
||||
#include <span>
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
@@ -32,7 +33,7 @@ struct Readable {
|
||||
|
||||
auto load(VFS::File fp) -> void {
|
||||
if(!self.size) allocate(fp->size());
|
||||
fp->read({self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
fp->read({(u8*)self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
for(u32 address = self.size; address <= self.mask; address++) {
|
||||
self.data[address] = self.data[mirror(address, self.size)];
|
||||
}
|
||||
@@ -59,7 +60,7 @@ struct Readable {
|
||||
auto end() const -> const T* { return &self.data[self.size]; }
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s(array_span<T>{self.data, self.size});
|
||||
s(std::span<T>{self.data, self.size});
|
||||
}
|
||||
|
||||
//private:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ares/memory/memory.hpp>
|
||||
#include <span>
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
@@ -32,14 +33,14 @@ struct Writable {
|
||||
|
||||
auto load(VFS::File fp) -> void {
|
||||
if(!self.size) allocate(fp->size());
|
||||
fp->read({self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
fp->read({(u8*)self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
for(u32 address = self.size; address <= self.mask; address++) {
|
||||
self.data[address] = self.data[mirror(address, self.size)];
|
||||
}
|
||||
}
|
||||
|
||||
auto save(VFS::File fp) -> void {
|
||||
fp->write({self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
fp->write({(const u8*)self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
}
|
||||
|
||||
explicit operator bool() const { return (bool)self.data; }
|
||||
@@ -61,7 +62,7 @@ struct Writable {
|
||||
auto end() const -> const T* { return &self.data[self.size]; }
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s(array_span<T>{self.data, self.size});
|
||||
s(std::span<T>{self.data, self.size});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
auto Stream::setChannels(u32 channels) -> void {
|
||||
_channels.reset();
|
||||
_channels.clear();
|
||||
_channels.resize(channels);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ auto Stream::setResamplerFrequency(f64 resamplerFrequency) -> void {
|
||||
_resamplerFrequency = resamplerFrequency;
|
||||
|
||||
for(auto& channel : _channels) {
|
||||
channel.nyquist.reset();
|
||||
channel.nyquist.clear();
|
||||
channel.resampler.reset(_frequency, _resamplerFrequency);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ auto Stream::setResamplerFrequency(f64 resamplerFrequency) -> void {
|
||||
DSP::IIR::Biquad filter;
|
||||
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, _frequency, q);
|
||||
channel.nyquist.append(filter);
|
||||
channel.nyquist.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ auto Stream::setMuted(bool muted) -> void {
|
||||
|
||||
auto Stream::resetFilters() -> void {
|
||||
for(auto& channel : _channels) {
|
||||
channel.filters.reset();
|
||||
channel.filters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,13 +47,13 @@ auto Stream::addLowPassFilter(f64 cutoffFrequency, u32 order, u32 passes) -> voi
|
||||
if(order == 1) {
|
||||
Filter filter{Filter::Mode::OnePole, Filter::Type::LowPass, Filter::Order::First};
|
||||
filter.onePole.reset(DSP::IIR::OnePole::Type::LowPass, cutoffFrequency, _frequency);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
if(order == 2) {
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::LowPass, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,13 +65,13 @@ auto Stream::addHighPassFilter(f64 cutoffFrequency, u32 order, u32 passes) -> vo
|
||||
if(order == 1) {
|
||||
Filter filter{Filter::Mode::OnePole, Filter::Type::HighPass, Filter::Order::First};
|
||||
filter.onePole.reset(DSP::IIR::OnePole::Type::HighPass, cutoffFrequency, _frequency);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
if(order == 2) {
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::HighPass, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::HighPass, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ auto Stream::addLowShelfFilter(f64 cutoffFrequency, u32 order, f64 gain, f64 slo
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::LowShelf, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::shelf(gain, slope);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::LowShelf, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,13 +94,13 @@ auto Stream::addHighShelfFilter(f64 cutoffFrequency, u32 order, f64 gain, f64 sl
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::HighShelf, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::shelf(gain, slope);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::HighShelf, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::pending() const -> bool {
|
||||
return _channels && _channels[0].resampler.pending();
|
||||
return !_channels.empty() && _channels[0].resampler.pending();
|
||||
}
|
||||
|
||||
auto Stream::read(f64 samples[]) -> u32 {
|
||||
@@ -127,5 +127,5 @@ auto Stream::write(const f64 samples[]) -> void {
|
||||
|
||||
//if there are samples pending, then alert the frontend to possibly process them.
|
||||
//this will generally happen when every audio stream has pending samples to be mixed.
|
||||
if(pending()) platform->audio(shared());
|
||||
if(pending()) platform->audio(std::static_pointer_cast<Core::Audio::Stream>(shared_from_this()));
|
||||
}
|
||||
@@ -38,11 +38,11 @@ protected:
|
||||
DSP::IIR::Biquad biquad;
|
||||
};
|
||||
struct Channel {
|
||||
vector<Filter> filters;
|
||||
vector<DSP::IIR::Biquad> nyquist;
|
||||
std::vector<Filter> filters;
|
||||
std::vector<DSP::IIR::Biquad> nyquist;
|
||||
DSP::Resampler::Cubic resampler;
|
||||
};
|
||||
vector<Channel> _channels;
|
||||
std::vector<Channel> _channels;
|
||||
f64 _frequency = 48000.0;
|
||||
f64 _resamplerFrequency = 48000.0;
|
||||
bool _muted = false;
|
||||
|
||||
@@ -4,26 +4,28 @@
|
||||
struct Class {
|
||||
struct Instance {
|
||||
const string identifier;
|
||||
const function<Node::Object ()> create;
|
||||
const std::function<Node::Object ()> create;
|
||||
};
|
||||
|
||||
static auto classes() -> vector<Instance>& {
|
||||
static vector<Instance> classes;
|
||||
static auto classes() -> std::vector<Instance>& {
|
||||
static std::vector<Instance> classes;
|
||||
return classes;
|
||||
}
|
||||
|
||||
template<typename T> static auto register() -> void {
|
||||
if(!classes().find([&](auto instance) { return instance.identifier == T::identifier(); })) {
|
||||
classes().append({T::identifier(), &T::create});
|
||||
auto& cls = classes();
|
||||
auto it = std::ranges::find_if(cls, [&](const Instance& instance) { return instance.identifier == T::identifier(); });
|
||||
if(it == cls.end()) {
|
||||
cls.push_back({T::identifier(), &T::create});
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
static auto create(string identifier) -> Node::Object {
|
||||
if(auto index = classes().find([&](auto instance) { return instance.identifier == identifier; })) {
|
||||
return classes()[*index].create();
|
||||
}
|
||||
auto& cls = classes();
|
||||
auto it = std::ranges::find_if(cls, [&](const Instance& instance) { return instance.identifier == identifier; });
|
||||
if(it != cls.end()) return it->create();
|
||||
if(identifier == "Object") throw; //should never occur: detects unregistered classes
|
||||
return create("Object");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ struct RealTimeClock : Component {
|
||||
auto update() -> void { if(_update) return _update(); }
|
||||
auto timestamp() const -> u64 { return _timestamp; }
|
||||
|
||||
auto setUpdate(function<void ()> update) -> void { _update = update; }
|
||||
auto setUpdate(std::function<void ()> update) -> void { _update = update; }
|
||||
auto setTimestamp(u64 timestamp) -> void { _timestamp = timestamp; }
|
||||
|
||||
auto synchronize(u64 timestamp = 0) -> void {
|
||||
@@ -25,6 +25,6 @@ struct RealTimeClock : Component {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<void ()> _update;
|
||||
std::function<void ()> _update;
|
||||
u64 _timestamp;
|
||||
};
|
||||
@@ -6,10 +6,10 @@ struct Graphics : Debugger {
|
||||
|
||||
auto width() const -> u32 { return _width; }
|
||||
auto height() const -> u32 { return _height; }
|
||||
auto capture() const -> vector<u32> { if(_capture) return _capture(); return {}; }
|
||||
auto capture() const -> std::vector<u32> { if(_capture) return _capture(); return {}; }
|
||||
|
||||
auto setSize(u32 width, u32 height) -> void { _width = width, _height = height; }
|
||||
auto setCapture(function<vector<u32> ()> capture) -> void { _capture = capture; }
|
||||
auto setCapture(std::function<std::vector<u32> ()> capture) -> void { _capture = capture; }
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
Debugger::serialize(output, depth);
|
||||
@@ -22,5 +22,5 @@ struct Graphics : Debugger {
|
||||
protected:
|
||||
u32 _width = 0;
|
||||
u32 _height = 0;
|
||||
function<vector<u32> ()> _capture;
|
||||
std::function<std::vector<u32> ()> _capture;
|
||||
};
|
||||
@@ -9,8 +9,8 @@ struct Memory : Debugger {
|
||||
auto write(u32 address, u8 data) const -> void { if(_write) return _write(address, data); }
|
||||
|
||||
auto setSize(u32 size) -> void { _size = size; }
|
||||
auto setRead(function<u8 (u32)> read) -> void { _read = read; }
|
||||
auto setWrite(function<void (u32, u8)> write) -> void { _write = write; }
|
||||
auto setRead(std::function<u8 (u32)> read) -> void { _read = read; }
|
||||
auto setWrite(std::function<void (u32, u8)> write) -> void { _write = write; }
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
Debugger::serialize(output, depth);
|
||||
@@ -22,6 +22,6 @@ struct Memory : Debugger {
|
||||
|
||||
protected:
|
||||
u32 _size = 0;
|
||||
function<u8 (u32)> _read;
|
||||
function<void (u32, u8)> _write;
|
||||
std::function<u8 (u32)> _read;
|
||||
std::function<void (u32, u8)> _write;
|
||||
};
|
||||
@@ -6,7 +6,7 @@ struct Properties : Debugger {
|
||||
|
||||
auto query() const -> string { if(_query) return _query(); return {}; }
|
||||
|
||||
auto setQuery(function<string ()> query) -> void { _query = query; }
|
||||
auto setQuery(std::function<string ()> query) -> void { _query = query; }
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
Debugger::serialize(output, depth);
|
||||
@@ -17,5 +17,5 @@ struct Properties : Debugger {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<string ()> _query;
|
||||
std::function<string ()> _query;
|
||||
};
|
||||
@@ -23,7 +23,7 @@ struct Instruction : Tracer {
|
||||
|
||||
auto setDepth(u32 depth) -> void {
|
||||
_depth = depth;
|
||||
_history.reset();
|
||||
_history.clear();
|
||||
_history.resize(depth);
|
||||
for(auto& history : _history) history = ~0ull;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ struct Instruction : Tracer {
|
||||
for(auto index : range(_depth - 1)) {
|
||||
_history[index] = _history[index + 1];
|
||||
}
|
||||
_history.last() = _address;
|
||||
_history.back() = _address;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -71,7 +71,8 @@ struct Instruction : Tracer {
|
||||
if(!enabled()) return;
|
||||
|
||||
if(_omitted) {
|
||||
PlatformLog(shared(), {"[Omitted: ", _omitted, "]"});
|
||||
auto message = string{ "[Omitted: ", _omitted, "]" };
|
||||
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), message);
|
||||
_omitted = 0;
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ struct Instruction : Tracer {
|
||||
context, " ",
|
||||
extra
|
||||
};
|
||||
PlatformLog(shared(), {output.strip()});
|
||||
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), {output.strip()});
|
||||
}
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
@@ -135,6 +136,6 @@ protected:
|
||||
//unserialized:
|
||||
n64 _address = 0;
|
||||
n64 _omitted = 0;
|
||||
vector<u64> _history;
|
||||
std::vector<u64> _history;
|
||||
hashset<VisitMask> _masks;
|
||||
};
|
||||
@@ -6,7 +6,7 @@ struct Notification : Tracer {
|
||||
|
||||
auto notify(const string& message = {}) -> void {
|
||||
if(!enabled()) return;
|
||||
PlatformLog(shared(), message);
|
||||
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), message);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -12,7 +12,7 @@ struct Tracer : Debugger {
|
||||
auto file() const -> bool { return _file; }
|
||||
auto autoLineBreak() const -> bool { return _autoLineBreak; }
|
||||
|
||||
auto setToggle(function<void ()> toggle) -> void { _toggle = toggle; }
|
||||
auto setToggle(std::function<void ()> toggle) -> void { _toggle = toggle; }
|
||||
auto setComponent(string component) -> void { _component = component; }
|
||||
auto setPrefix(bool prefix) -> void { _prefix = prefix; }
|
||||
auto setTerminal(bool terminal) -> void { _terminal = terminal; if(_toggle) _toggle(); }
|
||||
@@ -36,7 +36,7 @@ struct Tracer : Debugger {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<void ()> _toggle;
|
||||
std::function<void ()> _toggle;
|
||||
string _component;
|
||||
bool _prefix = false;
|
||||
bool _terminal = false;
|
||||
|
||||
@@ -5,6 +5,57 @@ struct Axis : Input {
|
||||
auto value() const -> s64 { return _value; }
|
||||
auto setValue(s64 value) -> void { _value = value; }
|
||||
|
||||
auto setOperatingRange(s16 position, double saturationRadius, double offset) -> double {
|
||||
return position * saturationRadius / 32767.0 + offset;
|
||||
}
|
||||
|
||||
auto processDeadzoneAndResponseCurve(double position, double innerDeadzone, double cardinalMax, double offset) -> double {
|
||||
auto lengthAbsolute = abs(position - offset);
|
||||
if(lengthAbsolute <= innerDeadzone) {
|
||||
position = offset;
|
||||
} else {
|
||||
lengthAbsolute = (lengthAbsolute - innerDeadzone) * (cardinalMax) / (cardinalMax - innerDeadzone) / lengthAbsolute;
|
||||
position = (position - offset) * lengthAbsolute + offset;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
auto revisePosition(double position, double length, double saturationRadius, double offset) -> double {
|
||||
if(length > saturationRadius) {
|
||||
length = saturationRadius / length;
|
||||
position = (position - offset) * length + offset;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
auto applyGateBoundaries(double innerDeadzone, double cardinalMax, double diagonalMax, double positionX, double positionY, double offset, double& boundedPositionX, double& boundedPositionY) -> void {
|
||||
if(positionX != offset && positionY != offset) {
|
||||
auto slope = (positionY - offset) / (positionX - offset);
|
||||
auto edgex = copysign(cardinalMax / (abs(slope) + (cardinalMax - diagonalMax) / diagonalMax), positionX);
|
||||
auto edgey = copysign(min(abs(edgex * slope), cardinalMax / (1.0 / abs(slope) + (cardinalMax - diagonalMax) / diagonalMax)), positionY);
|
||||
edgex = edgey / slope;
|
||||
|
||||
auto distanceToEdge = hypot(edgex, edgey);
|
||||
|
||||
auto length = hypot(positionX - offset, positionY - offset);
|
||||
if(length > distanceToEdge) {
|
||||
positionX = edgex + offset;
|
||||
positionY = edgey + offset;
|
||||
}
|
||||
}
|
||||
boundedPositionX = positionX;
|
||||
boundedPositionY = positionY;
|
||||
}
|
||||
|
||||
auto clampAxisToNearestBoundary(double position, double offset, double cardinalMax) -> double {
|
||||
if(abs(position - offset) > cardinalMax) position = copysign(cardinalMax, position - offset) + offset;
|
||||
return position;
|
||||
}
|
||||
|
||||
auto counteractPrecisionError(double position) -> double {
|
||||
return copysign(abs(position) + 1e-09, position);
|
||||
}
|
||||
|
||||
protected:
|
||||
s64 _value = 0;
|
||||
s64 _minimum = -32768;
|
||||
|
||||
+35
-34
@@ -45,47 +45,47 @@ namespace ares::Core {
|
||||
}
|
||||
|
||||
namespace ares::Node {
|
||||
using Object = shared_pointer<Core::Object>;
|
||||
using System = shared_pointer<Core::System>;
|
||||
using Peripheral = shared_pointer<Core::Peripheral>;
|
||||
using Port = shared_pointer<Core::Port>;
|
||||
using Object = std::shared_ptr<Core::Object>;
|
||||
using System = std::shared_ptr<Core::System>;
|
||||
using Peripheral = std::shared_ptr<Core::Peripheral>;
|
||||
using Port = std::shared_ptr<Core::Port>;
|
||||
namespace Component {
|
||||
using Component = shared_pointer<Core::Component::Component>;
|
||||
using RealTimeClock = shared_pointer<Core::Component::RealTimeClock>;
|
||||
using Component = std::shared_ptr<Core::Component::Component>;
|
||||
using RealTimeClock = std::shared_ptr<Core::Component::RealTimeClock>;
|
||||
}
|
||||
namespace Video {
|
||||
using Video = shared_pointer<Core::Video::Video>;
|
||||
using Sprite = shared_pointer<Core::Video::Sprite>;
|
||||
using Screen = shared_pointer<Core::Video::Screen>;
|
||||
using Video = std::shared_ptr<Core::Video::Video>;
|
||||
using Sprite = std::shared_ptr<Core::Video::Sprite>;
|
||||
using Screen = std::shared_ptr<Core::Video::Screen>;
|
||||
}
|
||||
namespace Audio {
|
||||
using Audio = shared_pointer<Core::Audio::Audio>;
|
||||
using Stream = shared_pointer<Core::Audio::Stream>;
|
||||
using Audio = std::shared_ptr<Core::Audio::Audio>;
|
||||
using Stream = std::shared_ptr<Core::Audio::Stream>;
|
||||
}
|
||||
namespace Input {
|
||||
using Input = shared_pointer<Core::Input::Input>;
|
||||
using Button = shared_pointer<Core::Input::Button>;
|
||||
using Axis = shared_pointer<Core::Input::Axis>;
|
||||
using Trigger = shared_pointer<Core::Input::Trigger>;
|
||||
using Rumble = shared_pointer<Core::Input::Rumble>;
|
||||
using Input = std::shared_ptr<Core::Input::Input>;
|
||||
using Button = std::shared_ptr<Core::Input::Button>;
|
||||
using Axis = std::shared_ptr<Core::Input::Axis>;
|
||||
using Trigger = std::shared_ptr<Core::Input::Trigger>;
|
||||
using Rumble = std::shared_ptr<Core::Input::Rumble>;
|
||||
}
|
||||
namespace Setting {
|
||||
using Setting = shared_pointer<Core::Setting::Setting>;
|
||||
using Boolean = shared_pointer<Core::Setting::Boolean>;
|
||||
using Natural = shared_pointer<Core::Setting::Natural>;
|
||||
using Integer = shared_pointer<Core::Setting::Integer>;
|
||||
using Real = shared_pointer<Core::Setting::Real>;
|
||||
using String = shared_pointer<Core::Setting::String>;
|
||||
using Setting = std::shared_ptr<Core::Setting::Setting>;
|
||||
using Boolean = std::shared_ptr<Core::Setting::Boolean>;
|
||||
using Natural = std::shared_ptr<Core::Setting::Natural>;
|
||||
using Integer = std::shared_ptr<Core::Setting::Integer>;
|
||||
using Real = std::shared_ptr<Core::Setting::Real>;
|
||||
using String = std::shared_ptr<Core::Setting::String>;
|
||||
}
|
||||
namespace Debugger {
|
||||
using Debugger = shared_pointer<Core::Debugger::Debugger>;
|
||||
using Memory = shared_pointer<Core::Debugger::Memory>;
|
||||
using Graphics = shared_pointer<Core::Debugger::Graphics>;
|
||||
using Properties = shared_pointer<Core::Debugger::Properties>;
|
||||
using Debugger = std::shared_ptr<Core::Debugger::Debugger>;
|
||||
using Memory = std::shared_ptr<Core::Debugger::Memory>;
|
||||
using Graphics = std::shared_ptr<Core::Debugger::Graphics>;
|
||||
using Properties = std::shared_ptr<Core::Debugger::Properties>;
|
||||
namespace Tracer {
|
||||
using Tracer = shared_pointer<Core::Debugger::Tracer::Tracer>;
|
||||
using Notification = shared_pointer<Core::Debugger::Tracer::Notification>;
|
||||
using Instruction = shared_pointer<Core::Debugger::Tracer::Instruction>;
|
||||
using Tracer = std::shared_ptr<Core::Debugger::Tracer::Tracer>;
|
||||
using Notification = std::shared_ptr<Core::Debugger::Tracer::Notification>;
|
||||
using Instruction = std::shared_ptr<Core::Debugger::Tracer::Instruction>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,9 +164,10 @@ namespace ares::Node {
|
||||
}
|
||||
|
||||
static inline auto parent(Object child) -> Object {
|
||||
if(!child || !child->parent()) return {};
|
||||
if(auto parent = child->parent().acquire()) return parent;
|
||||
return {};
|
||||
if(!child) return {};
|
||||
auto wp = child->parent();
|
||||
if(wp.expired()) return {};
|
||||
return wp.lock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -177,8 +178,8 @@ namespace ares::Node {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline auto enumerate(Object from) -> vector<T> {
|
||||
vector<T> objects;
|
||||
static inline auto enumerate(Object from) -> std::vector<T> {
|
||||
std::vector<T> objects;
|
||||
if(from) from->enumerate<T>(objects);
|
||||
return objects;
|
||||
}
|
||||
|
||||
+45
-38
@@ -3,13 +3,13 @@
|
||||
|
||||
#define DeclareClass(Type, Name) \
|
||||
static auto identifier() -> string { return Name; } \
|
||||
static auto create() -> Node::Object { return new Type; } \
|
||||
static auto create() -> Node::Object { return std::make_shared<Type>(); } \
|
||||
auto identity() const -> string override { return Name; } \
|
||||
private: static inline Class::Register<Type> register; public: \
|
||||
|
||||
struct Object : shared_pointer_this<Object> {
|
||||
struct Object : std::enable_shared_from_this<Object> {
|
||||
static auto identifier() -> string { return "Object"; }
|
||||
static auto create() -> Node::Object { return new Object; }
|
||||
static auto create() -> Node::Object { return std::make_shared<Object>(); }
|
||||
virtual auto identity() const -> string { return "Object"; }
|
||||
private: static inline Class::Register<Object> register; public:
|
||||
//DeclareClass(Object, "object")
|
||||
@@ -18,44 +18,47 @@ struct Object : shared_pointer_this<Object> {
|
||||
virtual ~Object() = default;
|
||||
|
||||
auto name() const -> string { return _name; }
|
||||
auto parent() const -> shared_pointer_weak<Object> { return _parent; }
|
||||
auto parent() const -> std::weak_ptr<Object> { return _parent; }
|
||||
|
||||
auto setName(string_view name) -> void { _name = name; }
|
||||
|
||||
auto prepend(Node::Object node) -> Node::Object {
|
||||
if(auto found = find(node)) return found;
|
||||
_nodes.prepend(node);
|
||||
node->_parent = shared();
|
||||
_nodes.insert(_nodes.begin(), node);
|
||||
node->_parent = shared_from_this();
|
||||
PlatformAttach(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T, typename... P>
|
||||
auto prepend(P&&... p) -> Node::Object {
|
||||
using Type = typename T::type;
|
||||
return prepend(shared_pointer<Type>::create(std::forward<P>(p)...));
|
||||
auto prepend(P&&... p) -> std::shared_ptr<typename T::element_type> {
|
||||
using Type = typename T::element_type;
|
||||
auto node = std::make_shared<Type>(std::forward<P>(p)...);
|
||||
prepend(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
auto append(Node::Object node) -> Node::Object {
|
||||
if(auto found = find(node)) return found;
|
||||
_nodes.append(node);
|
||||
node->_parent = shared();
|
||||
_nodes.push_back(node);
|
||||
node->_parent = shared_from_this();
|
||||
PlatformAttach(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T, typename... P>
|
||||
auto append(P&&... p) -> Node::Object {
|
||||
using Type = typename T::type;
|
||||
return append(shared_pointer<Type>::create(std::forward<P>(p)...));
|
||||
auto append(P&&... p) -> std::shared_ptr<typename T::element_type> {
|
||||
using Type = typename T::element_type;
|
||||
auto node = std::make_shared<Type>(std::forward<P>(p)...);
|
||||
append(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
auto remove(Node::Object node) -> void {
|
||||
if(auto index = _nodes.find(node)) {
|
||||
if(std::erase(_nodes, node)) {
|
||||
PlatformDetach(node);
|
||||
node->reset();
|
||||
node->_parent.reset();
|
||||
_nodes.remove(*index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,13 +68,12 @@ struct Object : shared_pointer_this<Object> {
|
||||
node->reset();
|
||||
node->_parent.reset();
|
||||
}
|
||||
_nodes.reset();
|
||||
_nodes.clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto cast() -> shared_pointer<typename T::type> {
|
||||
if(dynamic_cast<typename T::type*>(this)) return shared();
|
||||
return {};
|
||||
auto cast() -> std::shared_ptr<typename T::element_type> {
|
||||
return std::dynamic_pointer_cast<typename T::element_type>(shared_from_this());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -80,17 +82,20 @@ struct Object : shared_pointer_this<Object> {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto find() -> vector<shared_pointer<typename T::type>> {
|
||||
vector<shared_pointer<typename T::type>> result;
|
||||
if(dynamic_cast<typename T::type*>(this)) {
|
||||
if(auto instance = shared()) result.append(instance);
|
||||
auto find() -> std::vector<std::shared_ptr<typename T::element_type>> {
|
||||
std::vector<std::shared_ptr<typename T::element_type>> result;
|
||||
if(dynamic_cast<typename T::element_type*>(this)) {
|
||||
if(auto instance = cast<T>()) result.push_back(instance);
|
||||
}
|
||||
for(auto& node : _nodes) {
|
||||
auto sub = node->find<T>();
|
||||
std::ranges::copy(sub, std::back_inserter(result));
|
||||
}
|
||||
for(auto& node : _nodes) result.append(node->find<T>());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto find(u32 index) -> shared_pointer<typename T::type> {
|
||||
auto find(u32 index) -> std::shared_ptr<typename T::element_type> {
|
||||
auto result = find<T>();
|
||||
if(index < result.size()) return result[index];
|
||||
return {};
|
||||
@@ -106,31 +111,33 @@ struct Object : shared_pointer_this<Object> {
|
||||
|
||||
template<typename T = Node::Object>
|
||||
auto find(string name) -> T {
|
||||
using Type = typename T::type;
|
||||
auto path = name.split("/");
|
||||
name = path.takeFirst();
|
||||
using Type = typename T::element_type;
|
||||
auto path = nall::split(name, "/");
|
||||
if(path.empty()) return {};
|
||||
name = path.front();
|
||||
path.erase(path.begin());
|
||||
for(auto& node : _nodes) {
|
||||
if(node->_name != name) continue;
|
||||
if(path) return node->find<T>(path.merge("/"));
|
||||
if(node->identity() == Type::identifier()) return node;
|
||||
if(!path.empty()) return node->find<T>(nall::merge(path, "/"));
|
||||
if(node->identity() == Type::identifier()) return node->template cast<T>();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T = Node::Object>
|
||||
auto scan(string name) -> T {
|
||||
using Type = typename T::type;
|
||||
using Type = typename T::element_type;
|
||||
for(auto& node : _nodes) {
|
||||
if(node->identity() == Type::identifier() && node->_name == name) return node;
|
||||
if(node->identity() == Type::identifier() && node->_name == name) return node->template cast<T>();
|
||||
if(auto result = node->scan<T>(name)) return result;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto enumerate(vector<T>& objects) -> void {
|
||||
using Type = typename T::type;
|
||||
if(auto instance = cast<T>()) objects.append(instance);
|
||||
auto enumerate(std::vector<T>& objects) -> void {
|
||||
using Type = typename T::element_type;
|
||||
if(auto instance = cast<T>()) objects.push_back(instance);
|
||||
for(auto& node : _nodes) node->enumerate<T>(objects);
|
||||
}
|
||||
|
||||
@@ -230,6 +237,6 @@ protected:
|
||||
string _name;
|
||||
VFS::Pak _pak;
|
||||
set<Attribute> _attributes;
|
||||
shared_pointer_weak<Object> _parent;
|
||||
vector<Node::Object> _nodes;
|
||||
std::weak_ptr<Object> _parent;
|
||||
std::vector<Node::Object> _nodes;
|
||||
};
|
||||
@@ -5,15 +5,15 @@ struct Port : Object {
|
||||
auto type() const -> string { return _type; }
|
||||
auto family() const -> string { return _family; }
|
||||
auto hotSwappable() const -> bool { return _hotSwappable; }
|
||||
auto supported() const -> vector<string> { return _supported; }
|
||||
auto supported() const -> std::vector<string> { return _supported; }
|
||||
|
||||
auto setAllocate(function<Node::Peripheral (string)> allocate) -> void { _allocate = allocate; }
|
||||
auto setConnect(function<void ()> connect) -> void { _connect = connect; }
|
||||
auto setDisconnect(function<void ()> disconnect) -> void { _disconnect = disconnect; }
|
||||
auto setAllocate(std::function<Node::Peripheral (string)> allocate) -> void { _allocate = allocate; }
|
||||
auto setConnect(std::function<void ()> connect) -> void { _connect = connect; }
|
||||
auto setDisconnect(std::function<void ()> disconnect) -> void { _disconnect = disconnect; }
|
||||
auto setType(string type) -> void { _type = type; }
|
||||
auto setFamily(string family) -> void { _family = family; }
|
||||
auto setHotSwappable(bool hotSwappable) -> void { _hotSwappable = hotSwappable; }
|
||||
auto setSupported(vector<string> supported) -> void { _supported = supported; }
|
||||
auto setSupported(std::vector<string> supported) -> void { _supported = supported; }
|
||||
|
||||
auto connected() -> Node::Peripheral {
|
||||
return find<Node::Peripheral>(0);
|
||||
@@ -64,11 +64,11 @@ struct Port : Object {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<Node::Peripheral (string)> _allocate;
|
||||
function<void ()> _connect;
|
||||
function<void ()> _disconnect;
|
||||
std::function<Node::Peripheral (string)> _allocate;
|
||||
std::function<void ()> _connect;
|
||||
std::function<void ()> _disconnect;
|
||||
string _type;
|
||||
string _family;
|
||||
bool _hotSwappable = false;
|
||||
vector<string> _supported;
|
||||
std::vector<string> _supported;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Boolean : Setting {
|
||||
DeclareClass(Boolean, "setting.boolean")
|
||||
|
||||
Boolean(string name = {}, bool value = {}, function<void (bool)> modify = {}) : Setting(name) {
|
||||
Boolean(string name = {}, bool value = {}, std::function<void (bool)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,7 +11,7 @@ struct Boolean : Setting {
|
||||
auto value() const -> bool { return _currentValue; }
|
||||
auto latch() const -> bool { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (bool)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (bool)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(bool value) -> void {
|
||||
_currentValue = value;
|
||||
@@ -26,11 +26,11 @@ struct Boolean : Setting {
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override { return {"false", "true"}; }
|
||||
auto readAllowedValues() const -> std::vector<string> override { return {"false", "true"}; }
|
||||
auto writeValue(string value) -> void override { setValue(value.boolean()); }
|
||||
|
||||
protected:
|
||||
function<void (bool)> _modify;
|
||||
std::function<void (bool)> _modify;
|
||||
bool _currentValue = {};
|
||||
bool _latchedValue = {};
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Integer : Setting {
|
||||
DeclareClass(Integer, "setting.integer")
|
||||
|
||||
Integer(string name = {}, s64 value = {}, function<void (s64)> modify = {}) : Setting(name) {
|
||||
Integer(string name = {}, s64 value = {}, std::function<void (s64)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct Integer : Setting {
|
||||
auto value() const -> s64 { return _currentValue; }
|
||||
auto latch() const -> s64 { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (s64)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (s64)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(s64 value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,23 +25,23 @@ struct Integer : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<s64> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<s64> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override {
|
||||
vector<string> values;
|
||||
for(auto value : _allowedValues) values.append(value);
|
||||
auto readAllowedValues() const -> std::vector<string> override {
|
||||
std::vector<string> values;
|
||||
for(auto value : _allowedValues) values.push_back(value);
|
||||
return values;
|
||||
}
|
||||
auto writeValue(string value) -> void override { setValue(value.integer()); }
|
||||
|
||||
protected:
|
||||
function<void (s64)> _modify;
|
||||
std::function<void (s64)> _modify;
|
||||
s64 _currentValue = {};
|
||||
s64 _latchedValue = {};
|
||||
vector<s64> _allowedValues;
|
||||
std::vector<s64> _allowedValues;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Natural : Setting {
|
||||
DeclareClass(Natural, "setting.natural")
|
||||
|
||||
Natural(string name = {}, u64 value = {}, function<void (u64)> modify = {}) : Setting(name) {
|
||||
Natural(string name = {}, u64 value = {}, std::function<void (u64)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct Natural : Setting {
|
||||
auto value() const -> u64 { return _currentValue; }
|
||||
auto latch() const -> u64 { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (u64)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (u64)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(u64 value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,23 +25,23 @@ struct Natural : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<u64> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<u64> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override {
|
||||
vector<string> values;
|
||||
for(auto value : _allowedValues) values.append(value);
|
||||
auto readAllowedValues() const -> std::vector<string> override {
|
||||
std::vector<string> values;
|
||||
for(auto value : _allowedValues) values.push_back(value);
|
||||
return values;
|
||||
}
|
||||
auto writeValue(string value) -> void override { setValue(value.natural()); }
|
||||
|
||||
protected:
|
||||
function<void (u64)> _modify;
|
||||
std::function<void (u64)> _modify;
|
||||
u64 _currentValue = {};
|
||||
u64 _latchedValue = {};
|
||||
vector<u64> _allowedValues;
|
||||
std::vector<u64> _allowedValues;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Real : Setting {
|
||||
DeclareClass(Real, "setting.real")
|
||||
|
||||
Real(string name = {}, f64 value = {}, function<void (f64)> modify = {}) : Setting(name) {
|
||||
Real(string name = {}, f64 value = {}, std::function<void (f64)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct Real : Setting {
|
||||
auto value() const -> f64 { return _currentValue; }
|
||||
auto latch() const -> f64 { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (f64)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (f64)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(f64 value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,23 +25,23 @@ struct Real : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<f64> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<f64> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override {
|
||||
vector<string> values;
|
||||
for(auto value : _allowedValues) values.append(value);
|
||||
auto readAllowedValues() const -> std::vector<string> override {
|
||||
std::vector<string> values;
|
||||
for(auto value : _allowedValues) values.push_back(value);
|
||||
return values;
|
||||
}
|
||||
auto writeValue(string value) -> void override { setValue(value.real()); }
|
||||
|
||||
protected:
|
||||
function<void (f64)> _modify;
|
||||
std::function<void (f64)> _modify;
|
||||
f64 _currentValue = {};
|
||||
f64 _latchedValue = {};
|
||||
vector<f64> _allowedValues;
|
||||
std::vector<f64> _allowedValues;
|
||||
};
|
||||
@@ -12,12 +12,12 @@ struct Setting : Object {
|
||||
|
||||
virtual auto readValue() const -> string { return {}; }
|
||||
virtual auto readLatch() const -> string { return {}; }
|
||||
virtual auto readAllowedValues() const -> vector<string> { return {}; }
|
||||
virtual auto readAllowedValues() const -> std::vector<string> { return {}; }
|
||||
virtual auto writeValue(string value) -> void {}
|
||||
|
||||
auto load(Node::Object source) -> bool override {
|
||||
if(!Object::load(source)) return false;
|
||||
if(auto setting = source->cast<shared_pointer<Setting>>()) writeValue(setting->readValue());
|
||||
if(auto setting = source->cast<Node::Setting::Setting>()) writeValue(setting->readValue());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
struct String : Setting {
|
||||
DeclareClass(String, "setting.string")
|
||||
|
||||
String(string name = {}, string value = {}, function<void (string)> modify = {}) : Setting(name) {
|
||||
String(string name = {}, string value = {}, std::function<void (string)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct String : Setting {
|
||||
auto value() const -> string { return _currentValue; }
|
||||
auto latch() const -> string { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (string)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (string)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(string value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,19 +25,19 @@ struct String : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<string> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<string> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override { return _allowedValues; }
|
||||
auto readAllowedValues() const -> std::vector<string> override { return _allowedValues; }
|
||||
auto writeValue(string value) -> void override { setValue(value); }
|
||||
|
||||
protected:
|
||||
function<void (string)> _modify;
|
||||
std::function<void (string)> _modify;
|
||||
string _currentValue = {};
|
||||
string _latchedValue = {};
|
||||
vector<string> _allowedValues;
|
||||
std::vector<string> _allowedValues;
|
||||
};
|
||||
+14
-14
@@ -10,20 +10,20 @@ struct System : Object {
|
||||
auto serialize(bool synchronize = true) -> serializer { if(_serialize) return _serialize(synchronize); return {}; }
|
||||
auto unserialize(serializer& s) -> bool { if(_unserialize) return _unserialize(s); return false; }
|
||||
|
||||
auto setGame(function<string ()> game) -> void { _game = game; }
|
||||
auto setRun(function<void ()> run) -> void { _run = run; }
|
||||
auto setPower(function<void (bool)> power) -> void { _power = power; }
|
||||
auto setSave(function<void ()> save) -> void { _save = save; }
|
||||
auto setUnload(function<void ()> unload) -> void { _unload = unload; }
|
||||
auto setSerialize(function<serializer (bool)> serialize) -> void { _serialize = serialize; }
|
||||
auto setUnserialize(function<bool (serializer&)> unserialize) -> void { _unserialize = unserialize; }
|
||||
auto setGame(std::function<string ()> game) -> void { _game = game; }
|
||||
auto setRun(std::function<void ()> run) -> void { _run = run; }
|
||||
auto setPower(std::function<void (bool)> power) -> void { _power = power; }
|
||||
auto setSave(std::function<void ()> save) -> void { _save = save; }
|
||||
auto setUnload(std::function<void ()> unload) -> void { _unload = unload; }
|
||||
auto setSerialize(std::function<serializer (bool)> serialize) -> void { _serialize = serialize; }
|
||||
auto setUnserialize(std::function<bool (serializer&)> unserialize) -> void { _unserialize = unserialize; }
|
||||
|
||||
protected:
|
||||
function<string ()> _game;
|
||||
function<void ()> _run;
|
||||
function<void (bool)> _power;
|
||||
function<void ()> _save;
|
||||
function<void ()> _unload;
|
||||
function<serializer (bool)> _serialize;
|
||||
function<bool (serializer&)> _unserialize;
|
||||
std::function<string ()> _game;
|
||||
std::function<void ()> _run;
|
||||
std::function<void (bool)> _power;
|
||||
std::function<void ()> _save;
|
||||
std::function<void ()> _unload;
|
||||
std::function<serializer (bool)> _serialize;
|
||||
std::function<bool (serializer&)> _unserialize;
|
||||
};
|
||||
@@ -1,15 +1,18 @@
|
||||
#include <memory>
|
||||
Screen::Screen(string name, u32 width, u32 height) : Video(name) {
|
||||
_canvasWidth = width;
|
||||
_canvasHeight = height;
|
||||
|
||||
if(width && height) {
|
||||
_inputA = new u32[width * height]();
|
||||
_inputB = new u32[width * height]();
|
||||
_output = new u32[width * height]();
|
||||
_rotate = new u32[width * height]();
|
||||
_inputA = std::make_unique<u32[]>(width * height);
|
||||
_inputB = std::make_unique<u32[]>(width * height);
|
||||
_output = std::make_unique<u32[]>(width * height);
|
||||
_rotate = std::make_unique<u32[]>(width * height);
|
||||
_lineOverrideActive.resize(width * height, false);
|
||||
_lineOverride.resize(width * height, nullptr);
|
||||
|
||||
if constexpr(ares::Video::Threaded) {
|
||||
_thread = nall::thread::create({&Screen::main, this});
|
||||
_thread = nall::thread::create(std::bind_front(&Screen::main, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +27,7 @@ Screen::~Screen() {
|
||||
}
|
||||
|
||||
auto Screen::main(uintptr_t) -> void {
|
||||
thread::setName("dev.ares.screen");
|
||||
while(!_kill) {
|
||||
unique_lock<mutex> lock(_frameMutex);
|
||||
|
||||
@@ -40,34 +44,37 @@ auto Screen::main(uintptr_t) -> void {
|
||||
auto Screen::quit() -> void {
|
||||
_kill = true;
|
||||
_thread.join();
|
||||
_sprites.reset();
|
||||
_sprites.clear();
|
||||
}
|
||||
|
||||
auto Screen::power() -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
memory::fill<u32>(_inputA.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_inputB.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_output.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_rotate.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_inputA.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_inputB.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_output.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_rotate.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<n1>(_lineOverrideActive.data(), _canvasWidth * _canvasHeight, false);
|
||||
memory::fill<const u32*>(_lineOverride.data(), _canvasWidth * _canvasHeight, nullptr);
|
||||
}
|
||||
|
||||
auto Screen::pixels(bool frame) -> array_span<u32> {
|
||||
if(frame == 0) return {_inputA.data(), _canvasWidth * _canvasHeight};
|
||||
if(frame == 1) return {_inputB.data(), _canvasWidth * _canvasHeight};
|
||||
auto Screen::pixels(bool frame) -> std::span<u32> {
|
||||
if(frame == 0) return {_inputA.get(), _canvasWidth * _canvasHeight};
|
||||
if(frame == 1) return {_inputB.get(), _canvasWidth * _canvasHeight};
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Screen::resetPalette() -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::resetSprites() -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_sprites.reset();
|
||||
_sprites.clear();
|
||||
}
|
||||
|
||||
auto Screen::setRefresh(function<void ()> refresh) -> void {
|
||||
auto Screen::setRefresh(std::function<void ()> refresh) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_refresh = refresh;
|
||||
}
|
||||
@@ -116,18 +123,21 @@ auto Screen::setSaturation(f64 saturation) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_saturation = saturation;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::setGamma(f64 gamma) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_gamma = gamma;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::setLuminance(f64 luminance) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_luminance = luminance;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::setFillColor(u32 fillColor) -> void {
|
||||
@@ -171,21 +181,22 @@ auto Screen::setInterlace(bool interlaceField) -> void {
|
||||
|
||||
auto Screen::attach(Node::Video::Sprite sprite) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
if(_sprites.find(sprite)) return;
|
||||
_sprites.append(sprite);
|
||||
if(std::ranges::find(_sprites, sprite) != _sprites.end()) return;
|
||||
_sprites.push_back(sprite);
|
||||
}
|
||||
|
||||
auto Screen::detach(Node::Video::Sprite sprite) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
if(!_sprites.find(sprite)) return;
|
||||
_sprites.removeByValue(sprite);
|
||||
if(std::ranges::find(_sprites, sprite) == _sprites.end()) return;
|
||||
std::erase(_sprites, sprite);
|
||||
}
|
||||
|
||||
auto Screen::colors(u32 colors, function<n64 (n32)> color) -> void {
|
||||
auto Screen::colors(u32 colors, std::function<n64 (n32)> color) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_colors = colors;
|
||||
_color = color;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::frame() -> void {
|
||||
@@ -218,14 +229,20 @@ auto Screen::refresh() -> void {
|
||||
auto pitch = _canvasWidth;
|
||||
auto width = _canvasWidth;
|
||||
auto height = _canvasHeight;
|
||||
auto input = _inputB.data();
|
||||
auto output = _output.data();
|
||||
auto input = _inputB.get();
|
||||
auto output = _output.get();
|
||||
|
||||
for(u32 y : range(height)) {
|
||||
auto source = input + y * pitch;
|
||||
auto target = output + y * width;
|
||||
|
||||
if(_interlace) {
|
||||
if (_lineOverrideActive[y]) {
|
||||
auto source = _lineOverride[y];
|
||||
for(u32 x : range(width)) {
|
||||
auto color = *source++;
|
||||
*target++ = color;
|
||||
}
|
||||
} else if(_interlace) {
|
||||
if((_interlaceField & 1) == (y & 1)) {
|
||||
for(u32 x : range(width)) {
|
||||
auto color = _palette[*source++];
|
||||
@@ -294,11 +311,11 @@ auto Screen::refresh() -> void {
|
||||
for(u32 y : range(height)) {
|
||||
auto source = output + y * width;
|
||||
for(u32 x : range(width)) {
|
||||
auto target = _rotate.data() + (width - 1 - x) * height + y;
|
||||
auto target = _rotate.get() + (width - 1 - x) * height + y;
|
||||
*target = *source++;
|
||||
}
|
||||
}
|
||||
output = _rotate.data();
|
||||
output = _rotate.get();
|
||||
swap(width, height);
|
||||
swap(viewWidth, viewHeight);
|
||||
}
|
||||
@@ -308,11 +325,11 @@ auto Screen::refresh() -> void {
|
||||
for(u32 y : range(height)) {
|
||||
auto source = output + y * width;
|
||||
for(u32 x : range(width)) {
|
||||
auto target = _rotate.data() + (height - 1 - y) * width + (width - 1 - x);
|
||||
auto target = _rotate.get() + (height - 1 - y) * width + (width - 1 - x);
|
||||
*target = *source++;
|
||||
}
|
||||
}
|
||||
output = _rotate.data();
|
||||
output = _rotate.get();
|
||||
}
|
||||
|
||||
if(_rotation == 270) {
|
||||
@@ -320,17 +337,31 @@ auto Screen::refresh() -> void {
|
||||
for(u32 y : range(height)) {
|
||||
auto source = output + y * width;
|
||||
for(u32 x : range(width)) {
|
||||
auto target = _rotate.data() + x * height + (height - 1 - y);
|
||||
auto target = _rotate.get() + x * height + (height - 1 - y);
|
||||
*target = *source++;
|
||||
}
|
||||
}
|
||||
output = _rotate.data();
|
||||
output = _rotate.get();
|
||||
swap(width, height);
|
||||
swap(viewWidth, viewHeight);
|
||||
}
|
||||
|
||||
platform->video(shared(), output + viewX + viewY * width, width * sizeof(u32), viewWidth, viewHeight);
|
||||
memory::fill<u32>(_inputB.data(), width * height, _fillColor);
|
||||
platform->video(std::static_pointer_cast<Core::Video::Screen>(shared_from_this()), output + viewX + viewY * width, width * sizeof(u32), viewWidth, viewHeight);
|
||||
memory::fill<u32>(_inputB.get(), width * height, _fillColor);
|
||||
}
|
||||
|
||||
auto Screen::lookupPalette(u32 index) -> u32 {
|
||||
return _palette[index];
|
||||
}
|
||||
|
||||
auto Screen::overrideLineDraw(u32 y, const u32* source) -> void {
|
||||
_lineOverride[y] = source;
|
||||
_lineOverrideActive[y] = true;
|
||||
}
|
||||
|
||||
auto Screen::clearOverrideLineDraw(u32 y) -> void {
|
||||
_lineOverrideActive[y] = false;
|
||||
_lineOverride[y] = nullptr;
|
||||
}
|
||||
|
||||
auto Screen::refreshPalette() -> void {
|
||||
@@ -338,7 +369,7 @@ auto Screen::refreshPalette() -> void {
|
||||
if(_palette) return;
|
||||
|
||||
//generate the color lookup palettes to convert native colors to ARGB8888
|
||||
_palette = new u32[_colors];
|
||||
_palette = std::make_unique<u32[]>(_colors);
|
||||
for(u32 index : range(_colors)) {
|
||||
n64 color = _color(index);
|
||||
n16 b = color.bit( 0,15);
|
||||
@@ -348,10 +379,9 @@ auto Screen::refreshPalette() -> void {
|
||||
|
||||
if(_saturation != 1.0) {
|
||||
n16 grayscale = uclamp<16>((r + g + b) / 3);
|
||||
f64 inverse = max(0.0, 1.0 - _saturation);
|
||||
r = uclamp<16>(r * _saturation + grayscale * inverse);
|
||||
g = uclamp<16>(g * _saturation + grayscale * inverse);
|
||||
b = uclamp<16>(b * _saturation + grayscale * inverse);
|
||||
r = uclamp<16>(grayscale + (r - grayscale) * _saturation);
|
||||
g = uclamp<16>(grayscale + (g - grayscale) * _saturation);
|
||||
b = uclamp<16>(grayscale + (b - grayscale) * _saturation);
|
||||
}
|
||||
|
||||
if(_gamma != 1.0) {
|
||||
|
||||
@@ -18,7 +18,7 @@ struct Screen : Video {
|
||||
auto aspectY() const -> f64 { return _aspectY; }
|
||||
auto overscan() const -> bool { return _overscan; }
|
||||
auto colors() const -> u32 { return _colors; }
|
||||
auto pixels(bool frame = 0) -> array_span<u32>;
|
||||
auto pixels(bool frame = 0) -> std::span<u32>;
|
||||
|
||||
auto saturation() const -> double { return _saturation; }
|
||||
auto gamma() const -> double { return _gamma; }
|
||||
@@ -32,7 +32,7 @@ struct Screen : Video {
|
||||
auto resetPalette() -> void;
|
||||
auto resetSprites() -> void;
|
||||
|
||||
auto setRefresh(function<void ()> refresh) -> void;
|
||||
auto setRefresh(std::function<void ()> refresh) -> void;
|
||||
auto setViewport(u32 x, u32 y, u32 width, u32 height) -> void;
|
||||
auto refreshRateHint(double refreshRate) -> void;
|
||||
auto refreshRateHint(double pixelFrequency, int dotsPerLine, int linesPerFrame) -> void;
|
||||
@@ -58,9 +58,12 @@ struct Screen : Video {
|
||||
auto attach(Node::Video::Sprite) -> void;
|
||||
auto detach(Node::Video::Sprite) -> void;
|
||||
|
||||
auto colors(u32 colors, function<n64 (n32)> color) -> void;
|
||||
auto colors(u32 colors, std::function<n64 (n32)> color) -> void;
|
||||
auto frame() -> void;
|
||||
auto refresh() -> void;
|
||||
auto lookupPalette(u32 index) -> u32;
|
||||
auto overrideLineDraw(u32 y, const u32* source) -> void;
|
||||
auto clearOverrideLineDraw(u32 y) -> void;
|
||||
|
||||
auto serialize(string& output, string depth) -> void override;
|
||||
auto unserialize(Markup::Node node) -> void override;
|
||||
@@ -83,18 +86,20 @@ protected:
|
||||
f64 _luminance = 1.0;
|
||||
u32 _fillColor = 0;
|
||||
bool _colorBleed = false;
|
||||
bool _colorBleedWidth = 1;
|
||||
u32 _colorBleedWidth = 1;
|
||||
bool _interframeBlending = false;
|
||||
bool _overscan = true;
|
||||
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[]> _palette;
|
||||
vector<Node::Video::Sprite> _sprites;
|
||||
std::function<n64 (n32)> _color;
|
||||
std::unique_ptr<u32[]> _inputA;
|
||||
std::unique_ptr<u32[]> _inputB;
|
||||
std::unique_ptr<u32[]> _output;
|
||||
std::unique_ptr<u32[]> _rotate;
|
||||
std::unique_ptr<u32[]> _palette;
|
||||
std::vector<n1> _lineOverrideActive;
|
||||
std::vector<const u32*> _lineOverride;
|
||||
std::vector<Node::Video::Sprite> _sprites;
|
||||
|
||||
//unserialized:
|
||||
nall::thread _thread;
|
||||
@@ -103,7 +108,7 @@ protected:
|
||||
condition_variable _frameCondition;
|
||||
atomic<bool> _kill = false;
|
||||
atomic<bool> _frame = false;
|
||||
function<void ()> _refresh;
|
||||
std::function<void ()> _refresh;
|
||||
bool _progressive = false;
|
||||
bool _progressiveDouble = false;
|
||||
bool _interlace = false;
|
||||
|
||||
@@ -10,13 +10,13 @@ auto Sprite::setPosition(u32 x, u32 y) -> void {
|
||||
auto Sprite::setImage(nall::image image, bool invert) -> void {
|
||||
_width = image.width();
|
||||
_height = image.height();
|
||||
_pixels = new u32[_width * _height];
|
||||
_pixels = std::make_unique<u32[]>(_width * _height);
|
||||
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
|
||||
memory::copy(_pixels.data(), _width * _height * sizeof(u32), image.data(), image.size());
|
||||
memory::copy(_pixels.get(), _width * _height * sizeof(u32), image.data(), image.size());
|
||||
if(!invert) return;
|
||||
|
||||
for(u32 y : range(_height)) {
|
||||
auto data = _pixels.data() + y * _width;
|
||||
auto data = _pixels.get() + y * _width;
|
||||
for(u32 x : range(_width)) {
|
||||
auto pixel = data[x];
|
||||
pixel ^= 0xffffff;
|
||||
|
||||
@@ -7,7 +7,7 @@ struct Sprite : Video {
|
||||
auto y() const -> u32 { return _y; }
|
||||
auto width() const -> u32 { return _width; }
|
||||
auto height() const -> u32 { return _height; }
|
||||
auto image() const -> array_view<u32> { return {_pixels.data(), _width * _height}; }
|
||||
auto image() const -> std::span<const u32> { return {_pixels.get(), _width * _height}; }
|
||||
|
||||
auto setVisible(bool visible) -> void;
|
||||
auto setPosition(u32 x, u32 y) -> void;
|
||||
@@ -19,5 +19,5 @@ protected:
|
||||
u32 _y = 0;
|
||||
u32 _width = 0;
|
||||
u32 _height = 0;
|
||||
unique_pointer<u32[]> _pixels;
|
||||
std::unique_ptr<u32[]> _pixels;
|
||||
};
|
||||
@@ -13,7 +13,7 @@ enum class Event : u32 {
|
||||
struct Platform {
|
||||
virtual auto attach(Node::Object) -> void {}
|
||||
virtual auto detach(Node::Object) -> void {}
|
||||
virtual auto pak(Node::Object) -> shared_pointer<vfs::directory> { return {}; }
|
||||
virtual auto pak(Node::Object) -> std::shared_ptr<vfs::directory> { return {}; }
|
||||
virtual auto event(Event) -> void {}
|
||||
virtual auto log(Node::Debugger::Tracer::Tracer, string_view message) -> void {}
|
||||
virtual auto status(string_view message) -> void {}
|
||||
|
||||
+13
-5
@@ -4,6 +4,9 @@ namespace ares {
|
||||
|
||||
struct Random {
|
||||
enum class Entropy : u32 { None, Low, High };
|
||||
struct Init { u64 seed, sequence; };
|
||||
|
||||
static constexpr Init Default { 0x853c49e6748fea9b, 0xda3e39cb94b95bdb };
|
||||
|
||||
auto operator()() -> n64 {
|
||||
return random();
|
||||
@@ -14,8 +17,8 @@ struct Random {
|
||||
seed();
|
||||
}
|
||||
|
||||
auto seed(maybe<n32> seed = nothing, maybe<n32> sequence = nothing) -> void {
|
||||
if(!seed) seed = (n32)clock();
|
||||
auto seed(maybe<n64> seed = nothing, maybe<n64> sequence = nothing) -> void {
|
||||
if(!seed) seed = (n64)clock();
|
||||
if(!sequence) sequence = 0;
|
||||
|
||||
_state = 0;
|
||||
@@ -25,6 +28,10 @@ struct Random {
|
||||
step();
|
||||
}
|
||||
|
||||
auto seed(Init init) -> void {
|
||||
seed((n64)init.seed, (n64)init.sequence);
|
||||
}
|
||||
|
||||
auto random() -> n64 {
|
||||
if(_entropy == Entropy::None) return 0;
|
||||
return (n64)step() << 32 | (n64)step() << 0;
|
||||
@@ -43,15 +50,16 @@ struct Random {
|
||||
}
|
||||
}
|
||||
|
||||
auto array(array_span<n8> buffer) -> void {
|
||||
auto array(std::span<u8> buffer) -> void {
|
||||
if(_entropy == Entropy::None) {
|
||||
memory::fill(buffer.data(), buffer.size());
|
||||
return;
|
||||
}
|
||||
|
||||
if(_entropy == Entropy::High) {
|
||||
for(n32 address : range(buffer.size())) {
|
||||
buffer[address] = random();
|
||||
while(buffer.size()) {
|
||||
u64 value = random();
|
||||
nall::writel(buffer, value, min((u32)sizeof(value), (u32)buffer.size()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
build := stable
|
||||
nall.path := ../../../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
all:
|
||||
sourcery resource.bml resource.cpp resource.hpp
|
||||
|
||||
clean:
|
||||
$(call delete,resource.cpp)
|
||||
$(call delete,resource.hpp)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,34 +0,0 @@
|
||||
namespace Resource {
|
||||
namespace Ares {
|
||||
extern const unsigned char Icon1x[6562];
|
||||
extern const unsigned char Icon2x[9662];
|
||||
extern const unsigned char Logo1x[11533];
|
||||
extern const unsigned char Logo2x[18991];
|
||||
}
|
||||
namespace Sprite {
|
||||
namespace SuperFamicom {
|
||||
extern const unsigned char CrosshairBlue[332];
|
||||
extern const unsigned char CrosshairGreen[329];
|
||||
extern const unsigned char CrosshairRed[342];
|
||||
}
|
||||
namespace WonderSwan {
|
||||
extern const unsigned char Auxiliary0[117];
|
||||
extern const unsigned char Auxiliary1[134];
|
||||
extern const unsigned char Auxiliary2[136];
|
||||
extern const unsigned char Headphones[167];
|
||||
extern const unsigned char Initialized[136];
|
||||
extern const unsigned char LowBattery[144];
|
||||
extern const unsigned char Orientation0[148];
|
||||
extern const unsigned char Orientation1[150];
|
||||
extern const unsigned char PoweredOn[155];
|
||||
extern const unsigned char Sleeping[154];
|
||||
extern const unsigned char VolumeA0[129];
|
||||
extern const unsigned char VolumeA1[142];
|
||||
extern const unsigned char VolumeA2[146];
|
||||
extern const unsigned char VolumeB0[125];
|
||||
extern const unsigned char VolumeB1[137];
|
||||
extern const unsigned char VolumeB2[148];
|
||||
extern const unsigned char VolumeB3[153];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
inline auto Scheduler::reset() -> void {
|
||||
_threads.reset();
|
||||
_threads.clear();
|
||||
}
|
||||
|
||||
inline auto Scheduler::threads() const -> u32 {
|
||||
@@ -41,15 +41,15 @@ inline auto Scheduler::maximum() const -> u64 {
|
||||
}
|
||||
|
||||
inline auto Scheduler::append(Thread& thread) -> bool {
|
||||
if(_threads.find(&thread)) return false;
|
||||
if(std::ranges::find(_threads, &thread) != _threads.end()) return false;
|
||||
thread._uniqueID = uniqueID();
|
||||
thread._clock = maximum() + thread._uniqueID;
|
||||
_threads.append(&thread);
|
||||
_threads.push_back(&thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline auto Scheduler::remove(Thread& thread) -> void {
|
||||
_threads.removeByValue(&thread);
|
||||
std::erase(_threads, &thread);
|
||||
}
|
||||
|
||||
//power cycle and soft reset events: assigns the primary thread and resets all thread clocks.
|
||||
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
cothread_t _primary = nullptr; //primary thread (used to synchronize components)
|
||||
Mode _mode = Mode::Run;
|
||||
Event _event = Event::Step;
|
||||
vector<Thread*> _threads;
|
||||
std::vector<Thread*> _threads;
|
||||
bool _synchronize = false;
|
||||
|
||||
friend struct Thread;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
inline auto Thread::EntryPoints() -> vector<EntryPoint>& {
|
||||
static vector<EntryPoint> entryPoints;
|
||||
inline auto Thread::EntryPoints() -> std::vector<EntryPoint>& {
|
||||
static std::vector<EntryPoint> entryPoints;
|
||||
return entryPoints;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ inline auto Thread::Enter() -> void {
|
||||
for(u32 index : range(EntryPoints().size())) {
|
||||
if(co_active() == EntryPoints()[index].handle) {
|
||||
auto entryPoint = EntryPoints()[index].entryPoint;
|
||||
EntryPoints().remove(index);
|
||||
EntryPoints().erase(EntryPoints().begin() + index);
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
entryPoint();
|
||||
@@ -45,22 +45,22 @@ inline auto Thread::setClock(u64 clock) -> void {
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
inline auto Thread::create(double frequency, function<void ()> entryPoint) -> void {
|
||||
inline auto Thread::create(double frequency, std::function<void ()> entryPoint) -> void {
|
||||
if(!_handle) {
|
||||
_handle = co_create(Thread::Size, &Thread::Enter);
|
||||
} else {
|
||||
co_derive(_handle, Thread::Size, &Thread::Enter);
|
||||
}
|
||||
EntryPoints().append({_handle, entryPoint});
|
||||
EntryPoints().push_back({_handle, entryPoint});
|
||||
setFrequency(frequency);
|
||||
setClock(0);
|
||||
scheduler.append(*this);
|
||||
}
|
||||
|
||||
//returns a thread to its entry point (eg for a reset), without resetting the clock value
|
||||
inline auto Thread::restart(function<void()> entryPoint) -> void {
|
||||
inline auto Thread::restart(std::function<void()> entryPoint) -> void {
|
||||
co_derive(_handle, Thread::Size, &Thread::Enter);
|
||||
EntryPoints().append({_handle, entryPoint});
|
||||
EntryPoints().push_back({_handle, entryPoint});
|
||||
}
|
||||
|
||||
inline auto Thread::destroy() -> void {
|
||||
|
||||
@@ -6,10 +6,10 @@ struct Thread {
|
||||
|
||||
struct EntryPoint {
|
||||
cothread_t handle = nullptr;
|
||||
function<void ()> entryPoint;
|
||||
std::function<void ()> entryPoint;
|
||||
};
|
||||
|
||||
static auto EntryPoints() -> vector<EntryPoint>&;
|
||||
static auto EntryPoints() -> std::vector<EntryPoint>&;
|
||||
static auto Enter() -> void;
|
||||
|
||||
Thread() = default;
|
||||
@@ -29,8 +29,8 @@ struct Thread {
|
||||
auto setScalar(u64 scalar) -> void;
|
||||
auto setClock(u64 clock) -> void;
|
||||
|
||||
auto create(double frequency, function<void ()> entryPoint) -> void;
|
||||
auto restart(function<void ()> entryPoint) -> void;
|
||||
auto create(double frequency, std::function<void ()> entryPoint) -> void;
|
||||
auto restart(std::function<void ()> entryPoint) -> void;
|
||||
auto destroy() -> void;
|
||||
|
||||
auto step(u32 clocks) -> void;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
target_link_options(ares PRIVATE LINKER:-export-dynamic)
|
||||
|
||||
target_sources(ares PRIVATE cmake/os-linux.cmake)
|
||||
@@ -0,0 +1 @@
|
||||
target_sources(ares PRIVATE cmake/os-macos.cmake)
|
||||
@@ -0,0 +1,5 @@
|
||||
target_link_libraries(
|
||||
ares
|
||||
PRIVATE uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32
|
||||
)
|
||||
target_sources(ares PRIVATE cmake/os-windows.cmake)
|
||||
@@ -0,0 +1,486 @@
|
||||
list(REMOVE_DUPLICATES ares.components)
|
||||
|
||||
set(ARES_COMPONENTS_LIST "${ares.components}" CACHE STRING "Enabled shared hardware components" FORCE)
|
||||
|
||||
mark_as_advanced(ARES_COMPONENTS_LIST)
|
||||
|
||||
ares_add_sources(INCLUDED CMakeLists.txt)
|
||||
|
||||
macro(component_sources)
|
||||
set(options "")
|
||||
set(oneValueArgs COMPONENT PRIMARY)
|
||||
set(multiValueArgs INCLUDED)
|
||||
|
||||
cmake_parse_arguments(CPS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(${CPS_COMPONENT} IN_LIST ares.components)
|
||||
target_sources(ares PRIVATE ${CPS_PRIMARY})
|
||||
foreach(arg IN ITEMS ${CPS_INCLUDED})
|
||||
list(APPEND ARES_HEADER_SOURCES "component/${arg}")
|
||||
target_sources(ares PRIVATE ${arg})
|
||||
endforeach()
|
||||
endif()
|
||||
set(ARES_HEADER_SOURCES ${ARES_HEADER_SOURCES} PARENT_SCOPE)
|
||||
endmacro()
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
ay38910
|
||||
PRIMARY
|
||||
audio/ay38910/ay38910.cpp
|
||||
INCLUDED
|
||||
audio/ay38910/ay38910.hpp
|
||||
audio/ay38910/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
msm5205
|
||||
PRIMARY
|
||||
audio/msm5205/msm5205.cpp
|
||||
INCLUDED
|
||||
audio/msm5205/msm5205.hpp
|
||||
audio/msm5205/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
sn76489
|
||||
PRIMARY
|
||||
audio/sn76489/sn76489.cpp
|
||||
INCLUDED
|
||||
audio/sn76489/sn76489.hpp
|
||||
audio/sn76489/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
t6w28
|
||||
PRIMARY
|
||||
audio/t6w28/t6w28.cpp
|
||||
INCLUDED
|
||||
audio/t6w28/t6w28.hpp
|
||||
audio/t6w28/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
ym2149
|
||||
PRIMARY
|
||||
audio/ym2149/ym2149.cpp
|
||||
INCLUDED
|
||||
audio/ym2149/ym2149.hpp
|
||||
audio/ym2149/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
ym2413
|
||||
PRIMARY
|
||||
audio/ym2413/ym2413.cpp
|
||||
INCLUDED
|
||||
audio/ym2413/constants.cpp
|
||||
audio/ym2413/io.cpp
|
||||
audio/ym2413/operator.cpp
|
||||
audio/ym2413/serialization.cpp
|
||||
audio/ym2413/voice.cpp
|
||||
audio/ym2413/ym2413.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
ym2612
|
||||
PRIMARY
|
||||
audio/ym2612/ym2612.cpp
|
||||
INCLUDED
|
||||
audio/ym2612/channel.cpp
|
||||
audio/ym2612/constants.cpp
|
||||
audio/ym2612/io.cpp
|
||||
audio/ym2612/serialization.cpp
|
||||
audio/ym2612/timer.cpp
|
||||
audio/ym2612/ym2612.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
m24c
|
||||
PRIMARY
|
||||
eeprom/m24c/m24c.cpp
|
||||
INCLUDED
|
||||
eeprom/m24c/m24c.hpp
|
||||
eeprom/m24c/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
m93lcx6
|
||||
PRIMARY
|
||||
eeprom/m93lcx6/m93lcx6.cpp
|
||||
INCLUDED
|
||||
eeprom/m93lcx6/m93lcx6.hpp
|
||||
eeprom/m93lcx6/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
i8255
|
||||
PRIMARY
|
||||
io/i8255/i8255.cpp
|
||||
INCLUDED
|
||||
io/i8255/i8255.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
arm7tdmi
|
||||
PRIMARY
|
||||
processor/arm7tdmi/arm7tdmi.cpp
|
||||
INCLUDED
|
||||
processor/arm7tdmi/algorithms.cpp
|
||||
processor/arm7tdmi/arm7tdmi.hpp
|
||||
processor/arm7tdmi/coprocessor.cpp
|
||||
processor/arm7tdmi/disassembler.cpp
|
||||
processor/arm7tdmi/instruction.cpp
|
||||
processor/arm7tdmi/instructions-arm.cpp
|
||||
processor/arm7tdmi/instructions-thumb.cpp
|
||||
processor/arm7tdmi/memory.cpp
|
||||
processor/arm7tdmi/registers.cpp
|
||||
processor/arm7tdmi/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
gsu
|
||||
PRIMARY
|
||||
processor/gsu/gsu.cpp
|
||||
INCLUDED
|
||||
processor/gsu/disassembler.cpp
|
||||
processor/gsu/gsu.hpp
|
||||
processor/gsu/instruction.cpp
|
||||
processor/gsu/instructions.cpp
|
||||
processor/gsu/registers.hpp
|
||||
processor/gsu/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
hg51b
|
||||
PRIMARY
|
||||
processor/hg51b/hg51b.cpp
|
||||
INCLUDED
|
||||
processor/hg51b/disassembler.cpp
|
||||
processor/hg51b/hg51b.hpp
|
||||
processor/hg51b/instruction.cpp
|
||||
processor/hg51b/instructions.cpp
|
||||
processor/hg51b/registers.cpp
|
||||
processor/hg51b/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
huc6280
|
||||
PRIMARY
|
||||
processor/huc6280/huc6280.cpp
|
||||
INCLUDED
|
||||
processor/huc6280/algorithms.cpp
|
||||
processor/huc6280/disassembler.cpp
|
||||
processor/huc6280/huc6280.hpp
|
||||
processor/huc6280/instruction.cpp
|
||||
processor/huc6280/instructions.cpp
|
||||
processor/huc6280/memory.cpp
|
||||
processor/huc6280/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
i8080
|
||||
PRIMARY
|
||||
processor/i8080/i8080.cpp
|
||||
INCLUDED
|
||||
processor/i8080/algorithms.cpp
|
||||
processor/i8080/disassembler.cpp
|
||||
processor/i8080/i8080.hpp
|
||||
processor/i8080/instruction.cpp
|
||||
processor/i8080/instructions.cpp
|
||||
processor/i8080/memory.cpp
|
||||
processor/i8080/registers.hpp
|
||||
processor/i8080/serialization.cpp
|
||||
)
|
||||
component_sources(
|
||||
COMPONENT
|
||||
m68hc05
|
||||
PRIMARY
|
||||
processor/m68hc05/m68hc05.cpp
|
||||
INCLUDED
|
||||
processor/m68hc05/algorithms.cpp
|
||||
processor/m68hc05/disassembler.cpp
|
||||
processor/m68hc05/instruction.cpp
|
||||
processor/m68hc05/instructions.cpp
|
||||
processor/m68hc05/m68hc05.hpp
|
||||
processor/m68hc05/memory.cpp
|
||||
processor/m68hc05/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
m68000
|
||||
PRIMARY
|
||||
processor/m68000/m68000.cpp
|
||||
INCLUDED
|
||||
processor/m68000/algorithms.cpp
|
||||
processor/m68000/conditions.cpp
|
||||
processor/m68000/disassembler.cpp
|
||||
processor/m68000/effective-address.cpp
|
||||
processor/m68000/instruction.cpp
|
||||
processor/m68000/instructions.cpp
|
||||
processor/m68000/m68000.hpp
|
||||
processor/m68000/memory.cpp
|
||||
processor/m68000/registers.cpp
|
||||
processor/m68000/serialization.cpp
|
||||
processor/m68000/traits.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
mos6502
|
||||
PRIMARY
|
||||
processor/mos6502/mos6502.cpp
|
||||
INCLUDED
|
||||
processor/mos6502/addresses.cpp
|
||||
processor/mos6502/algorithms.cpp
|
||||
processor/mos6502/disassembler.cpp
|
||||
processor/mos6502/instruction.cpp
|
||||
processor/mos6502/instructions.cpp
|
||||
processor/mos6502/memory.cpp
|
||||
processor/mos6502/mos6502.hpp
|
||||
processor/mos6502/serialization.cpp
|
||||
)
|
||||
component_sources(
|
||||
COMPONENT
|
||||
sh2
|
||||
PRIMARY
|
||||
processor/sh2/sh2.cpp
|
||||
INCLUDED
|
||||
processor/sh2/accuracy.hpp
|
||||
processor/sh2/decoder.hpp
|
||||
processor/sh2/disassembler.cpp
|
||||
processor/sh2/exceptions.cpp
|
||||
processor/sh2/instruction.cpp
|
||||
processor/sh2/instructions.cpp
|
||||
processor/sh2/recompiler.cpp
|
||||
processor/sh2/serialization.cpp
|
||||
processor/sh2/sh2.hpp
|
||||
processor/sh2/sh7604/bus.cpp
|
||||
processor/sh2/sh7604/cache.cpp
|
||||
processor/sh2/sh7604/dma.cpp
|
||||
processor/sh2/sh7604/interrupts.cpp
|
||||
processor/sh2/sh7604/io.cpp
|
||||
processor/sh2/sh7604/serial.cpp
|
||||
processor/sh2/sh7604/sh7604.cpp
|
||||
processor/sh2/sh7604/sh7604.hpp
|
||||
processor/sh2/sh7604/timer.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
sm5k
|
||||
PRIMARY
|
||||
processor/sm5k/sm5k.cpp
|
||||
INCLUDED
|
||||
processor/sm5k/disassembler.cpp
|
||||
processor/sm5k/instruction.cpp
|
||||
processor/sm5k/instructions.cpp
|
||||
processor/sm5k/memory.cpp
|
||||
processor/sm5k/serialization.cpp
|
||||
processor/sm5k/sm5k.hpp
|
||||
processor/sm5k/timer.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
sm83
|
||||
PRIMARY
|
||||
processor/sm83/sm83.cpp
|
||||
INCLUDED
|
||||
processor/sm83/algorithms.cpp
|
||||
processor/sm83/disassembler.cpp
|
||||
processor/sm83/instruction.cpp
|
||||
processor/sm83/instructions.cpp
|
||||
processor/sm83/memory.cpp
|
||||
processor/sm83/registers.hpp
|
||||
processor/sm83/serialization.cpp
|
||||
processor/sm83/sm83.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
spc700
|
||||
PRIMARY
|
||||
processor/spc700/spc700.cpp
|
||||
INCLUDED
|
||||
processor/spc700/algorithms.cpp
|
||||
processor/spc700/disassembler.cpp
|
||||
processor/spc700/instruction.cpp
|
||||
processor/spc700/instructions.cpp
|
||||
processor/spc700/memory.cpp
|
||||
processor/spc700/serialization.cpp
|
||||
processor/spc700/spc700.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
ssp1601
|
||||
PRIMARY
|
||||
processor/ssp1601/ssp1601.cpp
|
||||
INCLUDED
|
||||
processor/ssp1601/algorithms.cpp
|
||||
processor/ssp1601/disassembler.cpp
|
||||
processor/ssp1601/instructions.cpp
|
||||
processor/ssp1601/memory.cpp
|
||||
processor/ssp1601/registers.cpp
|
||||
processor/ssp1601/serialization.cpp
|
||||
processor/ssp1601/ssp1601.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
tlcs900h
|
||||
PRIMARY
|
||||
processor/tlcs900h/tlcs900h.cpp
|
||||
INCLUDED
|
||||
processor/tlcs900h/algorithms.cpp
|
||||
processor/tlcs900h/conditions.cpp
|
||||
processor/tlcs900h/control-registers.cpp
|
||||
processor/tlcs900h/disassembler.cpp
|
||||
processor/tlcs900h/dma.cpp
|
||||
processor/tlcs900h/instruction.cpp
|
||||
processor/tlcs900h/instructions.cpp
|
||||
processor/tlcs900h/memory.cpp
|
||||
processor/tlcs900h/prefetch.cpp
|
||||
processor/tlcs900h/registers.cpp
|
||||
processor/tlcs900h/serialization.cpp
|
||||
processor/tlcs900h/tlcs900h.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
upd96050
|
||||
PRIMARY
|
||||
processor/upd96050/upd96050.cpp
|
||||
INCLUDED
|
||||
processor/upd96050/disassembler.cpp
|
||||
processor/upd96050/instructions.cpp
|
||||
processor/upd96050/memory.cpp
|
||||
processor/upd96050/serialization.cpp
|
||||
processor/upd96050/upd96050.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
v30mz
|
||||
PRIMARY
|
||||
processor/v30mz/v30mz.cpp
|
||||
INCLUDED
|
||||
processor/v30mz/algorithms.cpp
|
||||
processor/v30mz/disassembler.cpp
|
||||
processor/v30mz/instruction.cpp
|
||||
processor/v30mz/instructions-adjust.cpp
|
||||
processor/v30mz/instructions-alu.cpp
|
||||
processor/v30mz/instructions-exec.cpp
|
||||
processor/v30mz/instructions-flag.cpp
|
||||
processor/v30mz/instructions-group.cpp
|
||||
processor/v30mz/instructions-misc.cpp
|
||||
processor/v30mz/instructions-move.cpp
|
||||
processor/v30mz/instructions-string.cpp
|
||||
processor/v30mz/memory.cpp
|
||||
processor/v30mz/modrm.cpp
|
||||
processor/v30mz/prefetch.cpp
|
||||
processor/v30mz/registers.cpp
|
||||
processor/v30mz/serialization.cpp
|
||||
processor/v30mz/v30mz.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
wdc65816
|
||||
PRIMARY
|
||||
processor/wdc65816/wdc65816.cpp
|
||||
INCLUDED
|
||||
processor/wdc65816/algorithms.cpp
|
||||
processor/wdc65816/disassembler.cpp
|
||||
processor/wdc65816/instruction.cpp
|
||||
processor/wdc65816/instruction.hpp
|
||||
processor/wdc65816/instructions-modify.cpp
|
||||
processor/wdc65816/instructions-other.cpp
|
||||
processor/wdc65816/instructions-pc.cpp
|
||||
processor/wdc65816/instructions-read.cpp
|
||||
processor/wdc65816/instructions-write.cpp
|
||||
processor/wdc65816/memory.cpp
|
||||
processor/wdc65816/registers.hpp
|
||||
processor/wdc65816/serialization.cpp
|
||||
processor/wdc65816/wdc65816.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
z80
|
||||
PRIMARY
|
||||
processor/z80/z80.cpp
|
||||
INCLUDED
|
||||
processor/z80/algorithms.cpp
|
||||
processor/z80/disassembler.cpp
|
||||
processor/z80/instruction.cpp
|
||||
processor/z80/instructions.cpp
|
||||
processor/z80/memory.cpp
|
||||
processor/z80/registers.hpp
|
||||
processor/z80/serialization.cpp
|
||||
processor/z80/z80.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
s3511a
|
||||
PRIMARY
|
||||
rtc/s3511a/s3511a.cpp
|
||||
INCLUDED
|
||||
rtc/s3511a/s3511a.hpp
|
||||
rtc/s3511a/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
sst39sf0x0
|
||||
PRIMARY
|
||||
flash/sst39sf0x0/sst39sf0x0.cpp
|
||||
INCLUDED
|
||||
flash/sst39sf0x0/sst39sf0x0.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
tms9918
|
||||
PRIMARY
|
||||
video/tms9918/tms9918.cpp
|
||||
INCLUDED
|
||||
video/tms9918/background.cpp
|
||||
video/tms9918/dac.cpp
|
||||
video/tms9918/io.cpp
|
||||
video/tms9918/serialization.cpp
|
||||
video/tms9918/sprite.cpp
|
||||
video/tms9918/tms9918.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
v9938
|
||||
PRIMARY
|
||||
video/v9938/v9938.cpp
|
||||
INCLUDED
|
||||
video/v9938/background.cpp
|
||||
video/v9938/commands.cpp
|
||||
video/v9938/dac.cpp
|
||||
video/v9938/io.cpp
|
||||
video/v9938/serialization.cpp
|
||||
video/v9938/sprite.cpp
|
||||
video/v9938/v9938.hpp
|
||||
)
|
||||
@@ -1,76 +0,0 @@
|
||||
ares.components := $(call unique,$(ares.components))
|
||||
|
||||
ares.objects += $(if $(findstring ay38910,$(ares.components)),ares-audio-ay38910)
|
||||
ares.objects += $(if $(findstring msm5205,$(ares.components)),ares-audio-msm5205)
|
||||
ares.objects += $(if $(findstring sn76489,$(ares.components)),ares-audio-sn76489)
|
||||
ares.objects += $(if $(findstring t6w28,$(ares.components)),ares-audio-t6w28)
|
||||
ares.objects += $(if $(findstring ym2149,$(ares.components)),ares-audio-ym2149)
|
||||
ares.objects += $(if $(findstring ym2413,$(ares.components)),ares-audio-ym2413)
|
||||
ares.objects += $(if $(findstring ym2610,$(ares.components)),ares-audio-ym2610)
|
||||
ares.objects += $(if $(findstring ym2612,$(ares.components)),ares-audio-ym2612)
|
||||
|
||||
ares.objects += $(if $(findstring m24c,$(ares.components)),ares-eeprom-m24c)
|
||||
ares.objects += $(if $(findstring m93lcx6,$(ares.components)),ares-eeprom-m93lcx6)
|
||||
|
||||
ares.objects += $(if $(findstring i8255,$(ares.components)),ares-io-i8255)
|
||||
|
||||
ares.objects += $(if $(findstring arm7tdmi,$(ares.components)),ares-processor-arm7tdmi)
|
||||
ares.objects += $(if $(findstring gsu,$(ares.components)),ares-processor-gsu)
|
||||
ares.objects += $(if $(findstring hg51b,$(ares.components)),ares-processor-hg51b)
|
||||
ares.objects += $(if $(findstring huc6280,$(ares.components)),ares-processor-huc6280)
|
||||
ares.objects += $(if $(findstring i8080,$(ares.components)),ares-processor-i8080)
|
||||
ares.objects += $(if $(findstring m68hc05,$(ares.components)),ares-processor-m68hc05)
|
||||
ares.objects += $(if $(findstring m68000,$(ares.components)),ares-processor-m68000)
|
||||
ares.objects += $(if $(findstring mos6502,$(ares.components)),ares-processor-mos6502)
|
||||
ares.objects += $(if $(findstring sh2,$(ares.components)),ares-processor-sh2)
|
||||
ares.objects += $(if $(findstring sm5k,$(ares.components)),ares-processor-sm5k)
|
||||
ares.objects += $(if $(findstring sm83,$(ares.components)),ares-processor-sm83)
|
||||
ares.objects += $(if $(findstring spc700,$(ares.components)),ares-processor-spc700)
|
||||
ares.objects += $(if $(findstring ssp1601,$(ares.components)),ares-processor-ssp1601)
|
||||
ares.objects += $(if $(findstring tlcs900h,$(ares.components)),ares-processor-tlcs900h)
|
||||
ares.objects += $(if $(findstring upd96050,$(ares.components)),ares-processor-upd96050)
|
||||
ares.objects += $(if $(findstring v30mz,$(ares.components)),ares-processor-v30mz)
|
||||
ares.objects += $(if $(findstring wdc65816,$(ares.components)),ares-processor-wdc65816)
|
||||
ares.objects += $(if $(findstring z80,$(ares.components)),ares-processor-z80)
|
||||
|
||||
ares.objects += $(if $(findstring sst39sf0x0,$(ares.components)),ares-flash-sst39sf0x0)
|
||||
|
||||
ares.objects += $(if $(findstring tms9918,$(ares.components)),ares-video-tms9918)
|
||||
ares.objects += $(if $(findstring v9938,$(ares.components)),ares-video-v9938)
|
||||
|
||||
$(object.path)/ares-audio-ay38910.o: $(ares.path)/component/audio/ay38910/ay38910.cpp
|
||||
$(object.path)/ares-audio-msm5205.o: $(ares.path)/component/audio/msm5205/msm5205.cpp
|
||||
$(object.path)/ares-audio-sn76489.o: $(ares.path)/component/audio/sn76489/sn76489.cpp
|
||||
$(object.path)/ares-audio-t6w28.o: $(ares.path)/component/audio/t6w28/t6w28.cpp
|
||||
$(object.path)/ares-audio-ym2149.o: $(ares.path)/component/audio/ym2149/ym2149.cpp
|
||||
$(object.path)/ares-audio-ym2413.o: $(ares.path)/component/audio/ym2413/ym2413.cpp
|
||||
$(object.path)/ares-audio-ym2612.o: $(ares.path)/component/audio/ym2612/ym2612.cpp
|
||||
|
||||
$(object.path)/ares-eeprom-m24c.o: $(ares.path)/component/eeprom/m24c/m24c.cpp
|
||||
$(object.path)/ares-eeprom-m93lcx6.o: $(ares.path)/component/eeprom/m93lcx6/m93lcx6.cpp
|
||||
|
||||
$(object.path)/ares-io-i8255.o: $(ares.path)/component/io/i8255/i8255.cpp
|
||||
|
||||
$(object.path)/ares-processor-arm7tdmi.o: $(ares.path)/component/processor/arm7tdmi/arm7tdmi.cpp
|
||||
$(object.path)/ares-processor-gsu.o: $(ares.path)/component/processor/gsu/gsu.cpp
|
||||
$(object.path)/ares-processor-hg51b.o: $(ares.path)/component/processor/hg51b/hg51b.cpp
|
||||
$(object.path)/ares-processor-huc6280.o: $(ares.path)/component/processor/huc6280/huc6280.cpp
|
||||
$(object.path)/ares-processor-i8080.o: $(ares.path)/component/processor/i8080/i8080.cpp
|
||||
$(object.path)/ares-processor-m68hc05.o: $(ares.path)/component/processor/m68hc05/m68hc05.cpp
|
||||
$(object.path)/ares-processor-m68000.o: $(ares.path)/component/processor/m68000/m68000.cpp
|
||||
$(object.path)/ares-processor-mos6502.o: $(ares.path)/component/processor/mos6502/mos6502.cpp
|
||||
$(object.path)/ares-processor-sh2.o: $(ares.path)/component/processor/sh2/sh2.cpp
|
||||
$(object.path)/ares-processor-sm5k.o: $(ares.path)/component/processor/sm5k/sm5k.cpp
|
||||
$(object.path)/ares-processor-sm83.o: $(ares.path)/component/processor/sm83/sm83.cpp
|
||||
$(object.path)/ares-processor-spc700.o: $(ares.path)/component/processor/spc700/spc700.cpp
|
||||
$(object.path)/ares-processor-ssp1601.o: $(ares.path)/component/processor/ssp1601/ssp1601.cpp
|
||||
$(object.path)/ares-processor-tlcs900h.o: $(ares.path)/component/processor/tlcs900h/tlcs900h.cpp
|
||||
$(object.path)/ares-processor-upd96050.o: $(ares.path)/component/processor/upd96050/upd96050.cpp
|
||||
$(object.path)/ares-processor-v30mz.o: $(ares.path)/component/processor/v30mz/v30mz.cpp
|
||||
$(object.path)/ares-processor-wdc65816.o: $(ares.path)/component/processor/wdc65816/wdc65816.cpp
|
||||
$(object.path)/ares-processor-z80.o: $(ares.path)/component/processor/z80/z80.cpp
|
||||
|
||||
$(object.path)/ares-flash-sst39sf0x0.o: $(ares.path)/component/flash/sst39sf0x0/sst39sf0x0.cpp
|
||||
|
||||
$(object.path)/ares-video-tms9918.o: $(ares.path)/component/video/tms9918/tms9918.cpp
|
||||
$(object.path)/ares-video-v9938.o: $(ares.path)/component/video/v9938/v9938.cpp
|
||||
@@ -135,10 +135,10 @@ auto YM2149::read() -> n8 {
|
||||
data.bit(4,7) = envelope.unused;
|
||||
break;
|
||||
case 14:
|
||||
data.bit(0,7) = portA.data;
|
||||
data.bit(0,7) = readIO(0);
|
||||
break;
|
||||
case 15:
|
||||
data.bit(0,7) = portB.data;
|
||||
data.bit(0,7) = readIO(1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -215,9 +215,11 @@ auto YM2149::write(n8 data) -> void {
|
||||
break;
|
||||
case 14:
|
||||
portA.data = data;
|
||||
writeIO(0, data);
|
||||
break;
|
||||
case 15:
|
||||
portB.data = data;
|
||||
writeIO(1, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace ares {
|
||||
//Yamaha YM2149 (General Instrument AY-3-8910 derivative)
|
||||
|
||||
struct YM2149 {
|
||||
virtual auto readIO(n1 port) -> n8 { return 0xff; }
|
||||
virtual auto writeIO(n1 port, n8 data) -> void {}
|
||||
|
||||
//ym2149.cpp
|
||||
auto clock() -> array<n5[3]>;
|
||||
auto read() -> n8;
|
||||
|
||||
@@ -29,24 +29,25 @@ auto YM2612::Channel::Operator::updateKeyState() -> void {
|
||||
auto YM2612::Channel::Operator::runEnvelope() -> void {
|
||||
if(ym2612.envelope.clock & (1 << envelope.divider) - 1) return;
|
||||
|
||||
if(envelope.state == Attack && envelope.value == 0) {
|
||||
envelope.state = Decay;
|
||||
updateEnvelope();
|
||||
}
|
||||
|
||||
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x1f << 5;
|
||||
if(envelope.state == Decay && envelope.value >= sustain) {
|
||||
envelope.state = Sustain;
|
||||
updateEnvelope();
|
||||
}
|
||||
|
||||
u32 value = ym2612.envelope.clock >> envelope.divider;
|
||||
u32 step = envelope.steps >> ((~value & 7) << 2) & 0xf;
|
||||
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x1f << 5;
|
||||
|
||||
if(envelope.state == Attack) {
|
||||
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;
|
||||
}
|
||||
// will stop updating if attack rate is increased to upper threshold during attack phase (confirmed behavior)
|
||||
if(envelope.rate < 62) envelope.value += ~u16(envelope.value) * step >> 4;
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -82,8 +83,6 @@ auto YM2612::Channel::Operator::runPhase() -> void {
|
||||
}
|
||||
|
||||
auto YM2612::Channel::Operator::updateEnvelope() -> void {
|
||||
u32 key = min(max((u32)pitch.value, 0x300), 0x4ff);
|
||||
u32 ksr = (octave.value << 2) + ((key - 0x300) >> 7);
|
||||
u32 rate = 0;
|
||||
|
||||
if(envelope.state == Attack) rate += (envelope.attackRate << 1);
|
||||
@@ -91,7 +90,7 @@ auto YM2612::Channel::Operator::updateEnvelope() -> void {
|
||||
if(envelope.state == Sustain) rate += (envelope.sustainRate << 1);
|
||||
if(envelope.state == Release) rate += (envelope.releaseRate << 1);
|
||||
|
||||
rate += (ksr >> 3 - envelope.keyScale) * (rate > 0);
|
||||
rate += (keyScale >> 3 - envelope.rateScaling) * (rate > 0);
|
||||
rate = min(rate, 63);
|
||||
|
||||
auto& entry = envelopeRates[rate >> 2];
|
||||
@@ -107,15 +106,15 @@ auto YM2612::Channel::Operator::updatePitch() -> void {
|
||||
pitch.value = channel.mode ? pitch.reload : channel[3].pitch.reload;
|
||||
octave.value = channel.mode ? octave.reload : channel[3].octave.reload;
|
||||
|
||||
u32 key = min(max((u32)pitch.value, 0x300), 0x4ff);
|
||||
keyScale = (octave.value << 2) + ((key - 0x300) >> 7);
|
||||
|
||||
updatePhase();
|
||||
updateEnvelope(); //due to key scaling
|
||||
}
|
||||
|
||||
auto YM2612::Channel::Operator::updatePhase() -> void {
|
||||
u32 key = min(max((u32)pitch.value, 0x300), 0x4ff);
|
||||
u32 ksr = (octave.value << 2) + ((key - 0x300) >> 7);
|
||||
u32 tuning = detune & 3 ? detunes[(detune & 3) - 1][ksr & 7] >> (3 - (ksr >> 3)) : 0;
|
||||
|
||||
u32 tuning = detune & 3 ? detunes[(detune & 3) - 1][keyScale & 7] >> (3 - (keyScale >> 3)) : 0;
|
||||
u32 lfo = ym2612.lfo.clock >> 2 & 0x1f;
|
||||
s32 pm = (pitch.value * vibratos[channel.vibrato][lfo & 15] >> 9) * (lfo > 15 ? -1 : 1);
|
||||
|
||||
@@ -126,12 +125,12 @@ auto YM2612::Channel::Operator::updatePhase() -> void {
|
||||
|
||||
auto YM2612::Channel::Operator::updateLevel() -> void {
|
||||
u32 lfo = ym2612.lfo.clock & 0x40 ? ym2612.lfo.clock & 0x3f : ~ym2612.lfo.clock & 0x3f;
|
||||
u32 depth = tremolos[channel.tremolo];
|
||||
u32 depth = tremolos[tremoloEnable * channel.tremolo];
|
||||
|
||||
bool invert = ssg.attack != ssg.invert && envelope.state != Release;
|
||||
n10 value = ssg.enable && invert ? 0x200 - envelope.value : 0 + envelope.value;
|
||||
|
||||
outputLevel = ((totalLevel << 3) + value + (lfoEnable ? lfo << 1 >> depth : 0)) << 3;
|
||||
outputLevel = (totalLevel << 3) + value + (lfo << 1 >> depth) << 3;
|
||||
}
|
||||
|
||||
auto YM2612::Channel::power() -> void {
|
||||
@@ -148,7 +147,8 @@ auto YM2612::Channel::power() -> void {
|
||||
for(auto& op : operators) {
|
||||
op.keyOn = 0;
|
||||
op.keyLine = 0;
|
||||
op.lfoEnable = 0;
|
||||
op.tremoloEnable = 0;
|
||||
op.keyScale = 0;
|
||||
op.detune = 0;
|
||||
op.multiple = 0;
|
||||
op.totalLevel = 0;
|
||||
@@ -175,7 +175,7 @@ auto YM2612::Channel::power() -> void {
|
||||
op.envelope.steps = 0;
|
||||
op.envelope.value = 0x3ff;
|
||||
|
||||
op.envelope.keyScale = 0;
|
||||
op.envelope.rateScaling = 0;
|
||||
op.envelope.attackRate = 0;
|
||||
op.envelope.decayRate = 0;
|
||||
op.envelope.sustainRate = 0;
|
||||
|
||||
@@ -14,8 +14,10 @@ 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;
|
||||
if(!lfo.enable) {
|
||||
lfo.clock = 0;
|
||||
lfo.divider = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -34,18 +36,14 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
//timer B period
|
||||
case 0x026: {
|
||||
timerB.period.bit(0,7) = data.bit(0,7);
|
||||
// Not sure if this is the right place for it, but...
|
||||
// handle a specific use case to reset the subticks on timer B
|
||||
if(!timerB.enable) timerB.divider = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
//timer control
|
||||
case 0x027: {
|
||||
//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;
|
||||
timerB.divider = 0;
|
||||
}
|
||||
|
||||
timerA.enable = data.bit(0);
|
||||
timerB.enable = data.bit(1);
|
||||
timerA.irq = data.bit(2);
|
||||
@@ -114,19 +112,19 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
break;
|
||||
}
|
||||
|
||||
//key scaling, attack rate
|
||||
//rate scaling, attack rate
|
||||
case 0x050: {
|
||||
op.envelope.attackRate = data.bit(0,4);
|
||||
op.envelope.keyScale = data.bit(6,7);
|
||||
op.envelope.rateScaling = data.bit(6,7);
|
||||
channel[index].updateEnvelope();
|
||||
channel[index].updatePhase();
|
||||
break;
|
||||
}
|
||||
|
||||
//LFO enable, decay rate
|
||||
//LFO AM enable, decay rate
|
||||
case 0x060: {
|
||||
op.envelope.decayRate = data.bit(0,4);
|
||||
op.lfoEnable = data.bit(7);
|
||||
op.tremoloEnable = data.bit(7);
|
||||
channel[index].updateEnvelope();
|
||||
channel[index].updateLevel();
|
||||
break;
|
||||
|
||||
@@ -13,12 +13,14 @@ auto YM2612::serialize(serializer& s) -> void {
|
||||
s(envelope.divider);
|
||||
|
||||
s(timerA.enable);
|
||||
s(timerA.enableLatch);
|
||||
s(timerA.irq);
|
||||
s(timerA.line);
|
||||
s(timerA.period);
|
||||
s(timerA.counter);
|
||||
|
||||
s(timerB.enable);
|
||||
s(timerB.enableLatch);
|
||||
s(timerB.irq);
|
||||
s(timerB.line);
|
||||
s(timerB.period);
|
||||
@@ -43,7 +45,8 @@ auto YM2612::Channel::serialize(serializer& s) -> void {
|
||||
auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
|
||||
s(keyOn);
|
||||
s(keyLine);
|
||||
s(lfoEnable);
|
||||
s(tremoloEnable);
|
||||
s(keyScale);
|
||||
s(detune);
|
||||
s(multiple);
|
||||
s(totalLevel);
|
||||
@@ -68,7 +71,7 @@ auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
|
||||
s(envelope.divider);
|
||||
s(envelope.steps);
|
||||
s(envelope.value);
|
||||
s(envelope.keyScale);
|
||||
s(envelope.rateScaling);
|
||||
s(envelope.attackRate);
|
||||
s(envelope.decayRate);
|
||||
s(envelope.sustainRate);
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
auto YM2612::TimerA::run() -> void {
|
||||
if(!enable) return;
|
||||
if(++counter) return;
|
||||
|
||||
counter = period;
|
||||
line |= irq;
|
||||
if(!++counter)
|
||||
line |= irq & enableLatch;
|
||||
if(enableLatch < enable || !counter)
|
||||
counter = period;
|
||||
enableLatch = enable;
|
||||
}
|
||||
|
||||
auto YM2612::TimerB::run() -> void {
|
||||
if(!enable) return;
|
||||
if(++divider) return;
|
||||
if(++counter) return;
|
||||
|
||||
counter = period;
|
||||
line |= irq;
|
||||
if(!++divider && !++counter)
|
||||
line |= irq & enableLatch;
|
||||
if(enableLatch < enable || !counter && !divider)
|
||||
counter = period; // do not reset divider on reenable
|
||||
enableLatch = enable;
|
||||
}
|
||||
@@ -13,6 +13,25 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
s32 left = 0;
|
||||
s32 right = 0;
|
||||
|
||||
timerA.run();
|
||||
timerB.run();
|
||||
|
||||
if(++envelope.divider == 3) {
|
||||
envelope.divider = 0;
|
||||
if(!++envelope.clock) ++envelope.clock; // 12-bit counter: 1..4095 - zero-value is skipped (confirmed behavior)
|
||||
}
|
||||
|
||||
if(lfo.enable && ++lfo.divider >= lfoDividers[lfo.rate]) {
|
||||
lfo.divider = 0;
|
||||
lfo.clock++;
|
||||
for(auto& channel : channels) {
|
||||
for(auto& op : channel.operators) {
|
||||
op.updatePhase(); //due to vibrato
|
||||
op.updateLevel(); //due to tremolo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& channel : channels) {
|
||||
auto& op = channel.operators;
|
||||
|
||||
@@ -30,12 +49,18 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
return y < 0x1a00 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0; // -78 dB floor
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
for(auto& op : channel.operators) {
|
||||
op.runPhase();
|
||||
if(envelope.divider) continue;
|
||||
op.runEnvelope();
|
||||
}
|
||||
|
||||
s32 feedback = modMask & op[0].prior + op[0].priorBuffer >> 9 - channel.feedback;
|
||||
s32 accumulator = 0;
|
||||
|
||||
op[0].output = wave(0, feedback * (channel.feedback > 0));
|
||||
|
||||
// Note: Despite not emulating per cycle, operator pipelining has been accounted for.
|
||||
@@ -122,33 +147,6 @@ auto YM2612::clock() -> array<i16[2]> {
|
||||
//if(channel.rightEnable) right += voiceData;
|
||||
}
|
||||
|
||||
timerA.run();
|
||||
timerB.run();
|
||||
|
||||
if(lfo.enable && ++lfo.divider == lfoDividers[lfo.rate]) {
|
||||
lfo.divider = 0;
|
||||
lfo.clock++;
|
||||
for(auto& channel : channels) {
|
||||
for(auto& op : channel.operators) {
|
||||
op.updatePhase(); //due to vibrato
|
||||
op.updateLevel(); //due to tremolo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(++envelope.divider == 3) {
|
||||
envelope.divider = 0;
|
||||
if(!++envelope.clock) ++envelope.clock; // 12-bit counter: 1..4095 - zero-value is skipped (confirmed behavior)
|
||||
}
|
||||
|
||||
for(auto& channel : channels) {
|
||||
for(auto& op : channel.operators) {
|
||||
op.runPhase();
|
||||
if(envelope.divider) continue;
|
||||
op.runEnvelope();
|
||||
}
|
||||
}
|
||||
|
||||
return {sclamp<16>(left), sclamp<16>(right)};
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ protected:
|
||||
auto run() -> void;
|
||||
|
||||
n1 enable = 0;
|
||||
n1 enableLatch = 0;
|
||||
n1 irq = 0;
|
||||
n1 line = 0;
|
||||
n10 period = 0;
|
||||
@@ -56,6 +57,7 @@ protected:
|
||||
auto run() -> void;
|
||||
|
||||
n1 enable = 0;
|
||||
n1 enableLatch = 0;
|
||||
n1 irq = 0;
|
||||
n1 line = 0;
|
||||
n8 period = 0;
|
||||
@@ -106,7 +108,8 @@ protected:
|
||||
|
||||
n1 keyOn = 0;
|
||||
n1 keyLine = 0;
|
||||
n1 lfoEnable = 0;
|
||||
n1 tremoloEnable = 0;
|
||||
n5 keyScale = 0;
|
||||
n3 detune = 0;
|
||||
n4 multiple = 0;
|
||||
n7 totalLevel = 0;
|
||||
@@ -140,7 +143,7 @@ protected:
|
||||
n32 steps = 0;
|
||||
n10 value = 0x3ff;
|
||||
|
||||
n2 keyScale = 0;
|
||||
n2 rateScaling = 0;
|
||||
n5 attackRate = 0;
|
||||
n5 decayRate = 0;
|
||||
n5 sustainRate = 0;
|
||||
|
||||
@@ -15,7 +15,7 @@ auto M24C::serialize(serializer& s) -> void {
|
||||
s(output);
|
||||
s(response);
|
||||
s(writable);
|
||||
s(array_span<u8>{memory, size()});
|
||||
s(std::span<n8>{memory, size()});
|
||||
if(type >= Type::M24C32) s(idpage);
|
||||
s(locked);
|
||||
}
|
||||
@@ -9,7 +9,6 @@ namespace ares {
|
||||
io.portCHigherInput = 1;
|
||||
io.portAInput = 1;
|
||||
io.groupAMode = 0;
|
||||
io.ioMode = 0;
|
||||
state.portA = 0xff;
|
||||
state.portB = 0xff;
|
||||
state.portC = 0xff;
|
||||
@@ -43,15 +42,20 @@ namespace ares {
|
||||
}
|
||||
|
||||
auto I8255::writeControl(n8 data) -> void {
|
||||
if(data.bit(7) == 0) {
|
||||
n3 bitSelect = data.bit(1, 3);
|
||||
state.portC.bit(bitSelect) = data.bit(0);
|
||||
writePortC(state.portC);
|
||||
return;
|
||||
}
|
||||
|
||||
io.portCLowerInput = data.bit(0);
|
||||
io.portBInput = data.bit(1);
|
||||
io.groupBMode = data.bit(2);
|
||||
io.portCHigherInput = data.bit(3);
|
||||
io.portAInput = data.bit(4);
|
||||
io.groupAMode = data.bit(5,6);
|
||||
io.ioMode = data.bit(7);
|
||||
|
||||
if(!io.ioMode) debug(unimplemented, "[I8255] BSR Mode");
|
||||
if(io.groupAMode != 0) debug(unimplemented, "[I8255] Group A Mode != 0");
|
||||
if(io.groupBMode != 0) debug(unimplemented, "[I8255] Group B Mode != 0");
|
||||
}
|
||||
@@ -63,7 +67,6 @@ namespace ares {
|
||||
s(io.portCHigherInput);
|
||||
s(io.portAInput);
|
||||
s(io.groupAMode);
|
||||
s(io.ioMode);
|
||||
|
||||
s(state.portA);
|
||||
s(state.portB);
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace ares {
|
||||
n1 portCHigherInput;
|
||||
n1 portAInput;
|
||||
n2 groupAMode;
|
||||
n1 ioMode;
|
||||
} io;
|
||||
|
||||
struct State {
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace ares {
|
||||
#include "instruction.cpp"
|
||||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "coprocessor.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
@@ -19,7 +20,9 @@ ARM7TDMI::ARM7TDMI() {
|
||||
|
||||
auto ARM7TDMI::power() -> void {
|
||||
processor = {};
|
||||
processor.r15.modify = [&] { pipeline.reload = true; };
|
||||
processor.r15.modify = [&] { processor.r15.data &= ~1; pipeline.reload = true; };
|
||||
processor.rNULL.modify = [&] { processor.rNULL.data = 0; };
|
||||
processor.spsrNULL.readonly = true;
|
||||
pipeline = {};
|
||||
carry = 0;
|
||||
irq = 0;
|
||||
|
||||
@@ -6,15 +6,13 @@ namespace ares {
|
||||
|
||||
struct ARM7TDMI {
|
||||
enum : u32 {
|
||||
Nonsequential = 1 << 0, //N cycle
|
||||
Sequential = 1 << 1, //S cycle
|
||||
Load = 1 << 0, //load operation
|
||||
Store = 1 << 1, //store operation
|
||||
Prefetch = 1 << 2, //instruction fetch
|
||||
Byte = 1 << 3, // 8-bit access
|
||||
Half = 1 << 4, //16-bit access
|
||||
Word = 1 << 5, //32-bit access
|
||||
Load = 1 << 6, //load operation
|
||||
Store = 1 << 7, //store operation
|
||||
Signed = 1 << 8, //sign-extend
|
||||
Signed = 1 << 6, //sign-extend
|
||||
};
|
||||
|
||||
virtual auto step(u32 clocks) -> void = 0;
|
||||
@@ -22,6 +20,8 @@ struct ARM7TDMI {
|
||||
virtual auto get(u32 mode, n32 address) -> n32 = 0;
|
||||
virtual auto getDebugger(u32 mode, n32 address) -> n32 { return get(mode, address); }
|
||||
virtual auto set(u32 mode, n32 address, n32 word) -> void = 0;
|
||||
virtual auto lock() -> void { return; }
|
||||
virtual auto unlock() -> void { return; }
|
||||
|
||||
//arm7tdmi.cpp
|
||||
ARM7TDMI();
|
||||
@@ -42,6 +42,7 @@ struct ARM7TDMI {
|
||||
auto load(u32 mode, n32 address) -> n32;
|
||||
auto write(u32 mode, n32 address, n32 word) -> void;
|
||||
auto store(u32 mode, n32 address, n32 word) -> void;
|
||||
auto endBurst() -> void { nonsequential = true; return; }
|
||||
|
||||
//algorithms.cpp
|
||||
auto ADD(n32, n32, bool) -> n32;
|
||||
@@ -56,6 +57,7 @@ struct ARM7TDMI {
|
||||
auto TST(n4) -> bool;
|
||||
|
||||
//instruction.cpp
|
||||
auto reload() -> void;
|
||||
auto fetch() -> void;
|
||||
auto instruction() -> void;
|
||||
auto exception(u32 mode, n32 address) -> void;
|
||||
@@ -67,21 +69,25 @@ struct ARM7TDMI {
|
||||
auto armMoveToStatus(n4 field, n1 source, n32 data) -> void;
|
||||
|
||||
auto armInstructionBranch(i24, n1) -> void;
|
||||
auto armInstructionBranchExchangeRegister(n4) -> void;
|
||||
auto armInstructionBranchExchangeRegister(n4, n4, n4, n1) -> void;
|
||||
auto armInstructionCoprocessorDataProcessing(n4, n3, n4, n4, n4, n4) -> void;
|
||||
auto armInstructionDataImmediate(n8, n4, n4, n4, n1, n4) -> void;
|
||||
auto armInstructionDataImmediateShift(n4, n2, n5, n4, n4, n1, n4) -> void;
|
||||
auto armInstructionDataRegisterShift(n4, n2, n4, n4, n4, n1, n4) -> void;
|
||||
auto armInstructionLoadImmediate(n8, n1, n4, n4, n1, n1, n1) -> void;
|
||||
auto armInstructionLoadRegister(n4, n1, n4, n4, n1, n1, n1) -> void;
|
||||
auto armInstructionMemorySwap(n4, n4, n4, n1) -> void;
|
||||
auto armInstructionMoveHalfImmediate(n8, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveHalfRegister(n4, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveImmediateOffset(n12, n4, n4, n1, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveMultiple(n16, n4, n1, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveRegisterOffset(n4, n2, n5, n4, n4, n1, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveSignedImmediate(n8, n1, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveSignedRegister(n4, n1, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveToCoprocessorFromRegister(n4, n3, n4, n4, n4, n3) -> void;
|
||||
auto armInstructionMoveToRegisterFromCoprocessor(n4, n3, n4, n4, n4, n3) -> void;
|
||||
auto armInstructionMoveToRegisterFromRegister(n4, n4) -> void;
|
||||
auto armInstructionMoveToRegisterFromStatus(n4, n1) -> void;
|
||||
auto armInstructionMoveToStatusFromImmediate(n8, n4, n4, n1) -> void;
|
||||
auto armInstructionMoveToStatusFromRegister(n4, n4, n1) -> void;
|
||||
auto armInstructionMoveToStatusFromRegister(n4, n2, n5, n4, n1) -> void;
|
||||
auto armInstructionMultiply(n4, n4, n4, n4, n1, n1) -> void;
|
||||
auto armInstructionMultiplyLong(n4, n4, n4, n4, n1, n1, n1) -> void;
|
||||
auto armInstructionSoftwareInterrupt(n24 immediate) -> void;
|
||||
@@ -130,7 +136,7 @@ struct ARM7TDMI {
|
||||
}
|
||||
|
||||
n32 data;
|
||||
function<auto () -> void> modify;
|
||||
std::function<auto () -> void> modify;
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
@@ -145,21 +151,31 @@ struct ARM7TDMI {
|
||||
};
|
||||
|
||||
operator u32() const {
|
||||
return m << 0 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
|
||||
return m << 0 | 1 << 4 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
|
||||
}
|
||||
|
||||
auto operator=(n32 data) -> PSR& {
|
||||
m = data.bit(0,4);
|
||||
t = data.bit(5);
|
||||
f = data.bit(6);
|
||||
i = data.bit(7);
|
||||
v = data.bit(28);
|
||||
c = data.bit(29);
|
||||
z = data.bit(30);
|
||||
n = data.bit(31);
|
||||
set(0b1111, data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto set(n4 field, n32 data) -> void {
|
||||
if(readonly) return;
|
||||
if(field.bit(0)) {
|
||||
m = data.bit(0,4) | 0x10;
|
||||
t = data.bit(5);
|
||||
f = data.bit(6);
|
||||
i = data.bit(7);
|
||||
}
|
||||
|
||||
if(field.bit(3)) {
|
||||
v = data.bit(28);
|
||||
c = data.bit(29);
|
||||
z = data.bit(30);
|
||||
n = data.bit(31);
|
||||
}
|
||||
}
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
@@ -171,6 +187,8 @@ struct ARM7TDMI {
|
||||
b1 c; //carry
|
||||
b1 z; //zero
|
||||
b1 n; //negative
|
||||
|
||||
b1 readonly;
|
||||
};
|
||||
|
||||
struct Processor {
|
||||
@@ -179,6 +197,8 @@ struct ARM7TDMI {
|
||||
|
||||
GPR r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
PSR cpsr;
|
||||
GPR rNULL; //read-only, used when no register is mapped to r(13) or r(14)
|
||||
PSR spsrNULL; //read-only, used when no SPSR is mapped
|
||||
|
||||
struct FIQ {
|
||||
GPR r8, r9, r10, r11, r12, r13, r14;
|
||||
@@ -214,10 +234,10 @@ struct ARM7TDMI {
|
||||
n32 address;
|
||||
n32 instruction;
|
||||
b1 thumb; //not used by fetch stage
|
||||
b1 irq; //not used by fetch stage
|
||||
};
|
||||
|
||||
n1 reload = 1;
|
||||
n1 nonsequential = 1;
|
||||
Instruction fetch;
|
||||
Instruction decode;
|
||||
Instruction execute;
|
||||
@@ -226,27 +246,41 @@ struct ARM7TDMI {
|
||||
n32 opcode;
|
||||
b1 carry;
|
||||
b1 irq;
|
||||
b1 nonsequential;
|
||||
|
||||
function<void (n32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
std::function<void (n32 opcode)> armInstruction[4096];
|
||||
std::function<void ()> thumbInstruction[65536];
|
||||
|
||||
//coprocessor.cpp
|
||||
auto bindCDP(n4 id, std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void;
|
||||
auto bindMCR(n4 id, std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
auto bindMRC(n4 id, std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
|
||||
std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> CDP[16];
|
||||
std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> MCR[16];
|
||||
std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> MRC[16];
|
||||
|
||||
//disassembler.cpp
|
||||
auto armDisassembleBranch(i24, n1) -> string;
|
||||
auto armDisassembleBranchExchangeRegister(n4) -> string;
|
||||
auto armDisassembleBranchExchangeRegister(n4, n4, n4, n1) -> string;
|
||||
auto armDisassembleCoprocessorDataProcessing(n4, n3, n4, n4, n4, n4) -> string;
|
||||
auto armDisassembleDataImmediate(n8, n4, n4, n4, n1, n4) -> string;
|
||||
auto armDisassembleDataImmediateShift(n4, n2, n5, n4, n4, n1, n4) -> string;
|
||||
auto armDisassembleDataRegisterShift(n4, n2, n4, n4, n4, n1, n4) -> string;
|
||||
auto armDisassembleLoadImmediate(n8, n1, n4, n4, n1, n1, n1) -> string;
|
||||
auto armDisassembleLoadRegister(n4, n1, n4, n4, n1, n1, n1) -> string;
|
||||
auto armDisassembleMemorySwap(n4, n4, n4, n1) -> string;
|
||||
auto armDisassembleMoveHalfImmediate(n8, n4, n4, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveHalfRegister(n4, n4, n4, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveImmediateOffset(n12, n4, n4, n1, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveMultiple(n16, n4, n1, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveRegisterOffset(n4, n2, n5, n4, n4, n1, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveSignedImmediate(n8, n1, n4, n4, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveSignedRegister(n4, n1, n4, n4, n1, n1, n1, n1) -> string;
|
||||
auto armDisassembleMoveToCoprocessorFromRegister(n4, n3, n4, n4, n4, n3) -> string;
|
||||
auto armDisassembleMoveToRegisterFromCoprocessor(n4, n3, n4, n4, n4, n3) -> string;
|
||||
auto armDisassembleMoveToRegisterFromRegister(n4, n4) -> string;
|
||||
auto armDisassembleMoveToRegisterFromStatus(n4, n1) -> string;
|
||||
auto armDisassembleMoveToStatusFromImmediate(n8, n4, n4, n1) -> string;
|
||||
auto armDisassembleMoveToStatusFromRegister(n4, n4, n1) -> string;
|
||||
auto armDisassembleMoveToStatusFromRegister(n4, n2, n5, n4, n1) -> string;
|
||||
auto armDisassembleMultiply(n4, n4, n4, n4, n1, n1) -> string;
|
||||
auto armDisassembleMultiplyLong(n4, n4, n4, n4, n1, n1, n1) -> string;
|
||||
auto armDisassembleSoftwareInterrupt(n24) -> string;
|
||||
@@ -276,8 +310,8 @@ struct ARM7TDMI {
|
||||
auto thumbDisassembleStackMultiple(n8, n1, n1) -> string;
|
||||
auto thumbDisassembleUndefined() -> string;
|
||||
|
||||
function<string (n32 opcode)> armDisassemble[4096];
|
||||
function<string ()> thumbDisassemble[65536];
|
||||
std::function<string (n32 opcode)> armDisassemble[4096];
|
||||
std::function<string ()> thumbDisassemble[65536];
|
||||
|
||||
n32 _pc;
|
||||
string _c;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
auto ARM7TDMI::bindCDP(n4 id, std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void {
|
||||
CDP[id] = handler;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::bindMCR(n4 id, std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
MCR[id] = handler;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::bindMRC(n4 id, std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
MRC[id] = handler;
|
||||
}
|
||||
@@ -17,12 +17,12 @@ auto ARM7TDMI::disassembleInstruction(maybe<n32> pc, maybe<boolean> thumb) -> st
|
||||
|
||||
_pc = pc();
|
||||
if(!thumb()) {
|
||||
n32 opcode = getDebugger(Word | Nonsequential, _pc & ~3);
|
||||
n32 opcode = getDebugger(Word, _pc & ~3);
|
||||
n12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
_c = _conditions[opcode >> 28];
|
||||
return pad(armDisassemble[index](opcode), -40);
|
||||
} else {
|
||||
n16 opcode = getDebugger(Half | Nonsequential, _pc & ~1);
|
||||
n16 opcode = getDebugger(Half, _pc & ~1);
|
||||
return pad(thumbDisassemble[opcode](), -40);
|
||||
}
|
||||
}
|
||||
@@ -64,10 +64,16 @@ auto ARM7TDMI::armDisassembleBranch
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleBranchExchangeRegister
|
||||
(n4 m) -> string {
|
||||
(n4 m, n4 d, n4 field, n1 mode) -> string {
|
||||
return {"bx", _c, " ", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleCoprocessorDataProcessing
|
||||
(n4 cm, n3 op2, n4 cpid, n4 cd, n4 cn, n4 op1) -> string {
|
||||
return {"cdp", _c, " p", cpid, ", ", op1, ", cr", cd,
|
||||
", cr", cn, ", cr", cm, ", ", op2};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleDataImmediate
|
||||
(n8 immediate, n4 shift, n4 d, n4 n, n1 save, n4 mode) -> string {
|
||||
static const string opcode[] = {
|
||||
@@ -118,30 +124,6 @@ auto ARM7TDMI::armDisassembleDataRegisterShift
|
||||
" ", _r[s]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte) | Nonsequential,
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> string {
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMemorySwap
|
||||
(n4 m, n4 d, n4 n, n1 byte) -> string {
|
||||
return {"swp", _c, byte ? "b" : "", " ", _r[d], ",", _r[m], ",[", _r[n], "]"};
|
||||
@@ -150,7 +132,7 @@ auto ARM7TDMI::armDisassembleMemorySwap
|
||||
auto ARM7TDMI::armDisassembleMoveHalfImmediate
|
||||
(n8 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger(Half | Nonsequential, _pc + (up ? +immediate : -immediate)), 4L)};
|
||||
if(n == 15) data = {" =0x", hex(getDebugger(Half, _pc + (up ? +immediate : -immediate)), 4L)};
|
||||
|
||||
return {mode ? "ldr" : "str", _c, "h ",
|
||||
_r[d], ",[", _r[n],
|
||||
@@ -173,7 +155,7 @@ auto ARM7TDMI::armDisassembleMoveHalfRegister
|
||||
auto ARM7TDMI::armDisassembleMoveImmediateOffset
|
||||
(n12 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 byte, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((byte ? Byte : Word) | Nonsequential,
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((byte ? Byte : Word),
|
||||
_pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)};
|
||||
return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
@@ -212,6 +194,47 @@ auto ARM7TDMI::armDisassembleMoveRegisterOffset
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveSignedImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte),
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {mode ? "ldr" : "str", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveSignedRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
|
||||
return {mode ? "ldr" : "str", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToCoprocessorFromRegister
|
||||
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> string {
|
||||
return {"mcr", _c, " p", cpid, ", ", op1, ", ", _r[d],
|
||||
", cr", cn, ", cr", cm, ", ", op2};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromCoprocessor
|
||||
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> string {
|
||||
return {"mrc", _c, " p", cpid, ", ", op1, ", ", _r[d],
|
||||
", cr", cn, ", cr", cm, ", ", op2};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromRegister
|
||||
(n4 d, n4 n) -> string {
|
||||
return {"mov", _c, " ", _r[d], ",", _r[n]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus
|
||||
(n4 d, n1 mode) -> string {
|
||||
return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"};
|
||||
@@ -229,13 +252,18 @@ auto ARM7TDMI::armDisassembleMoveToStatusFromImmediate
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToStatusFromRegister
|
||||
(n4 m, n4 field, n1 mode) -> string {
|
||||
(n4 m, n2 type, n5 shift, n4 field, n1 mode) -> string {
|
||||
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
|
||||
field.bit(0) ? "c" : "",
|
||||
field.bit(1) ? "x" : "",
|
||||
field.bit(2) ? "s" : "",
|
||||
field.bit(3) ? "f" : "",
|
||||
",", _r[m]};
|
||||
",", _r[m],
|
||||
type == 0 && shift ? string{" lsl #", shift} : string{},
|
||||
type == 1 ? string{" lsr #", shift ? (u32)shift : 32} : string{},
|
||||
type == 2 ? string{" asr #", shift ? (u32)shift : 32} : string{},
|
||||
type == 3 && shift ? string{" ror #", shift} : string{},
|
||||
type == 3 && !shift ? " rrx" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMultiply
|
||||
@@ -276,7 +304,7 @@ auto ARM7TDMI::thumbDisassembleALU
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleALUExtended
|
||||
(n4 d, n4 m, n2 mode) -> string {
|
||||
static const string opcode[] = {"add", "sub", "mov"};
|
||||
static const string opcode[] = {"add", "cmp", "mov"};
|
||||
if(d == 8 && m == 8 && mode == 2) return {"nop"};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m]};
|
||||
}
|
||||
@@ -308,7 +336,7 @@ auto ARM7TDMI::thumbDisassembleBranchExchange
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchFarPrefix
|
||||
(i11 displacementHi) -> string {
|
||||
n11 displacementLo = getDebugger(Half | Nonsequential, (_pc & ~1) + 2);
|
||||
n11 displacementLo = getDebugger(Half, (_pc & ~1) + 2);
|
||||
i22 displacement = displacementHi << 11 | displacementLo << 0;
|
||||
n32 address = _pc + 4 + displacement * 2;
|
||||
return {"bl 0x", hex(address, 8L)};
|
||||
@@ -340,7 +368,7 @@ auto ARM7TDMI::thumbDisassembleImmediate
|
||||
auto ARM7TDMI::thumbDisassembleLoadLiteral
|
||||
(n8 displacement, n3 d) -> string {
|
||||
n32 address = ((_pc + 4) & ~3) + (displacement << 2);
|
||||
n32 data = getDebugger(Word | Nonsequential, address);
|
||||
n32 data = getDebugger(Word, address);
|
||||
return {"ldr ", _r[d], ",[pc,#0x", hex(address, 8L), "] =0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,30 @@
|
||||
auto ARM7TDMI::reload() -> void {
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
pipeline.reload = false;
|
||||
endBurst();
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::fetch() -> void {
|
||||
pipeline.execute = pipeline.decode;
|
||||
pipeline.execute.irq = pipeline.execute.irq & irq;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.decode.thumb = cpsr().t;
|
||||
pipeline.decode.irq = !cpsr().i;
|
||||
|
||||
u32 sequential = Sequential;
|
||||
if(pipeline.nonsequential) {
|
||||
pipeline.nonsequential = false;
|
||||
sequential = Nonsequential;
|
||||
}
|
||||
|
||||
u32 mask = !cpsr().t ? 3 : 1;
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
r(15).data += size >> 3;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | sequential, pipeline.fetch.address);
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::instruction() -> void {
|
||||
u32 mask = !cpsr().t ? 3 : 1;
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~mask;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
if(pipeline.reload) reload();
|
||||
fetch();
|
||||
|
||||
if(irq && !cpsr().i) {
|
||||
if(pipeline.execute.irq) {
|
||||
exception(PSR::IRQ, 0x18);
|
||||
if(pipeline.execute.thumb) r(14).data += 2;
|
||||
return;
|
||||
@@ -81,13 +75,31 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) /* m */
|
||||
{
|
||||
auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????");
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* field */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(n3 _ : range(8))
|
||||
for(n1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0??0 ???? ???? ---- 0??1 ????") | _.bit(0,1) << 5 | _.bit(2) << 21 | mode << 22;
|
||||
bind(opcode, BranchExchangeRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* cm */ \
|
||||
opcode.bit( 5, 7), /* op2 */ \
|
||||
opcode.bit( 8,11), /* cpid */ \
|
||||
opcode.bit(12,15), /* cd */ \
|
||||
opcode.bit(16,19), /* cn */ \
|
||||
opcode.bit(20,23) /* op1 */
|
||||
for(n3 op2 : range(8))
|
||||
for(n4 op1 : range(16)) {
|
||||
auto opcode = pattern(".... 1110 ???? ???? ???? ???? ???0 ????") | op2 << 5 | op1 << 20;
|
||||
bind(opcode, CoprocessorDataProcessing);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 7), /* immediate */ \
|
||||
opcode.bit( 8,11), /* shift */ \
|
||||
@@ -139,47 +151,14 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?1 ???? ???? ???? 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?1 ???? ???? ---- 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(22) /* byte */
|
||||
for(n3 _ : range(8))
|
||||
for(n1 byte : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22;
|
||||
auto opcode = pattern(".... 0001 ???? ???? ???? ---- 1001 ????") | _.bit(0,1) << 20 | byte << 22 | _.bit(2) << 23;
|
||||
bind(opcode, MemorySwap);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -283,11 +262,88 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 mode : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?? ???? ???? ???? 11?1 ????") | half << 5 | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveSignedImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 mode : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?? ???? ???? ---- 11?1 ????") | half << 5 | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveSignedRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* cm */ \
|
||||
opcode.bit( 5, 7), /* op2 */ \
|
||||
opcode.bit( 8,11), /* cpid */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* cn */ \
|
||||
opcode.bit(21,23) /* op1 */
|
||||
for(n3 op2 : range(8))
|
||||
for(n3 op1 : range(8)) {
|
||||
auto opcode = pattern(".... 1110 ???0 ???? ???? ???? ???1 ????") | op2 << 5 | op1 << 21;
|
||||
bind(opcode, MoveToCoprocessorFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* cm */ \
|
||||
opcode.bit( 5, 7), /* op2 */ \
|
||||
opcode.bit( 8,11), /* cpid */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* cn */ \
|
||||
opcode.bit(21,23) /* op1 */
|
||||
for(n3 op2 : range(8))
|
||||
for(n3 op1 : range(8)) {
|
||||
auto opcode = pattern(".... 1110 ???1 ???? ???? ???? ???1 ????") | op2 << 5 | op1 << 21;
|
||||
bind(opcode, MoveToRegisterFromCoprocessor);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19) /* n */
|
||||
for(n5 _ : range(32)) {
|
||||
//undocumented instruction, equivalent to "mov rd, rn"
|
||||
auto opcode = pattern(".... 0011 0?00 ???? ???? ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4) << 22;
|
||||
bind(opcode, MoveToRegisterFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(n3 _ : range(8))
|
||||
for(n1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22;
|
||||
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- ???0 ----") | _ << 5 | mode << 22;
|
||||
bind(opcode, MoveToRegisterFromStatus);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -306,10 +362,14 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5, 6), /* type */ \
|
||||
opcode.bit( 7,11), /* shift */ \
|
||||
opcode.bit(16,19), /* field */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(n2 type : range(4))
|
||||
for(n1 shiftLo : range(2))
|
||||
for(n1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22;
|
||||
auto opcode = pattern(".... 0001 0?10 ???? ---- ???? ???0 ????") | type << 5 | shiftLo << 7 | mode << 22;
|
||||
bind(opcode, MoveToStatusFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -322,8 +382,9 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21) /* accumulate */
|
||||
for(n1 save : range(2))
|
||||
for(n1 accumulate : range(2)) {
|
||||
auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21;
|
||||
for(n1 accumulate : range(2))
|
||||
for(n1 _ : range(2)) {
|
||||
auto opcode = pattern(".... 0000 0??? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21 | _ << 22;
|
||||
bind(opcode, Multiply);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -354,22 +415,35 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
#undef arguments
|
||||
|
||||
#define arguments
|
||||
for(n12 id : range(4096)) {
|
||||
if(armInstruction[id]) continue;
|
||||
auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | id.bit(0,3) << 4 | id.bit(4,11) << 20;
|
||||
for(n8 _ : range(256)) {
|
||||
//architecturally undefined
|
||||
auto opcode = pattern(".... 011? ???? ---- ---- ---- ???1 ----") | _.bit(0,2) << 5 | _.bit(3,7) << 20;
|
||||
bind(opcode, Undefined);
|
||||
}
|
||||
for(n8 _ : range(256)) {
|
||||
//load to coprocessor
|
||||
auto opcode = pattern(".... 110? ???1 ---- ---- ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4,7) << 21;
|
||||
bind(opcode, Undefined);
|
||||
}
|
||||
for(n8 _ : range(256)) {
|
||||
//store from coprocessor
|
||||
auto opcode = pattern(".... 110? ???0 ---- ---- ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4,7) << 21;
|
||||
bind(opcode, Undefined);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
|
||||
//check that all encodings are bound
|
||||
for(n12 index : range(4096)) assert(armInstruction[index]);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInitialize() -> void {
|
||||
#define bind(id, name, ...) { \
|
||||
assert(!thumbInstruction[id]); \
|
||||
thumbInstruction[id] = [=] { return thumbInstruction##name(__VA_ARGS__); }; \
|
||||
thumbDisassemble[id] = [=] { return thumbDisassemble##name(__VA_ARGS__); }; \
|
||||
thumbInstruction[id] = [=, this] { return thumbInstruction##name(__VA_ARGS__); }; \
|
||||
thumbDisassemble[id] = [=, this] { return thumbDisassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
@@ -419,9 +493,9 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
||||
bind(opcode, AdjustStack, immediate, mode);
|
||||
}
|
||||
|
||||
for(n3 _ : range(8))
|
||||
for(n4 _ : range(16))
|
||||
for(n4 m : range(16)) {
|
||||
auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3;
|
||||
auto opcode = pattern("0100 0111 ???? ?---") | _.bit(0,2) << 0 | m << 3 | _.bit(3) << 7;
|
||||
bind(opcode, BranchExchange, m);
|
||||
}
|
||||
|
||||
@@ -442,6 +516,7 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
||||
|
||||
for(n8 displacement : range(256))
|
||||
for(n4 condition : range(16)) {
|
||||
if(condition == 14) continue; //BAL
|
||||
if(condition == 15) continue; //BNV
|
||||
auto opcode = pattern("1101 ???? ???? ????") | displacement << 0 | condition << 8;
|
||||
bind(opcode, BranchTest, displacement, condition);
|
||||
|
||||
@@ -24,24 +24,12 @@ auto ARM7TDMI::armALU(n4 mode, n4 d, n32 rn, n32 rm) -> void {
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armMoveToStatus(n4 field, n1 mode, n32 data) -> void {
|
||||
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
|
||||
PSR& psr = mode ? spsr() : cpsr();
|
||||
|
||||
if(field.bit(0)) {
|
||||
if(mode || privileged()) {
|
||||
psr.m = data.bit(0,4);
|
||||
psr.t = data.bit(5);
|
||||
psr.f = data.bit(6);
|
||||
psr.i = data.bit(7);
|
||||
if(!mode && psr.t) r(15).data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(field.bit(3)) {
|
||||
psr.v = data.bit(28);
|
||||
psr.c = data.bit(29);
|
||||
psr.z = data.bit(30);
|
||||
psr.n = data.bit(31);
|
||||
if(mode) {
|
||||
spsr().set(field, data);
|
||||
} else {
|
||||
if(!privileged()) field.bit(0) = 0;
|
||||
cpsr().set(field, data);
|
||||
if(cpsr().t) r(15).data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,10 +42,21 @@ auto ARM7TDMI::armInstructionBranch
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionBranchExchangeRegister
|
||||
(n4 m) -> void {
|
||||
(n4 m, n4 d, n4 field, n1 mode) -> void {
|
||||
n32 address = r(m);
|
||||
cpsr().t = address.bit(0);
|
||||
r(15) = address;
|
||||
if((field & 0b1001) == 0b1001) {
|
||||
PSR& psr = mode ? spsr() : cpsr();
|
||||
psr.t = address.bit(0);
|
||||
} else {
|
||||
armMoveToStatus(field, mode, address);
|
||||
}
|
||||
r(d) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionCoprocessorDataProcessing
|
||||
(n4 cm, n3 op2, n4 cpid, n4 cd, n4 cn, n4 op1) -> void {
|
||||
if(!CDP[cpid]) return armInstructionUndefined();
|
||||
CDP[cpid](cm, op2, cd, cn, op1);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionDataImmediate
|
||||
@@ -87,82 +86,65 @@ auto ARM7TDMI::armInstructionDataImmediateShift
|
||||
|
||||
auto ARM7TDMI::armInstructionDataRegisterShift
|
||||
(n4 m, n2 type, n4 s, n4 d, n4 n, n1 save, n4 mode) -> void {
|
||||
n8 rs = r(s) + (s == 15 ? 4 : 0);
|
||||
n8 rs = r(s);
|
||||
n32 rn = r(n) + (n == 15 ? 4 : 0);
|
||||
n32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||
carry = cpsr().c;
|
||||
|
||||
idle();
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, rs < 33 ? rs : (n8)33); break;
|
||||
case 1: rm = LSR(rm, rs < 33 ? rs : (n8)33); break;
|
||||
case 2: rm = ASR(rm, rs < 32 ? rs : (n8)32); break;
|
||||
case 3: if(rs) rm = ROR(rm, rs & 31 ? u32(rs & 31) : 32); break;
|
||||
case 0: rm = LSL(rm, rs); break;
|
||||
case 1: rm = LSR(rm, rs); break;
|
||||
case 2: rm = ASR(rm, rs); break;
|
||||
case 3: rm = ROR(rm, rs); break;
|
||||
}
|
||||
|
||||
armALU(mode, d, rn, rm);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMemorySwap
|
||||
(n4 m, n4 d, n4 n, n1 byte) -> void {
|
||||
n32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
|
||||
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
|
||||
lock();
|
||||
n32 word = load((byte ? Byte : Word), r(n));
|
||||
store((byte ? Byte : Word), r(n), r(m) + (m == 15 ? 4 : 0));
|
||||
unlock();
|
||||
idle();
|
||||
r(d) = word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
(n8 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rd = r(d);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load(Half, rn);
|
||||
if(mode == 0) store(Half, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
(n4 m, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load(Half, rn);
|
||||
if(mode == 0) store(Half, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
@@ -171,46 +153,47 @@ auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load((byte ? Byte : Word), rn);
|
||||
if(mode == 0) store((byte ? Byte : Word), rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveMultiple
|
||||
(n16 list, n4 n, n1 mode, n1 writeback, n1 type, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 bitCount = list ? bit::count(list) : 16;
|
||||
n32 rnEnd;
|
||||
if(up == 1) rnEnd = r(n) + bitCount * 4; //IA,IB
|
||||
if(up == 0) rnEnd = r(n) - bitCount * 4; //DA,DB
|
||||
if(pre == 0 && up == 1) rn = rn + 0; //IA
|
||||
if(pre == 1 && up == 1) rn = rn + 4; //IB
|
||||
if(pre == 1 && up == 0) rn = rn - bitCount * 4 + 0; //DB
|
||||
if(pre == 0 && up == 0) rn = rn - bitCount * 4 + 4; //DA
|
||||
|
||||
if(writeback && mode == 1 && !list.bit(n)) {
|
||||
if(up == 1) r(n) = r(n) + bitCount * 4; //IA,IB
|
||||
if(up == 0) r(n) = r(n) - bitCount * 4; //DA,DB
|
||||
}
|
||||
|
||||
auto cpsrMode = cpsr().m;
|
||||
bool usr = false;
|
||||
if(type && mode == 1 && !list.bit(15)) usr = true;
|
||||
if(type && mode == 0) usr = true;
|
||||
if(usr) cpsr().m = PSR::USR;
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(15) + 4);
|
||||
} else {
|
||||
for(u32 m : range(16)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(m) + (m == 15 ? 4 : 0));
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
if(writeback && mode == 1 && !list.bit(n)) r(n) = rnEnd;
|
||||
|
||||
endBurst();
|
||||
if(!list) list.bit(15) = 1;
|
||||
for(u32 m : range(16)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, rn);
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m) + (!(n == 15 && writeback) && m == 15 ? 4 : 0));
|
||||
if(writeback) r(n) = rnEnd; //writeback occurs after first access
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(usr) cpsr().m = cpsrMode;
|
||||
@@ -221,19 +204,14 @@ auto ARM7TDMI::armInstructionMoveMultiple
|
||||
cpsr() = spsr();
|
||||
}
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
}
|
||||
|
||||
if(writeback && mode == 0) {
|
||||
if(up == 1) r(n) = r(n) + bitCount * 4; //IA,IB
|
||||
if(up == 0) r(n) = r(n) - bitCount * 4; //DA,DB
|
||||
endBurst();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
(n4 m, n2 type, n5 shift, n4 d, n4 n, n1 mode, n1 writeback, n1 byte, n1 up, n1 pre) -> void {
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
n32 rn = r(n);
|
||||
carry = cpsr().c;
|
||||
|
||||
@@ -245,12 +223,67 @@ auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
}
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load((byte ? Byte : Word), rn);
|
||||
if(mode == 0) store((byte ? Byte : Word), rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveSignedImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load((half ? Half : Byte) | Signed, rn);
|
||||
if(mode == 0) store((half ? Half : Byte) | Signed, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveSignedRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load((half ? Half : Byte) | Signed, rn);
|
||||
if(mode == 0) store((half ? Half : Byte) | Signed, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToCoprocessorFromRegister
|
||||
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> void {
|
||||
if(!MCR[cpid]) return armInstructionUndefined();
|
||||
MCR[cpid](r(d), cm, op2, cn, op1);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToRegisterFromCoprocessor
|
||||
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> void {
|
||||
if(!MRC[cpid]) return armInstructionUndefined();
|
||||
r(d) = MRC[cpid](cm, op2, cn, op1);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToRegisterFromRegister
|
||||
(n4 d, n4 n) -> void {
|
||||
r(d) = r(n);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToRegisterFromStatus
|
||||
@@ -266,14 +299,25 @@ auto ARM7TDMI::armInstructionMoveToStatusFromImmediate
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToStatusFromRegister
|
||||
(n4 m, n4 field, n1 mode) -> void {
|
||||
armMoveToStatus(field, mode, r(m));
|
||||
(n4 m, n2 type, n5 shift, n4 field, n1 mode) -> void {
|
||||
n32 rm = r(m);
|
||||
carry = cpsr().c;
|
||||
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, shift); break;
|
||||
case 1: rm = LSR(rm, shift ? (u32)shift : 32); break;
|
||||
case 2: rm = ASR(rm, shift ? (u32)shift : 32); break;
|
||||
case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break;
|
||||
}
|
||||
|
||||
armMoveToStatus(field, mode, rm);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiply
|
||||
(n4 m, n4 s, n4 n, n4 d, n1 save, n1 accumulate) -> void {
|
||||
if(accumulate) idle();
|
||||
r(d) = MUL(accumulate ? r(n) : 0, r(m), r(s));
|
||||
n32 product = MUL(accumulate ? r(n) : 0, r(m), r(s));
|
||||
if(d != 15) r(d) = product;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiplyLong
|
||||
@@ -300,8 +344,8 @@ auto ARM7TDMI::armInstructionMultiplyLong
|
||||
n64 rd = rm * rs;
|
||||
if(accumulate) rd += (n64)r(h) << 32 | (n64)r(l) << 0;
|
||||
|
||||
r(h) = rd >> 32;
|
||||
r(l) = rd >> 0;
|
||||
if(l != 15) r(l) = rd >> 0;
|
||||
if(h != 15) r(h) = rd >> 32;
|
||||
|
||||
if(save) {
|
||||
cpsr().z = rd == 0;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
auto ARM7TDMI::thumbInstructionALU
|
||||
(n3 d, n3 m, n4 mode) -> void {
|
||||
carry = cpsr().c;
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(r(d) & r(m)); break; //AND
|
||||
case 1: r(d) = BIT(r(d) ^ r(m)); break; //EOR
|
||||
case 2: r(d) = BIT(LSL(r(d), r(m))); break; //LSL
|
||||
case 3: r(d) = BIT(LSR(r(d), r(m))); break; //LSR
|
||||
case 4: r(d) = BIT(ASR(r(d), r(m))); break; //ASR
|
||||
case 2: r(d) = BIT(LSL(r(d), r(m))); idle(); break; //LSL
|
||||
case 3: r(d) = BIT(LSR(r(d), r(m))); idle(); break; //LSR
|
||||
case 4: r(d) = BIT(ASR(r(d), r(m))); idle(); break; //ASR
|
||||
case 5: r(d) = ADD(r(d), r(m), cpsr().c); break; //ADC
|
||||
case 6: r(d) = SUB(r(d), r(m), cpsr().c); break; //SBC
|
||||
case 7: r(d) = BIT(ROR(r(d), r(m))); break; //ROR
|
||||
case 7: r(d) = BIT(ROR(r(d), r(m))); idle(); break; //ROR
|
||||
case 8: BIT(r(d) & r(m)); break; //TST
|
||||
case 9: r(d) = SUB(0, r(m), 1); break; //NEG
|
||||
case 10: SUB(r(d), r(m), 1); break; //CMP
|
||||
@@ -24,7 +25,7 @@ auto ARM7TDMI::thumbInstructionALUExtended
|
||||
(n4 d, n4 m, n2 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = r(d) + r(m); break; //ADD
|
||||
case 1: SUB(r(d), r(m), 1); break; //SUBS
|
||||
case 1: SUB(r(d), r(m), 1); break; //CMP
|
||||
case 2: r(d) = r(m); break; //MOV
|
||||
}
|
||||
}
|
||||
@@ -92,6 +93,7 @@ auto ARM7TDMI::thumbInstructionBranchTest
|
||||
|
||||
auto ARM7TDMI::thumbInstructionImmediate
|
||||
(n8 immediate, n3 d, n2 mode) -> void {
|
||||
carry = cpsr().c;
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(immediate); break; //MOV
|
||||
case 1: SUB(r(d), immediate, 1); break; //CMP
|
||||
@@ -103,81 +105,81 @@ auto ARM7TDMI::thumbInstructionImmediate
|
||||
auto ARM7TDMI::thumbInstructionLoadLiteral
|
||||
(n8 displacement, n3 d) -> void {
|
||||
n32 address = (r(15) & ~3) + (displacement << 2);
|
||||
r(d) = load(Word | Nonsequential, address);
|
||||
r(d) = load(Word, address);
|
||||
idle();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveByteImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Byte | Nonsequential, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte | Nonsequential, r(n) + offset); break; //LDRB
|
||||
case 0: store(Byte, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte, r(n) + offset); idle(); break; //LDRB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveHalfImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Half | Nonsequential, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half | Nonsequential, r(n) + offset * 2); break; //LDRH
|
||||
case 0: store(Half, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half, r(n) + offset * 2); idle(); break; //LDRH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveMultiple
|
||||
(n8 list, n3 n, n1 mode) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 bitCount = list ? bit::count(list) : 16;
|
||||
n16 rlist = list;
|
||||
n32 bitCount = rlist ? bit::count(rlist) : 16;
|
||||
n32 rnEnd = r(n) + bitCount * 4;
|
||||
|
||||
if(mode == 1 && !list.bit(n)) r(n) = r(n) + bitCount * 4;
|
||||
if(mode == 1 && !rlist.bit(n)) r(n) = rnEnd;
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(15) + 2);
|
||||
} else {
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn); //LDMIA
|
||||
if(mode == 0) write(Word | sequential, rn, r(m)); //STMIA
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
endBurst();
|
||||
if(!rlist) rlist.bit(15) = 1;
|
||||
for(u32 m : range(16)) {
|
||||
if(!rlist.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, rn); //LDMIA
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m) + (m == 15 ? 2 : 0)); //STMIA
|
||||
r(n) = rnEnd; //writeback occurs after first access
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(mode) {
|
||||
idle();
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
r(n) = r(n) + bitCount * 4;
|
||||
endBurst();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveRegisterOffset
|
||||
(n3 d, n3 n, n3 m, n3 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
|
||||
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
|
||||
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
|
||||
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
|
||||
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
|
||||
case 0: store(Word, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Signed, r(n) + r(m)); idle(); break; //LDSB
|
||||
case 4: r(d) = load(Word, r(n) + r(m)); idle(); break; //LDR
|
||||
case 5: r(d) = load(Half, r(n) + r(m)); idle(); break; //LDRH
|
||||
case 6: r(d) = load(Byte, r(n) + r(m)); idle(); break; //LDRB
|
||||
case 7: r(d) = load(Half | Signed, r(n) + r(m)); idle(); break; //LDSH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveStack
|
||||
(n8 immediate, n3 d, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(13) + immediate * 4); break; //LDR
|
||||
case 0: store(Word, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(13) + immediate * 4); idle(); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveWordImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(n) + offset * 4); break; //LDR
|
||||
case 0: store(Word, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(n) + offset * 4); idle(); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,33 +200,28 @@ auto ARM7TDMI::thumbInstructionSoftwareInterrupt
|
||||
auto ARM7TDMI::thumbInstructionStackMultiple
|
||||
(n8 list, n1 lrpc, n1 mode) -> void {
|
||||
n32 sp = r(13);
|
||||
n32 bitCount = (list | lrpc) ? (bit::count(list) + lrpc) : 16;
|
||||
n16 rlist = list;
|
||||
if(lrpc) {
|
||||
if(mode == 1) rlist.bit(15) = 1; //POP
|
||||
if(mode == 0) rlist.bit(14) = 1; //PUSH
|
||||
}
|
||||
n32 bitCount = rlist ? bit::count(rlist) : 16;
|
||||
if(mode == 1) r(13) = r(13) + bitCount * 4; //POP
|
||||
if(mode == 0) sp = sp - bitCount * 4 + 0; //PUSH
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
if(bitCount == 16) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(15) + 2); //PUSH
|
||||
} else {
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(m)); //PUSH
|
||||
sp += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
}
|
||||
if(lrpc) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(14)); //PUSH
|
||||
endBurst();
|
||||
if(!rlist) rlist.bit(15) = 1;
|
||||
for(u32 m : range(16)) {
|
||||
if(!rlist.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(m) + (m == 15 ? 2 : 0)); //PUSH
|
||||
sp += 4;
|
||||
}
|
||||
|
||||
if(mode) {
|
||||
idle();
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
r(13) = r(13) - bitCount * 4; //PUSH
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
auto ARM7TDMI::idle() -> void {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
sleep();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::read(u32 mode, n32 address) -> n32 {
|
||||
return get(mode, address);
|
||||
n32 word = get(mode, address);
|
||||
nonsequential = false; //allows burst transfer to continue
|
||||
return word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
auto word = get(Load | mode, address);
|
||||
if(mode & Half) {
|
||||
address &= 1;
|
||||
@@ -23,17 +25,17 @@ auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
|
||||
} else {
|
||||
word = ROR(word, address.bit(0,1) << 3);
|
||||
}
|
||||
idle();
|
||||
return word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::write(u32 mode, n32 address, n32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
return set(mode, address, word);
|
||||
set(mode, address, word);
|
||||
nonsequential = false; //allows burst transfer to continue
|
||||
return;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::store(u32 mode, n32 address, n32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
if(mode & Half) { word &= 0xffff; word |= word << 16; }
|
||||
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||
return set(Store | mode, address, word);
|
||||
|
||||
@@ -14,20 +14,24 @@ inline auto ARM7TDMI::r(n4 index) -> GPR& {
|
||||
case 11: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r11 : processor.r11;
|
||||
case 12: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r12 : processor.r12;
|
||||
case 13: switch(processor.cpsr.m) {
|
||||
case PSR::USR: return processor.r13;
|
||||
case PSR::FIQ: return processor.fiq.r13;
|
||||
case PSR::IRQ: return processor.irq.r13;
|
||||
case PSR::SVC: return processor.svc.r13;
|
||||
case PSR::ABT: return processor.abt.r13;
|
||||
case PSR::UND: return processor.und.r13;
|
||||
default: return processor.r13;
|
||||
case PSR::SYS: return processor.r13;
|
||||
default: return processor.rNULL;
|
||||
}
|
||||
case 14: switch(processor.cpsr.m) {
|
||||
case PSR::USR: return processor.r14;
|
||||
case PSR::FIQ: return processor.fiq.r14;
|
||||
case PSR::IRQ: return processor.irq.r14;
|
||||
case PSR::SVC: return processor.svc.r14;
|
||||
case PSR::ABT: return processor.abt.r14;
|
||||
case PSR::UND: return processor.und.r14;
|
||||
default: return processor.r14;
|
||||
case PSR::SYS: return processor.r14;
|
||||
default: return processor.rNULL;
|
||||
}
|
||||
case 15: return processor.r15;
|
||||
}
|
||||
@@ -46,7 +50,7 @@ inline auto ARM7TDMI::spsr() -> PSR& {
|
||||
case PSR::ABT: return processor.abt.spsr;
|
||||
case PSR::UND: return processor.und.spsr;
|
||||
}
|
||||
throw;
|
||||
return processor.spsrNULL;
|
||||
}
|
||||
|
||||
inline auto ARM7TDMI::privileged() const -> bool {
|
||||
|
||||
@@ -3,6 +3,7 @@ auto ARM7TDMI::serialize(serializer& s) -> void {
|
||||
s(pipeline);
|
||||
s(carry);
|
||||
s(irq);
|
||||
s(nonsequential);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
|
||||
@@ -23,6 +24,8 @@ auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
|
||||
s(r14.data);
|
||||
s(r15.data);
|
||||
s(cpsr);
|
||||
s(rNULL.data);
|
||||
s(spsrNULL);
|
||||
s(fiq.r8.data);
|
||||
s(fiq.r9.data);
|
||||
s(fiq.r10.data);
|
||||
@@ -54,18 +57,21 @@ auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
||||
s(c);
|
||||
s(z);
|
||||
s(n);
|
||||
s(readonly);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
||||
s(reload);
|
||||
s(nonsequential);
|
||||
s(fetch.address);
|
||||
s(fetch.instruction);
|
||||
s(fetch.thumb);
|
||||
s(fetch.irq);
|
||||
s(decode.address);
|
||||
s(decode.instruction);
|
||||
s(decode.thumb);
|
||||
s(decode.irq);
|
||||
s(execute.address);
|
||||
s(execute.instruction);
|
||||
s(execute.thumb);
|
||||
s(execute.irq);
|
||||
}
|
||||
Loaded 100 of 5458 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user