mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-10 09:21:41 -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 |
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})
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -26,7 +26,7 @@ do
|
||||
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}"
|
||||
@@ -42,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/*
|
||||
+19
-43
@@ -1,4 +1,4 @@
|
||||
name: Build
|
||||
name: Build (Primary)
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
@@ -7,6 +7,11 @@ on:
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
official:
|
||||
description: Use official version strings
|
||||
required: true
|
||||
default: true
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -22,49 +27,20 @@ jobs:
|
||||
compiler: clang++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang
|
||||
install: make git cmake ccache ninja 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:
|
||||
@@ -73,19 +49,19 @@ 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 git cmake ccache ninja ${{ matrix.platform.install }}
|
||||
install: ${{ matrix.platform.install }}
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && inputs.codesign
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
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@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
@@ -101,21 +77,20 @@ jobs:
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew uninstall --ignore-dependencies cmake
|
||||
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:
|
||||
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' && inputs.codesign
|
||||
continue-on-error: true
|
||||
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
|
||||
with:
|
||||
certificate: '${{ secrets.WIN_CERTIFICATE }}'
|
||||
@@ -128,6 +103,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
run: .github/scripts/build_macos.sh
|
||||
env:
|
||||
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 }}
|
||||
@@ -140,19 +116,19 @@ jobs:
|
||||
run: |
|
||||
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/rundir/ .
|
||||
- name: Upload Build
|
||||
uses: actions/upload-artifact@v4
|
||||
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@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
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
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
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
|
||||
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
|
||||
@@ -8,11 +8,16 @@ permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
name: Build ares
|
||||
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,17 +12,17 @@ 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-x64 windows-clang-cl-arm64; do
|
||||
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
|
||||
@@ -73,11 +73,10 @@ jobs:
|
||||
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
|
||||
@@ -26,6 +26,10 @@
|
||||
!CMakeLists.txt
|
||||
!CMakePresets.json
|
||||
|
||||
# Exclude old macOS Finder metadata
|
||||
.DS_Store
|
||||
|
||||
# Exclude generated sources that still reside in-tree
|
||||
ruby/video/metal/shaders.metallib
|
||||
ruby/video/metal/shaders.ir
|
||||
ares/ares/resource/resource.cpp
|
||||
@@ -36,7 +40,11 @@ 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
|
||||
+6
-5
@@ -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,8 +8,6 @@ include(compilerconfig)
|
||||
include(defaults)
|
||||
include(helpers)
|
||||
|
||||
add_subdirectory(cmake)
|
||||
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
add_subdirectory(nall/nall)
|
||||
@@ -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.15"},
|
||||
"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": [
|
||||
|
||||
@@ -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.
|
||||
----------------------------------------------------------------------
|
||||
+8
-1
@@ -21,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)
|
||||
@@ -293,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
|
||||
)
|
||||
|
||||
|
||||
+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,7 +7,7 @@
|
||||
namespace ares {
|
||||
|
||||
Platform* platform = nullptr;
|
||||
bool _runAhead = false;
|
||||
atomic<bool> _runAhead = false;
|
||||
|
||||
const string Name = "@ARES_NAME@";
|
||||
const string Version = "@ARES_VERSION@";
|
||||
|
||||
+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,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -69,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;
|
||||
@@ -132,7 +136,7 @@ struct ARM7TDMI {
|
||||
}
|
||||
|
||||
n32 data;
|
||||
function<auto () -> void> modify;
|
||||
std::function<auto () -> void> modify;
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
@@ -147,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;
|
||||
|
||||
@@ -173,6 +187,8 @@ struct ARM7TDMI {
|
||||
b1 c; //carry
|
||||
b1 z; //zero
|
||||
b1 n; //negative
|
||||
|
||||
b1 readonly;
|
||||
};
|
||||
|
||||
struct Processor {
|
||||
@@ -181,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;
|
||||
@@ -230,26 +248,39 @@ struct ARM7TDMI {
|
||||
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;
|
||||
@@ -279,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;
|
||||
}
|
||||
@@ -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),
|
||||
_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], "]"};
|
||||
@@ -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
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
auto ARM7TDMI::reload() -> void {
|
||||
u32 mask = !cpsr().t ? 3 : 1;
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
pipeline.reload = false;
|
||||
endBurst();
|
||||
r(15).data &= ~mask;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
@@ -17,11 +14,9 @@ auto ARM7TDMI::fetch() -> void {
|
||||
pipeline.decode.thumb = cpsr().t;
|
||||
pipeline.decode.irq = !cpsr().i;
|
||||
|
||||
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.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
}
|
||||
|
||||
@@ -80,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 */ \
|
||||
@@ -138,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
|
||||
@@ -282,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
|
||||
@@ -305,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
|
||||
@@ -321,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
|
||||
@@ -353,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) \
|
||||
@@ -418,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);
|
||||
}
|
||||
|
||||
@@ -441,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) | 0x10;
|
||||
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
|
||||
@@ -94,50 +93,23 @@ auto ARM7TDMI::armInstructionDataRegisterShift
|
||||
|
||||
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) | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
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) | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMemorySwap
|
||||
(n4 m, n4 d, n4 n, n1 byte) -> void {
|
||||
n32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||
lock();
|
||||
n32 word = load((byte ? Byte : Word), r(n));
|
||||
store((byte ? Byte : Word), r(n), rm);
|
||||
r(d) = word;
|
||||
store((byte ? Byte : Word), r(n), r(m) + (m == 15 ? 4 : 0));
|
||||
unlock();
|
||||
idle();
|
||||
r(d) = word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
@@ -151,7 +123,10 @@ auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
@@ -166,7 +141,10 @@ auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
@@ -180,7 +158,10 @@ auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
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
|
||||
@@ -204,28 +185,15 @@ auto ARM7TDMI::armInstructionMoveMultiple
|
||||
if(writeback && mode == 1 && !list.bit(n)) r(n) = rnEnd;
|
||||
|
||||
endBurst();
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word, rn);
|
||||
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(15) + 4);
|
||||
//writeback occurs after first access
|
||||
if(writeback) r(n) = rnEnd;
|
||||
}
|
||||
} else {
|
||||
bool wroteBack = false;
|
||||
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(!wroteBack && writeback) {
|
||||
//writeback occurs after first access
|
||||
r(n) = rnEnd;
|
||||
wroteBack = true;
|
||||
}
|
||||
}
|
||||
rn += 4;
|
||||
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;
|
||||
@@ -260,7 +228,62 @@ auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
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
|
||||
@@ -276,8 +299,18 @@ 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
|
||||
|
||||
@@ -106,13 +106,14 @@ auto ARM7TDMI::thumbInstructionLoadLiteral
|
||||
(n8 displacement, n3 d) -> void {
|
||||
n32 address = (r(15) & ~3) + (displacement << 2);
|
||||
r(d) = load(Word, address);
|
||||
idle();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveByteImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Byte, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte, r(n) + offset); break; //LDRB
|
||||
case 1: r(d) = load(Byte, r(n) + offset); idle(); break; //LDRB
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,41 +121,29 @@ auto ARM7TDMI::thumbInstructionMoveHalfImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Half, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half, r(n) + offset * 2); break; //LDRH
|
||||
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) = rnEnd;
|
||||
if(mode == 1 && !rlist.bit(n)) r(n) = rnEnd;
|
||||
|
||||
endBurst();
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word, rn);
|
||||
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(15) + 2);
|
||||
//writeback occurs after first access
|
||||
r(n) = rnEnd;
|
||||
}
|
||||
} else {
|
||||
bool wroteBack = false;
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, rn); //LDMIA
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m)); //STMIA
|
||||
//writeback occurs after first access
|
||||
if(!wroteBack) {
|
||||
r(n) = rnEnd;
|
||||
wroteBack = true;
|
||||
}
|
||||
}
|
||||
rn += 4;
|
||||
write(Word, rn, r(m) + (m == 15 ? 2 : 0)); //STMIA
|
||||
r(n) = rnEnd; //writeback occurs after first access
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(mode) {
|
||||
@@ -170,11 +159,11 @@ auto ARM7TDMI::thumbInstructionMoveRegisterOffset
|
||||
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)); break; //LDSB
|
||||
case 4: r(d) = load(Word, r(n) + r(m)); break; //LDR
|
||||
case 5: r(d) = load(Half, r(n) + r(m)); break; //LDRH
|
||||
case 6: r(d) = load(Byte, r(n) + r(m)); break; //LDRB
|
||||
case 7: r(d) = load(Half | Signed, r(n) + r(m)); break; //LDSH
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +171,7 @@ auto ARM7TDMI::thumbInstructionMoveStack
|
||||
(n8 immediate, n3 d, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(13) + immediate * 4); break; //LDR
|
||||
case 1: r(d) = load(Word, r(13) + immediate * 4); idle(); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +179,7 @@ auto ARM7TDMI::thumbInstructionMoveWordImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(n) + offset * 4); break; //LDR
|
||||
case 1: r(d) = load(Word, r(n) + offset * 4); idle(); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,25 +200,21 @@ 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
|
||||
|
||||
endBurst();
|
||||
if(bitCount == 16) {
|
||||
if(mode == 1) r(15) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(15) + 2); //PUSH
|
||||
} else {
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(m)); //PUSH
|
||||
sp += 4;
|
||||
}
|
||||
}
|
||||
if(lrpc) {
|
||||
if(mode == 1) r(15) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(14)); //PUSH
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
|
||||
} else {
|
||||
word = ROR(word, address.bit(0,1) << 3);
|
||||
}
|
||||
idle();
|
||||
return 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 {
|
||||
|
||||
@@ -24,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);
|
||||
@@ -55,6 +57,7 @@ auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
||||
s(c);
|
||||
s(z);
|
||||
s(n);
|
||||
s(readonly);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,10 +210,12 @@ auto MOS6502::algorithmJMP() -> void {
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmJSR() -> void {
|
||||
PC--;
|
||||
n16 target = operand();
|
||||
MDR = read(0x0100 | S); // dummy stack read
|
||||
push(PCH);
|
||||
L push(PCL);
|
||||
PC = MAR;
|
||||
push(PCL);
|
||||
L target |= operand() << 8;
|
||||
PC = target;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmLDA() -> void {
|
||||
@@ -257,8 +259,8 @@ auto MOS6502::algorithmORA() -> void {
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmPHA() -> void {
|
||||
read(MAR); // dummy implied read
|
||||
L push(A);
|
||||
read(MAR); // dummy implied read
|
||||
L push(A);
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmPHP() -> void {
|
||||
|
||||
@@ -24,7 +24,7 @@ auto MOS6502::reset() -> void {
|
||||
read(0x0100 | S--); // Dummy push (P)
|
||||
I = 1;
|
||||
PCL = read(vector++);
|
||||
L PCH = read(vector++);
|
||||
L PCH = read(vector++);
|
||||
resetting = 0;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x07, Modify, addr(ZeroPage), fp(SLO))
|
||||
op(0x08, None, addr(Implied), fp(PHP))
|
||||
op(0x09, Load, addr(Immediate), fp(ORA))
|
||||
op(0x0a, Load, addr(Accumulator), fp(ASLA))
|
||||
op(0x0a, Load, addr(Implied), fp(ASLA))
|
||||
op(0x0b, Load, addr(Immediate), fp(AAC))
|
||||
op(0x0c, Load, addr(Absolute), fp(NOP))
|
||||
op(0x0d, Load, addr(Absolute), fp(ORA))
|
||||
@@ -64,7 +64,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x1d, Load, addr(AbsoluteXRead), fp(ORA))
|
||||
op(0x1e, Modify, addr(AbsoluteXWrite), fp(ASLM))
|
||||
op(0x1f, Modify, addr(AbsoluteXWrite), fp(SLO))
|
||||
op(0x20, Load, addr(Absolute), fp(JSR))
|
||||
op(0x20, None, addr(Implied), fp(JSR))
|
||||
op(0x21, Load, addr(IndirectX), fp(AND))
|
||||
op(0x22, None, addr(Implied), fp(JAM))
|
||||
op(0x23, Modify, addr(IndirectX), fp(RLA))
|
||||
|
||||
@@ -40,7 +40,6 @@ struct MOS6502 {
|
||||
auto addressAbsoluteXWrite() -> n16;
|
||||
auto addressAbsoluteYRead() -> n16;
|
||||
auto addressAbsoluteYWrite() -> n16;
|
||||
auto addressAccumulator() -> n16;
|
||||
auto addressImmediate() -> n16;
|
||||
auto addressImplied() -> n16;
|
||||
auto addressIndirect() -> n16;
|
||||
|
||||
@@ -6,7 +6,7 @@ auto SH2::hint(P&&... p) const -> string {
|
||||
}
|
||||
|
||||
auto SH2::disassembleInstruction(u16 opcode) -> string {
|
||||
vector<string> s;
|
||||
std::vector<string> s;
|
||||
|
||||
auto registerName = [&](u32 r) -> string {
|
||||
return {"r", r};
|
||||
@@ -512,10 +512,10 @@ auto SH2::disassembleInstruction(u16 opcode) -> string {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!s) s = {"illegal", {"0x", hex(opcode, 4L)}};
|
||||
auto name = s.takeFirst();
|
||||
if(s.empty()) s = {"illegal", {"0x", hex(opcode, 4L)}};
|
||||
auto name = s.front(); s.erase(s.begin());
|
||||
while(name.size() < 8) name.append(" ");
|
||||
string r = {name, s.merge(",")};
|
||||
string r = {name, nall::merge(s, ",")};
|
||||
while(r.size() < 30) r.append(" ");
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -513,19 +513,19 @@ auto SH2::MOVI(u32 i, u32 n) -> void {
|
||||
}
|
||||
|
||||
//MOV.W @(disp,PC),Rn
|
||||
NALL_NOINLINE auto SH2::MOVWI(u32 d, u32 n) -> void {
|
||||
auto SH2::MOVWI(u32 d, u32 n) -> void {
|
||||
u32 pc = inDelaySlot() ? PPC - 2 : PC;
|
||||
R[n] = (s16)readWord(pc + d * 2);
|
||||
}
|
||||
|
||||
//MOV.L @(disp,PC),Rn
|
||||
NALL_NOINLINE auto SH2::MOVLI(u32 d, u32 n) -> void {
|
||||
auto SH2::MOVLI(u32 d, u32 n) -> void {
|
||||
u32 pc = inDelaySlot() ? PPC - 2 : PC;
|
||||
R[n] = readLong((pc & ~3) + d * 4);
|
||||
}
|
||||
|
||||
//MOVA @(disp,PC),R0
|
||||
NALL_NOINLINE auto SH2::MOVA(u32 d) -> void {
|
||||
auto SH2::MOVA(u32 d) -> void {
|
||||
u32 pc = inDelaySlot() ? PPC - 2 : PC;
|
||||
R[0] = (pc & ~3) + d * 4;
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BRA disp
|
||||
case range16(0xa0, 0xaf): {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(PPC, PC, imm(4 + (i12)d12 * 2));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
});
|
||||
@@ -714,7 +714,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BSR disp
|
||||
case range16(0xb0, 0xbf): {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(reg(0), PC);
|
||||
mov32(PR, reg(0));
|
||||
add32(reg(0), reg(0), imm(4 + (i12)d12 * 2));
|
||||
@@ -807,7 +807,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BT disp
|
||||
case 0x89: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_eq);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Take));
|
||||
@@ -818,7 +818,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BF disp
|
||||
case 0x8b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_ne);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Take));
|
||||
@@ -829,7 +829,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BT/S disp
|
||||
case 0x8d: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_eq);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
@@ -840,7 +840,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BF/S disp
|
||||
case 0x8f: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_ne);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
@@ -875,7 +875,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//TRAPA #imm
|
||||
case 0xc3: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
getSR(reg(2));
|
||||
sub32(reg(1), R15, imm(4));
|
||||
mov32(R15, reg(1));
|
||||
@@ -1022,7 +1022,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BSRF Rm
|
||||
case 0x003: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(reg(0), PC);
|
||||
mov32(PR, reg(0));
|
||||
add32(reg(0), reg(0), Rm);
|
||||
@@ -1059,7 +1059,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BRAF Rm
|
||||
case 0x023: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(reg(0), PC, Rm);
|
||||
add32(reg(0), reg(0), imm(4));
|
||||
mov32(PPC, reg(0));
|
||||
@@ -1168,7 +1168,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//JSR @Rm
|
||||
case 0x40b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(PR, PC);
|
||||
add32(PPC, Rm, imm(4));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
@@ -1370,7 +1370,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//JMP @Rm
|
||||
case 0x42b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(PPC, Rm, imm(4));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
});
|
||||
@@ -1405,7 +1405,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//RTS
|
||||
case 0x000b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(PPC, PR, imm(4));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
});
|
||||
@@ -1447,7 +1447,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//RTE
|
||||
case 0x002b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(reg(1), R15);
|
||||
add32(R15, reg(1), imm(4));
|
||||
call(readL);
|
||||
|
||||
@@ -283,8 +283,8 @@ struct SH2 {
|
||||
auto reset() -> void {
|
||||
generation = 0;
|
||||
blocks.reset();
|
||||
pools.reallocate(1 << 24);
|
||||
pools.fill();
|
||||
pools.resize(1 << 24);
|
||||
std::ranges::fill(pools, nullptr);
|
||||
}
|
||||
|
||||
auto invalidateCached() -> void {
|
||||
@@ -312,7 +312,7 @@ struct SH2 {
|
||||
bump_allocator allocator;
|
||||
hashset<BlockHashPair> blocks;
|
||||
u16 instructions[1 << 7];
|
||||
vector<Pool*> pools;
|
||||
std::vector<Pool*> pools;
|
||||
} recompiler{*this};
|
||||
|
||||
#include "sh7604/sh7604.hpp"
|
||||
|
||||
@@ -17,7 +17,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
return offset;
|
||||
};
|
||||
|
||||
auto instruction = [&](string_view name) -> string {
|
||||
auto instruction = [&](string name) -> string {
|
||||
if(name.size() >= 7) return name;
|
||||
return pad(name, -7);
|
||||
};
|
||||
@@ -150,7 +150,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
};
|
||||
|
||||
#define op(id, name, ...) case id: \
|
||||
output.append(instruction(name), vector<string>{__VA_ARGS__}.merge(",")); \
|
||||
output.append(instruction(name), nall::merge({__VA_ARGS__}, ",")); \
|
||||
break
|
||||
|
||||
auto opcode = read(0);
|
||||
|
||||
@@ -56,7 +56,7 @@ auto Z80::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, ")"}
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
#include <ares/ares.hpp>
|
||||
#include "s3511a.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
//calculate time between last play of game and current time;
|
||||
//increment RTC by said amount of seconds
|
||||
auto S3511A::load() -> void {
|
||||
n64 timestamp = 0;
|
||||
for(auto n : range(8)) timestamp.byte(n) = data[8 + n];
|
||||
if(!timestamp || !(timestamp + 1)) return initRegs(false); //new save file
|
||||
|
||||
if(status() & 0x15) {
|
||||
//these status bits are always 0; reset state on invalid status.
|
||||
initRegs(false);
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp = time(0) - timestamp;
|
||||
//prevent insurmountable slowdown by limiting skips to 5 years
|
||||
if(timestamp < 60*60*24*365*5) {
|
||||
while(timestamp--) tickSecond();
|
||||
}
|
||||
}
|
||||
|
||||
//save time when game is unloaded
|
||||
auto S3511A::save() -> void {
|
||||
n64 timestamp = time(0);
|
||||
for(auto n : range(8)) data[8 + n] = timestamp.byte(n);
|
||||
}
|
||||
|
||||
auto S3511A::power() -> void {
|
||||
cs = 0;
|
||||
sio = 0;
|
||||
sck = 0;
|
||||
inBuffer = 0;
|
||||
outBuffer = 0;
|
||||
shift = 0;
|
||||
index = 0;
|
||||
rwSelect = 0;
|
||||
regSelect = 0;
|
||||
cmdLatched = 0;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
auto S3511A::tickSecond() -> void {
|
||||
static auto bcdIncrement = [](n8& data) -> n8 {
|
||||
if ((data & 0x0F) >= 0x09) {
|
||||
data = (data & 0xF0) + 0x10;
|
||||
} else {
|
||||
data++;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
if(bcdIncrement(second()) < 0x60) return;
|
||||
second() = 0;
|
||||
|
||||
if(bcdIncrement(minute()) < 0x60) return;
|
||||
minute() = 0;
|
||||
|
||||
if(status() & 0x40) {
|
||||
//24-hour clock
|
||||
if((bcdIncrement(hour()) & 0x7F) < 0x24) return;
|
||||
hour().bit(0,5) = 0;
|
||||
} else {
|
||||
//12-hour clock
|
||||
if((bcdIncrement(hour()) & 0x7F) < 0x12) return;
|
||||
hour().bit(0,5) = 0;
|
||||
hour().bit(7) ^= 1;
|
||||
}
|
||||
|
||||
weekday() += 1;
|
||||
weekday() %= 7;
|
||||
|
||||
u32 bcdDaysInMonth[12] = {0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31};
|
||||
if(year() && !(year() & 3)) bcdDaysInMonth[1]++;
|
||||
|
||||
if(bcdIncrement(day()) <= bcdDaysInMonth[month()]) return;
|
||||
day() = 1;
|
||||
|
||||
if(bcdIncrement(month()) <= 0x12) return;
|
||||
month() = 1;
|
||||
|
||||
bcdIncrement(year());
|
||||
}
|
||||
|
||||
auto S3511A::checkAlarm() -> void {
|
||||
//todo: a lot of this is vaguely informed guesswork.
|
||||
if(status() & 0x08) {
|
||||
//per-minute edge/steady
|
||||
if(counter < 256) irqLevel(1);
|
||||
if(status() & 0x02 && second() == 0x30 && counter == 0) irqLevel(0);
|
||||
} else if(status() & 0x02) {
|
||||
//selected frequency steady
|
||||
n16 duty = (counter << 1) ^ 0xFFFF;
|
||||
n16 mask = (alarmHour() | (alarmMinute() << 8));
|
||||
irqLevel((duty & mask) != 0);
|
||||
} else if(status() & 0x20) {
|
||||
//alarm
|
||||
if(status() & 0x40) {
|
||||
//24-hour clock
|
||||
irqLevel((hour() & 0x3F) == (alarmHour() & 0x3F) && (minute() & 0x7F) == (alarmMinute() & 0x7F));
|
||||
} else {
|
||||
//12-hour clock
|
||||
irqLevel((hour() & 0xBF) == (alarmHour() & 0xBF) && (minute() & 0x7F) == (alarmMinute() & 0x7F));
|
||||
}
|
||||
} else {
|
||||
irqLevel(0);
|
||||
}
|
||||
}
|
||||
|
||||
auto S3511A::readSIO() -> n1 {
|
||||
return sio | ~rwSelect | ~cs;
|
||||
}
|
||||
|
||||
auto S3511A::writeCS(n1 data) -> void {
|
||||
n1 csPrev = cs;
|
||||
cs = data;
|
||||
|
||||
//clear command status on falling edge
|
||||
if(csPrev == 1 && cs == 0) {
|
||||
inBuffer = 0x00;
|
||||
shift = 0;
|
||||
index = 0;
|
||||
rwSelect = 0;
|
||||
cmdLatched = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto S3511A::writeSIO(n1 data) -> void {
|
||||
sio = data;
|
||||
}
|
||||
|
||||
auto S3511A::writeSCK(n1 data) -> void {
|
||||
n1 sckPrev = sck | ~cs;
|
||||
sck = data;
|
||||
|
||||
//only read SIO data if CS is raised
|
||||
if(!cs) return;
|
||||
|
||||
//process command and output data on falling edge of SCK
|
||||
if(sckPrev == 1 && sck == 0) {
|
||||
if(!cmdLatched && shift == 0) writeCommand();
|
||||
if(cmdLatched && rwSelect == 1 && shift == 0) readRegister();
|
||||
sio = outBuffer.bit(shift);
|
||||
}
|
||||
|
||||
//sample RTC command data on rising edge of SCK
|
||||
if(sckPrev == 0 && sck == 1) {
|
||||
//add bit into input buffer
|
||||
inBuffer.bit(shift) = sio;
|
||||
shift++;
|
||||
if(cmdLatched && rwSelect == 0 && shift == 0) writeRegister();
|
||||
}
|
||||
}
|
||||
|
||||
auto S3511A::writeCommand() -> void {
|
||||
n4 magic = inBuffer >> 4;
|
||||
n4 cmd = inBuffer;
|
||||
if(magic != 0b0110) {
|
||||
//flip bit order of command
|
||||
magic = cmd;
|
||||
cmd.bit(0) = inBuffer.bit(7);
|
||||
cmd.bit(1) = inBuffer.bit(6);
|
||||
cmd.bit(2) = inBuffer.bit(5);
|
||||
cmd.bit(3) = inBuffer.bit(4);
|
||||
}
|
||||
if(magic != 0b0110) return; //invalid command
|
||||
rwSelect = cmd;
|
||||
regSelect = cmd >> 1;
|
||||
cmdLatched = 1;
|
||||
|
||||
//process any registers that have an effect on write without a payload
|
||||
if(rwSelect == 1) return;
|
||||
switch(regSelect) {
|
||||
case 0:
|
||||
//RESET
|
||||
initRegs(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto S3511A::readRegister() -> void {
|
||||
switch(regSelect) {
|
||||
case 1:
|
||||
//STATUS
|
||||
outBuffer = status();
|
||||
break;
|
||||
case 2: {
|
||||
//DATETIME
|
||||
switch(index) {
|
||||
case 0: outBuffer = year(); index++; break;
|
||||
case 1: outBuffer = month(); index++; break;
|
||||
case 2: outBuffer = day(); index++; break;
|
||||
case 3: outBuffer = weekday(); index++; break;
|
||||
case 4: outBuffer = hour(); index++; break;
|
||||
case 5: outBuffer = minute(); index++; break;
|
||||
default: outBuffer = second(); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
//TIME
|
||||
switch(index) {
|
||||
case 0: outBuffer = hour(); index++; break;
|
||||
case 1: outBuffer = minute(); index++; break;
|
||||
default: outBuffer = second(); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
//ALARM
|
||||
switch(index) {
|
||||
case 0: outBuffer = alarmHour(); index++; break;
|
||||
default: outBuffer = alarmMinute(); break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
outBuffer = 0xff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto S3511A::writeRegister() -> void {
|
||||
switch(regSelect) {
|
||||
case 1:
|
||||
//STATUS
|
||||
status().bit(1) = inBuffer.bit(1);
|
||||
status().bit(3) = inBuffer.bit(3);
|
||||
status().bit(5) = inBuffer.bit(5);
|
||||
status().bit(6) = inBuffer.bit(6);
|
||||
status().bit(7) &= inBuffer.bit(7);
|
||||
break;
|
||||
case 2: {
|
||||
//DATETIME
|
||||
switch(index) {
|
||||
case 0: year() = inBuffer; index++; break;
|
||||
case 1: month() = inBuffer; index++; break;
|
||||
case 2: day() = inBuffer; index++; break;
|
||||
case 3: weekday() = inBuffer; index++; break;
|
||||
case 4: hour() = inBuffer; index++; break;
|
||||
case 5: minute() = inBuffer; index++; break;
|
||||
default: second().bit(0,6) = inBuffer.bit(0,6); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
//TIME
|
||||
switch(index) {
|
||||
case 0: hour() = inBuffer; index++; break;
|
||||
case 1: minute() = inBuffer; index++; break;
|
||||
default: second().bit(0,6) = inBuffer.bit(0,6); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
//ALARM
|
||||
switch(index) {
|
||||
case 0: alarmHour() = inBuffer; index++; break;
|
||||
default: alarmMinute() = inBuffer; break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto S3511A::initRegs(bool reset) -> void {
|
||||
year() = 0;
|
||||
month() = 1;
|
||||
day() = 1;
|
||||
weekday() = 0;
|
||||
hour() = 0;
|
||||
minute() = 0;
|
||||
second() = 0;
|
||||
status() = reset ? 0x00 : 0x82;
|
||||
alarmHour() = 0x00;
|
||||
alarmMinute() = reset ? 0x00 : 0x80;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//Seiko S-3511A Real-Time Clock
|
||||
|
||||
struct S3511A {
|
||||
// bytes 0- 6: date/time data, BCD
|
||||
// bytes 7- 7: status register
|
||||
// bytes 8-15: last timestamp
|
||||
// bytes 16-17: alarm register
|
||||
static constexpr u32 size = 18;
|
||||
n8 data[size];
|
||||
|
||||
virtual auto irqLevel(bool value) -> void = 0;
|
||||
|
||||
//s3511a.cpp
|
||||
auto load() -> void;
|
||||
auto save() -> void;
|
||||
auto power() -> void;
|
||||
auto tickSecond() -> void;
|
||||
auto checkAlarm() -> void;
|
||||
auto readSIO() -> n1;
|
||||
auto writeCS(n1 data) -> void;
|
||||
auto writeSIO(n1 data) -> void;
|
||||
auto writeSCK(n1 data) -> void;
|
||||
auto writeCommand() -> void;
|
||||
auto readRegister() -> void;
|
||||
auto writeRegister() -> void;
|
||||
auto initRegs(bool reset) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//pin states
|
||||
n1 cs;
|
||||
n1 sio;
|
||||
n1 sck;
|
||||
|
||||
//buffered command data
|
||||
n8 inBuffer;
|
||||
n8 outBuffer;
|
||||
n3 shift;
|
||||
n3 index;
|
||||
|
||||
//internal state
|
||||
n1 rwSelect;
|
||||
n3 regSelect;
|
||||
n1 cmdLatched;
|
||||
n15 counter;
|
||||
|
||||
auto year() -> n8& { return data[ 0]; }
|
||||
auto month() -> n8& { return data[ 1]; }
|
||||
auto day() -> n8& { return data[ 2]; }
|
||||
auto weekday() -> n8& { return data[ 3]; }
|
||||
auto hour() -> n8& { return data[ 4]; }
|
||||
auto minute() -> n8& { return data[ 5]; }
|
||||
auto second() -> n8& { return data[ 6]; }
|
||||
auto status() -> n8& { return data[ 7]; }
|
||||
auto alarmHour() -> n8& { return data[16]; }
|
||||
auto alarmMinute() -> n8& { return data[17]; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
auto S3511A::serialize(serializer& s) -> void {
|
||||
s(std::span<n8>{data, size});
|
||||
|
||||
s(cs);
|
||||
s(sio);
|
||||
s(sck);
|
||||
s(inBuffer);
|
||||
s(outBuffer);
|
||||
s(shift);
|
||||
s(index);
|
||||
s(rwSelect);
|
||||
s(regSelect);
|
||||
s(cmdLatched);
|
||||
s(counter);
|
||||
}
|
||||
@@ -27,11 +27,11 @@ auto TMS9918::main() -> void {
|
||||
background.run(x, y);
|
||||
sprite.run(x, y);
|
||||
dac.run(x, y);
|
||||
step(1);
|
||||
step(2);
|
||||
}
|
||||
step(200);
|
||||
step(172);
|
||||
} else {
|
||||
step(456);
|
||||
step(684);
|
||||
}
|
||||
|
||||
io.vcounter++;
|
||||
|
||||
@@ -34,9 +34,9 @@ auto V9938::main() -> void {
|
||||
tick(1);
|
||||
}
|
||||
|
||||
tick(200);
|
||||
tick(86);
|
||||
} else {
|
||||
tick(456);
|
||||
tick(342);
|
||||
}
|
||||
|
||||
io.hcounter = 0;
|
||||
@@ -71,7 +71,7 @@ auto V9938::tick(u32 clocks) -> void {
|
||||
io.hcounter += clocks;
|
||||
while(clocks--) {
|
||||
command();
|
||||
step(1);
|
||||
step(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ auto Cartridge::connect() -> void {
|
||||
information.region = pak->attribute("region");
|
||||
information.board = pak->attribute("board");
|
||||
|
||||
if(information.board == "xin1") board = new Board::xin1{*this};
|
||||
if(information.board == "coleco") board = new Board::coleco{*this};
|
||||
if(information.board == "megacart") board = new Board::megacart{*this};
|
||||
if(information.board == "xin1") board = std::make_unique<Board::xin1>(*this);
|
||||
if(information.board == "coleco") board = std::make_unique<Board::coleco>(*this);
|
||||
if(information.board == "megacart") board = std::make_unique<Board::megacart>(*this);
|
||||
|
||||
|
||||
if(!board) board = new Board::Interface{*this};
|
||||
if(!board) board = std::make_unique<Board::Interface>(*this);
|
||||
board->pak = pak;
|
||||
board->load();
|
||||
power();
|
||||
|
||||
Loaded 100 of 1089 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user