mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-08 01:08:24 -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 |
No files matched your search
@@ -1,11 +1,8 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/BlankSpruce/gersemi/master/gersemi/configuration.schema.json
|
||||
|
||||
color: false
|
||||
definitions: [ares/CMakeLists.txt]
|
||||
line_length: 120
|
||||
indent: 2
|
||||
list_expansion: favour-inlining
|
||||
quiet: false
|
||||
unsafe: false
|
||||
warn_about_unknown_commands: false
|
||||
workers: 10
|
||||
@@ -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})
|
||||
|
||||
@@ -10,6 +10,7 @@ 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
|
||||
|
||||
@@ -13,7 +13,7 @@ cmake --preset $TARGET_PRESET
|
||||
pushd build
|
||||
cmake --build . --config RelWithDebInfo
|
||||
|
||||
if [ "$CROSS_COMPILE" = true ]; then
|
||||
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/
|
||||
|
||||
@@ -21,13 +21,12 @@ do
|
||||
mkdir ${outdir}-dSYMs
|
||||
cp -a ${bindir}/ares-${package}-dSYMs/*.dSYM ${outdir}-dSYMs
|
||||
cp -a ${bindir}/ares-${package}/*.app ${outdir}
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
zip -r ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
|
||||
|
||||
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-x64 windows-clang-cl-arm64
|
||||
for package in windows-x64 windows-clang-cl-arm64
|
||||
do
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
@@ -43,3 +42,8 @@ do
|
||||
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/*
|
||||
+82
-264
@@ -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,53 +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
|
||||
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: 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:
|
||||
@@ -67,250 +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: |
|
||||
sudo xcode-select -s /Applications/Xcode_16.1.0.app/Contents/Developer
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.13
|
||||
brew install 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
|
||||
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'
|
||||
folder: 'build/desktop-ui/rundir/'
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
- name: "macOS: notarize"
|
||||
if: false
|
||||
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
|
||||
- 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: false
|
||||
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-universal/ares.app/Contents/MacOS/ares
|
||||
|
||||
for package in windows windows-msvc-arm64 macos-universal
|
||||
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-universal
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-universal.zip', asset_name: 'ares-macos-universal.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/*
|
||||
@@ -1,153 +0,0 @@
|
||||
name: Build (New)
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
codesign:
|
||||
description: Enable codesigning
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
program:
|
||||
- ares
|
||||
config:
|
||||
- RelWithDebInfo
|
||||
platform:
|
||||
- name: windows-x64
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-x64-gcc
|
||||
os: windows-latest
|
||||
compiler: g++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: mingw64
|
||||
install: 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-clang-cl-arm64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-cl-cross
|
||||
native-cmake-preset: windows-ci-cl-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: macos-universal
|
||||
os: macos-15
|
||||
compiler: clang++
|
||||
shell: sh
|
||||
install: cmake ccache xcbeautify
|
||||
target-cmake-preset: macos-ci-universal
|
||||
- name: ubuntu
|
||||
os: ubuntu-latest
|
||||
compiler: g++
|
||||
shell: bash
|
||||
install: cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
|
||||
target-cmake-preset: ubuntu-ci
|
||||
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@v2
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: make git cmake ccache ninja ${{ matrix.platform.install }}
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && inputs.codesign
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
continue-on-error: ${{ !inputs.codesign }}
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install ${{ matrix.platform.install }}
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install ${{ matrix.platform.install }}
|
||||
- name: "Build: Linux"
|
||||
if: runner.os == 'Linux'
|
||||
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:
|
||||
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' && inputs.codesign
|
||||
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
|
||||
with:
|
||||
certificate: '${{ secrets.WIN_CERTIFICATE }}'
|
||||
password: '${{ secrets.WIN_PASSWORD }}'
|
||||
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
|
||||
certificatename: '${{ secrets.WIN_CERTNAME }}'
|
||||
folder: 'build/desktop-ui/rundir/'
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
- name: "Build: macOS"
|
||||
if: runner.os == 'macOS'
|
||||
run: .github/scripts/build_macos.sh
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
|
||||
- name: Upload Build (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: build/desktop-ui/rundir/*
|
||||
- name: Upload Build (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: build/desktop-ui/RelWithDebInfo/
|
||||
- name: Upload Debug Symbols (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
|
||||
path: build/PDBs/*
|
||||
- name: Upload Debug Symbols (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
|
||||
path: build/dSYMs/*
|
||||
@@ -11,7 +11,13 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
build-project:
|
||||
name: Build
|
||||
uses: ./.github/workflows/build_new.yml
|
||||
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
|
||||
@@ -1,8 +1,6 @@
|
||||
name: Push
|
||||
on:
|
||||
push:
|
||||
branches: [ '*' ]
|
||||
tags: [ 'v*' ]
|
||||
push
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
@@ -10,11 +8,16 @@ permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
name: Build ares
|
||||
uses: ./.github/workflows/build_new.yml
|
||||
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
|
||||
|
||||
@@ -12,13 +12,22 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
path: 'src'
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
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: |
|
||||
@@ -48,21 +57,26 @@ jobs:
|
||||
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:
|
||||
draft: ${{ github.ref != 'refs/heads/master' }}
|
||||
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-x64.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-x64-PDBs.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-arm64.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-arm64-PDBs.zip
|
||||
+12
-4
@@ -26,10 +26,10 @@
|
||||
!CMakeLists.txt
|
||||
!CMakePresets.json
|
||||
|
||||
thirdparty/SDL/SDL
|
||||
thirdparty/SDL/libSDL2-2.0.0.dylib
|
||||
desktop-ui/out
|
||||
desktop-ui/obj
|
||||
# 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
|
||||
@@ -38,5 +38,13 @@ 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
|
||||
+7
-6
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.28...3.30)
|
||||
cmake_minimum_required(VERSION 3.28...4.1)
|
||||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE)
|
||||
|
||||
@@ -8,11 +8,9 @@ include(compilerconfig)
|
||||
include(defaults)
|
||||
include(helpers)
|
||||
|
||||
add_subdirectory(cmake)
|
||||
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
add_subdirectory(nall)
|
||||
add_subdirectory(nall/nall)
|
||||
add_subdirectory(libco)
|
||||
add_subdirectory(ruby)
|
||||
add_subdirectory(hiro)
|
||||
@@ -21,7 +19,7 @@ add_subdirectory(hiro)
|
||||
set(
|
||||
ARES_CORES
|
||||
a26 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
|
||||
CACHE STRING LIST
|
||||
CACHE STRING "List of systems to be built by the project"
|
||||
)
|
||||
# gersemi: on
|
||||
|
||||
@@ -35,7 +33,7 @@ if(ARES_BUILD_OPTIONAL_TARGETS)
|
||||
add_subdirectory(tests/arm7tdmi)
|
||||
add_subdirectory(tests/i8080)
|
||||
add_subdirectory(tests/m68000)
|
||||
if(NOT OS_WINDOWS AND NOT OS_MACOS)
|
||||
if(HIRO_BACKEND STREQUAL "GTK3")
|
||||
add_subdirectory(tools/genius)
|
||||
else()
|
||||
target_disable_subproject(genius "genius (database editor)")
|
||||
@@ -52,4 +50,7 @@ endif()
|
||||
add_subdirectory(tools/sourcery)
|
||||
|
||||
message_configuration()
|
||||
|
||||
add_subdirectory(.github)
|
||||
add_subdirectory(cmake)
|
||||
return()
|
||||
+27
-3
@@ -12,7 +12,8 @@
|
||||
"cacheVariables": {
|
||||
"ARES_PROFILE_ACCURACY": false,
|
||||
"ARES_BUILD_LOCAL": true,
|
||||
"ENABLE_CCACHE": true
|
||||
"ENABLE_CCACHE": true,
|
||||
"ARES_BUILD_OFFICIAL": {"type": "BOOL", "value": "$penv{ARES_BUILD_OFFICIAL}"}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -81,7 +82,7 @@
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_OSX_ARCHITECTURES": {"type": "STRING", "value": "x86_64;arm64"},
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "10.13"},
|
||||
"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,
|
||||
@@ -101,7 +102,9 @@
|
||||
"ARES_BUILD_LOCAL": false,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true,
|
||||
"ARES_UNITY_CORES": true,
|
||||
"ARES_PRECOMPILE_HEADERS": true
|
||||
"ARES_PRECOMPILE_HEADERS": true,
|
||||
"CMAKE_MSVC_RUNTIME_LIBRARY": {"type": "STRING", "value": "MultiThreaded"},
|
||||
"CMAKE_IGNORE_PATH": {"type": "STRING", "value": "C:/Strawberry/c/bin/"}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -158,10 +161,31 @@
|
||||
"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": [
|
||||
|
||||
@@ -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-2024 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.
|
||||
----------------------------------------------------------------------
|
||||
@@ -5,6 +5,8 @@
|
||||
**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,21 +16,19 @@ 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.
|
||||
|
||||
Building ares
|
||||
-------------
|
||||
|
||||
Build instructions are available on the ares wiki. See build instructions for:
|
||||
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)
|
||||
|
||||
For legacy Makefile build instructions, see [here](https://github.com/ares-emulator/ares/wiki/Legacy-Build-Instructions).
|
||||
|
||||
Command-line options
|
||||
--------------------
|
||||
|
||||
@@ -40,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)
|
||||
|
||||
+11
-2
@@ -1,5 +1,7 @@
|
||||
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)
|
||||
@@ -19,7 +21,7 @@ if(ARES_PRECOMPILE_HEADERS)
|
||||
target_precompile_headers(ares PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:ares/ares.hpp>")
|
||||
endif()
|
||||
|
||||
target_link_libraries(ares PUBLIC libco sljit nall)
|
||||
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)
|
||||
@@ -29,7 +31,7 @@ endif()
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE ares/ares.cpp ares/ares.hpp ares/inline.hpp ares/platform.hpp ares/random.hpp ares/types.hpp
|
||||
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(
|
||||
@@ -291,6 +293,13 @@ set_source_files_properties(
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
+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 = {};
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
namespace ares {
|
||||
|
||||
Platform* platform = nullptr;
|
||||
bool _runAhead = false;
|
||||
atomic<bool> _runAhead = false;
|
||||
|
||||
const string Name = "ares";
|
||||
const string Version = "142";
|
||||
const string Copyright = "ares team, Near";
|
||||
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-emu.net";
|
||||
const string WebsiteURI = "https://ares-emu.net/";
|
||||
const string Website = "@ARES_WEBSITE@";
|
||||
const string WebsiteURI = "https://@ARES_WEBSITE@/";
|
||||
const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
|
||||
|
||||
}
|
||||
+21
-6
@@ -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>
|
||||
@@ -22,14 +26,13 @@
|
||||
#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>
|
||||
@@ -51,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 {
|
||||
@@ -66,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>
|
||||
|
||||
+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;
|
||||
|
||||
@@ -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;
|
||||
@@ -88,13 +91,15 @@ protected:
|
||||
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;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
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)
|
||||
@@ -134,6 +138,7 @@ component_sources(
|
||||
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
|
||||
@@ -432,6 +437,16 @@ component_sources(
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -125,7 +125,7 @@ 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;
|
||||
@@ -147,7 +147,7 @@ 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;
|
||||
|
||||
@@ -36,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);
|
||||
@@ -125,10 +121,10 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
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,7 @@ 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,7 @@ protected:
|
||||
|
||||
n1 keyOn = 0;
|
||||
n1 keyLine = 0;
|
||||
n1 lfoEnable = 0;
|
||||
n1 tremoloEnable = 0;
|
||||
n5 keyScale = 0;
|
||||
n3 detune = 0;
|
||||
n4 multiple = 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;
|
||||
@@ -44,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;
|
||||
@@ -70,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;
|
||||
@@ -133,7 +136,7 @@ struct ARM7TDMI {
|
||||
}
|
||||
|
||||
n32 data;
|
||||
function<auto () -> void> modify;
|
||||
std::function<auto () -> void> modify;
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
@@ -148,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;
|
||||
|
||||
@@ -174,6 +187,8 @@ struct ARM7TDMI {
|
||||
b1 c; //carry
|
||||
b1 z; //zero
|
||||
b1 n; //negative
|
||||
|
||||
b1 readonly;
|
||||
};
|
||||
|
||||
struct Processor {
|
||||
@@ -182,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;
|
||||
@@ -221,7 +238,6 @@ struct ARM7TDMI {
|
||||
};
|
||||
|
||||
n1 reload = 1;
|
||||
n1 nonsequential = 1;
|
||||
Instruction fetch;
|
||||
Instruction decode;
|
||||
Instruction execute;
|
||||
@@ -230,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;
|
||||
@@ -280,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,11 +1,9 @@
|
||||
auto ARM7TDMI::reload() -> void {
|
||||
u32 mask = !cpsr().t ? 3 : 1;
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~mask;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
|
||||
endBurst();
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
|
||||
@@ -16,18 +14,10 @@ auto ARM7TDMI::fetch() -> void {
|
||||
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 {
|
||||
@@ -85,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 */ \
|
||||
@@ -143,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
|
||||
@@ -287,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
|
||||
@@ -310,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
|
||||
@@ -326,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
|
||||
@@ -358,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) \
|
||||
@@ -423,9 +493,9 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
||||
bind(opcode, AdjustStack, immediate, mode);
|
||||
}
|
||||
|
||||
for(n4 d : range(16))
|
||||
for(n4 _ : range(16))
|
||||
for(n4 m : range(16)) {
|
||||
auto opcode = pattern("0100 0111 ???? ?---") | d.bit(0,2) << 0 | m << 3 | d.bit(3) << 7;
|
||||
auto opcode = pattern("0100 0111 ???? ?---") | _.bit(0,2) << 0 | m << 3 | _.bit(3) << 7;
|
||||
bind(opcode, BranchExchange, m);
|
||||
}
|
||||
|
||||
@@ -446,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,84 +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 {
|
||||
lock();
|
||||
n32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
|
||||
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
|
||||
r(d) = word;
|
||||
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
|
||||
@@ -173,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;
|
||||
@@ -223,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;
|
||||
|
||||
@@ -247,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
|
||||
@@ -268,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
|
||||
@@ -302,8 +344,8 @@ auto ARM7TDMI::armInstructionMultiplyLong
|
||||
n64 rd = rm * rs;
|
||||
if(accumulate) rd += (n64)r(h) << 32 | (n64)r(l) << 0;
|
||||
|
||||
r(l) = rd >> 0;
|
||||
r(h) = rd >> 32;
|
||||
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,11 +57,11 @@ 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);
|
||||
|
||||
@@ -180,8 +180,8 @@ protected:
|
||||
} io;
|
||||
|
||||
n23 stack[8];
|
||||
function<void ()> instructionTable[65536];
|
||||
function<string ()> disassembleTable[65536];
|
||||
std::function<void ()> instructionTable[65536];
|
||||
std::function<string ()> disassembleTable[65536];
|
||||
|
||||
auto disassembleADD(n7 reg, n5 shift) -> string;
|
||||
auto disassembleADD(n8 imm, n5 shift) -> string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
HG51B::HG51B() {
|
||||
#define bind(id, name, ...) { \
|
||||
if(instructionTable[id]) throw; \
|
||||
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
||||
instructionTable[id] = [=, this] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=, this] { return disassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
|
||||
@@ -163,7 +163,7 @@ auto HuC6280::disassembleInstruction() -> string {
|
||||
|
||||
n8 opcode = readByte();
|
||||
|
||||
#define op(id, name, ...) case id: o = {name, " ", vector<string>{__VA_ARGS__}.merge(",")}; break;
|
||||
#define op(id, name, ...) case id: o = {name, " ", nall::merge({__VA_ARGS__}, ",")}; break;
|
||||
string o;
|
||||
|
||||
#define U
|
||||
|
||||
@@ -41,7 +41,7 @@ auto I8080::disassembleContext() -> string {
|
||||
return s;
|
||||
}
|
||||
|
||||
#define op(id, name, ...) case id: return {name, " ", vector<string>{__VA_ARGS__}.merge(",")};
|
||||
#define op(id, name, ...) case id: return {name, " ", nall::merge({__VA_ARGS__}, ",")};
|
||||
|
||||
#define N string{"$", hex(byte(), 2L)}
|
||||
#define IN string{"(", N, ")"}
|
||||
|
||||
@@ -10,13 +10,13 @@ auto M68000::instruction() -> void {
|
||||
M68000::M68000() {
|
||||
#define bind(id, name, ...) { \
|
||||
assert(!instructionTable[id]); \
|
||||
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
||||
instructionTable[id] = [=, this] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=, this] { return disassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define unbind(id) { \
|
||||
instructionTable[id].reset(); \
|
||||
disassembleTable[id].reset(); \
|
||||
instructionTable[id] = {}; \
|
||||
disassembleTable[id] = {}; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
|
||||
@@ -752,7 +752,12 @@ template<u32 Size> auto M68000::instructionMOVEM_TO_MEM(EffectiveAddress to) ->
|
||||
|
||||
if(to.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes<Size>();
|
||||
auto data = index < 8 ? read<Size>(DataRegister{index}) : read<Size>(AddressRegister{index});
|
||||
write<Size>(addr, data);
|
||||
if(to.mode == AddressRegisterIndirectWithPreDecrement) {
|
||||
//pre-decrement mode writes longwords in reverse-word order (low word before high)
|
||||
write<Size, Reverse>(addr, data);
|
||||
} else {
|
||||
write<Size>(addr, data);
|
||||
}
|
||||
if(to.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes<Size>();
|
||||
}
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ struct M68000 {
|
||||
bool reset;
|
||||
} r;
|
||||
|
||||
function<void ()> instructionTable[65536];
|
||||
std::function<void ()> instructionTable[65536];
|
||||
|
||||
private:
|
||||
//disassembler.cpp
|
||||
@@ -434,7 +434,7 @@ private:
|
||||
auto _condition(n4 condition) -> string;
|
||||
|
||||
n32 _pc;
|
||||
function<string ()> disassembleTable[65536];
|
||||
std::function<string ()> disassembleTable[65536];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,8 +6,8 @@ auto MOS6502::addressAbsolute() -> n16 {
|
||||
|
||||
auto MOS6502::addressAbsoluteJMP() -> n16 {
|
||||
n16 absolute = operand();
|
||||
// JMP Indirect last_cycle
|
||||
L absolute |= operand() << 8;
|
||||
// JMP Indirect last cycle
|
||||
L absolute |= operand() << 8;
|
||||
return absolute;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,6 @@ auto MOS6502::addressAbsoluteYWrite() -> n16 {
|
||||
return absolute + Y;
|
||||
}
|
||||
|
||||
auto MOS6502::addressAccumulator() -> n16 {
|
||||
return PC;
|
||||
}
|
||||
|
||||
auto MOS6502::addressImmediate() -> n16 {
|
||||
return PC++;
|
||||
}
|
||||
@@ -56,8 +52,8 @@ auto MOS6502::addressIndirect() -> n16 {
|
||||
absolute |= operand() << 8;
|
||||
n16 indirect = read(absolute);
|
||||
absolute.byte(0)++;
|
||||
// JMP Indirect last_cycle
|
||||
L indirect |= read(absolute) << 8;
|
||||
// JMP Indirect last cycle
|
||||
L indirect |= read(absolute) << 8;
|
||||
return indirect;
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 5256 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user