mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-09 17:03:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
625df94505 | ||
|
|
0dc80ee4a2 | ||
|
|
f373fdc165 | ||
|
|
68f2c94658 | ||
|
|
11750b9600 | ||
|
|
135cadd32f | ||
|
|
f015fffd69 | ||
|
|
aa7260a58d | ||
|
|
cdd551f122 | ||
|
|
f3ce7952f6 | ||
|
|
9b1eb2e2f9 | ||
|
|
c337ba258f | ||
|
|
6f16c5c17e | ||
|
|
b494705ad7 | ||
|
|
371ba7b136 | ||
|
|
fb685afa70 | ||
|
|
f3ff75feb1 | ||
|
|
5211e6c56d | ||
|
|
e3c5cfb44d | ||
|
|
c95b48d95f | ||
|
|
136afead52 | ||
|
|
0865680da1 | ||
|
|
08811ee3cb | ||
|
|
b79ed895ff | ||
|
|
ece74e44e4 | ||
|
|
b1c69c9f3f | ||
|
|
4c42273a07 | ||
|
|
ac58451996 | ||
|
|
325c0ed876 | ||
|
|
f89777d8cc | ||
|
|
f0fd4c0bd2 | ||
|
|
a3d8db1c2a | ||
|
|
073d7a5375 | ||
|
|
264a1baafa | ||
|
|
645be6ab9b | ||
|
|
67fc2b1073 | ||
|
|
46b1991f8f | ||
|
|
c9dfe8a1b9 | ||
|
|
af07e1f863 | ||
|
|
b624fadd75 | ||
|
|
46209710d7 | ||
|
|
90eb0df7d7 | ||
|
|
64c9751dc5 | ||
|
|
54e3479708 | ||
|
|
9186ec0201 | ||
|
|
64196caef8 | ||
|
|
1d0d6177a5 | ||
|
|
421b7abf96 | ||
|
|
7e9df5858d | ||
|
|
69381f7c54 | ||
|
|
8f55894d65 | ||
|
|
4e1435be8a | ||
|
|
cf0c21e15a | ||
|
|
e10ce79153 | ||
|
|
ad7b83b604 | ||
|
|
53f3b6a2a2 | ||
|
|
b630377ddc | ||
|
|
24a9c00ae7 | ||
|
|
b5488aad82 | ||
|
|
5f782419ae | ||
|
|
7d5c6d2561 | ||
|
|
585e43a94c | ||
|
|
28ab75242f | ||
|
|
4dd7a1f5fe | ||
|
|
756ea5b704 | ||
|
|
7c051bae0b | ||
|
|
edfc6b5fb0 | ||
|
|
cdc0633fdd | ||
|
|
71facd2e14 | ||
|
|
af95d2b760 | ||
|
|
f4f48eb4b9 | ||
|
|
667827ab00 | ||
|
|
70480452a8 | ||
|
|
a70acad605 | ||
|
|
dca8745f83 | ||
|
|
fabbdc8d8f | ||
|
|
1a79a0aae0 | ||
|
|
de066b1ea2 | ||
|
|
c185fbd66e | ||
|
|
dae8db9883 | ||
|
|
4c4b2a5e5a | ||
|
|
510ccf01d7 | ||
|
|
aab2fdf9b2 | ||
|
|
e2d7106a6c | ||
|
|
1598f67506 | ||
|
|
5d3f614c63 | ||
|
|
8ef16dfbd9 | ||
|
|
701cfb7b13 | ||
|
|
ae121d7377 | ||
|
|
ed1e34c74e | ||
|
|
728105b28e | ||
|
|
3d88e24559 | ||
|
|
a61ce6449f | ||
|
|
63aa9ec5e4 | ||
|
|
50e42627e2 | ||
|
|
3a46652b15 | ||
|
|
7528feabe8 | ||
|
|
e57a80ea1b | ||
|
|
4c0a03b35a | ||
|
|
a247271e35 | ||
|
|
d61cfa905a | ||
|
|
9987bf18b2 | ||
|
|
8a80d32519 | ||
|
|
5d0de5fbb3 | ||
|
|
f06168e3f5 | ||
|
|
828f847efe | ||
|
|
d8c997ca8a | ||
|
|
93137b76b4 | ||
|
|
b889aff3d4 | ||
|
|
70f3bfa00c | ||
|
|
d942746f74 | ||
|
|
1c05456bec | ||
|
|
240363d31a | ||
|
|
ebb3bcb37b | ||
|
|
ab14fb1d10 | ||
|
|
7ba94fe7e4 | ||
|
|
69ea086d95 | ||
|
|
a510ac7e55 | ||
|
|
ac98fd8d9c | ||
|
|
122820753e | ||
|
|
e355fbe88c | ||
|
|
c1efa05d65 | ||
|
|
da071246fe | ||
|
|
cca0ecf202 | ||
|
|
17aee9071d | ||
|
|
b92ae8a14c | ||
|
|
4ae42b2d44 | ||
|
|
2a11da200d | ||
|
|
cbf4a939aa | ||
|
|
d10a8498e2 | ||
|
|
2eb6bf6df8 | ||
|
|
35ede44b80 | ||
|
|
0c011fb2d4 | ||
|
|
a006ef97e7 | ||
|
|
14a4f32997 | ||
|
|
25c1e281cc | ||
|
|
3ee7556bb7 | ||
|
|
a5b11b13d0 | ||
|
|
01e6cc1443 | ||
|
|
f5dace0a0f | ||
|
|
6b5ebb2882 | ||
|
|
140782662b | ||
|
|
3daec1184a | ||
|
|
7e4386c1bf | ||
|
|
8eba8ad784 | ||
|
|
08377d02e2 | ||
|
|
ea4ad6890a | ||
|
|
50be2e4e63 | ||
|
|
effc5614bc | ||
|
|
5f81464857 | ||
|
|
bd8442605e | ||
|
|
da312032de | ||
|
|
c509dd3964 | ||
|
|
10a4d480de | ||
|
|
8c3ead7cb0 | ||
|
|
1b36d47554 | ||
|
|
2c940b03a1 | ||
|
|
7a5174a712 | ||
|
|
274d6eb9a5 | ||
|
|
de0cb099cb | ||
|
|
32fd70f7c7 | ||
|
|
b2251305c0 | ||
|
|
25a2602300 | ||
|
|
4480f7adec | ||
|
|
4197502402 | ||
|
|
fb96de3eef | ||
|
|
54c898f199 | ||
|
|
e48b208de2 | ||
|
|
a9f9fd90e7 | ||
|
|
deb8830c82 | ||
|
|
58af8cb64b | ||
|
|
c9285b5289 | ||
|
|
4fc09438d2 | ||
|
|
a0a7a53b32 | ||
|
|
90f1425b8e | ||
|
|
9f4446061d | ||
|
|
32e58943f0 | ||
|
|
bc116e70e1 | ||
|
|
992e1c08cb | ||
|
|
9dcc1a39d3 | ||
|
|
9bbcf638dd | ||
|
|
d6c8d36770 | ||
|
|
c19cf47803 | ||
|
|
1d5a5aef83 | ||
|
|
64ec01bd57 | ||
|
|
82b1e88ec1 | ||
|
|
a592dc24d2 | ||
|
|
976b9828b6 | ||
|
|
7f625b6348 | ||
|
|
23a9d66924 | ||
|
|
e4e9044097 | ||
|
|
04a51df859 | ||
|
|
0c80c1e56b | ||
|
|
6f7618dc81 | ||
|
|
fdd7acb76b | ||
|
|
7ce2ffd010 | ||
|
|
bb22386f5f | ||
|
|
b372f65691 | ||
|
|
048d0e331d | ||
|
|
1323a627b3 | ||
|
|
b4ef96e4d6 | ||
|
|
8d2f88b745 | ||
|
|
ca7eee17a9 | ||
|
|
9ef81df3cf | ||
|
|
68af829f8e | ||
|
|
56862e0026 | ||
|
|
09d8af1c18 | ||
|
|
d20bc3c1b0 | ||
|
|
97c82119b5 | ||
|
|
b78228c5c0 | ||
|
|
5107ed00cb | ||
|
|
aeff8ec8f9 | ||
|
|
7640e1598c |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# When archiving, export a version file containing tag/commit information
|
||||
cmake/common/.archive-version.json export-subst
|
||||
@@ -10,6 +10,7 @@ pushd build
|
||||
# build; pipe output to render warnings neatly
|
||||
xcodebuild -configuration RelWithDebInfo \
|
||||
DEBUG_INFORMATION_FORMAT="dwarf-with-dsym" \
|
||||
-parallelizeTargets \
|
||||
2>&1 | xcbeautify --renderer github-actions
|
||||
|
||||
popd
|
||||
|
||||
@@ -13,7 +13,7 @@ cmake --preset $TARGET_PRESET
|
||||
pushd build
|
||||
cmake --build . --config RelWithDebInfo
|
||||
|
||||
if [ "$CROSS_COMPILE" = true ]; then
|
||||
if [ "$CROSS_COMPILE" = true ] || [ "$ARES_PLATFORM_NAME" = "windows-arm64" ]; then
|
||||
cp ../.deps/ares-deps-windows-arm64/lib/*.pdb desktop-ui/rundir/
|
||||
else
|
||||
cp ../.deps/ares-deps-windows-x64/lib/*.pdb desktop-ui/rundir/
|
||||
|
||||
@@ -21,13 +21,12 @@ do
|
||||
mkdir ${outdir}-dSYMs
|
||||
cp -a ${bindir}/ares-${package}-dSYMs/*.dSYM ${outdir}-dSYMs
|
||||
cp -a ${bindir}/ares-${package}/*.app ${outdir}
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
zip -r ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
|
||||
|
||||
zip -r -y ../ares-${package}.zip ${outdir}
|
||||
zip -r -y ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
|
||||
cd -
|
||||
done
|
||||
|
||||
for package in windows-x64 windows-clang-cl-x64 windows-clang-cl-arm64
|
||||
for package in windows-x64 windows-clang-cl-arm64
|
||||
do
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
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: ${{ 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'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
|
||||
- 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_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: "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/*
|
||||
+80
-264
@@ -1,10 +1,17 @@
|
||||
name: Build
|
||||
name: Build (Primary)
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags: [ 'v*' ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_call:
|
||||
inputs:
|
||||
codesign:
|
||||
description: Enable codesigning
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
official:
|
||||
description: Use official version strings
|
||||
required: true
|
||||
default: true
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -12,53 +19,28 @@ jobs:
|
||||
matrix:
|
||||
program:
|
||||
- ares
|
||||
config:
|
||||
- RelWithDebInfo
|
||||
platform:
|
||||
- name: windows
|
||||
- name: windows-x64
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
windres: windres
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-pkgconf mingw-w64-clang-x86_64-SDL2
|
||||
- name: windows-arm64
|
||||
install: make git cmake ccache ninja mingw-w64-clang-x86_64-clang
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-clang-cl-arm64
|
||||
os: windows-latest
|
||||
compiler: clang++ --target=aarch64-w64-windows-gnu --sysroot=/clangarm64 -resource-dir=/clangarm64/lib/clang/$(basename "$(clang++ -print-resource-dir)")
|
||||
windres: windres --target=aarch64-w64-windows-gnu
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-pkgconf mingw-w64-clang-aarch64-SDL2
|
||||
- name: windows-msvc-x64
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
windres: llvm-rc
|
||||
shell: bash
|
||||
msvc-arch: x64
|
||||
- name: windows-msvc-arm64
|
||||
os: windows-latest
|
||||
compiler: clang++ --target=aarch64-w64-windows-msvc
|
||||
windres: llvm-rc
|
||||
shell: bash
|
||||
msvc-arch: x64_arm64
|
||||
- name: windows-cl-x64
|
||||
os: windows-latest
|
||||
compiler: cl
|
||||
windres: rc
|
||||
shell: bash
|
||||
msvc-arch: x64
|
||||
- name: windows-cl-arm64
|
||||
os: windows-latest
|
||||
compiler: cl
|
||||
windres: rc
|
||||
shell: bash
|
||||
msvc-arch: x64_arm64
|
||||
target-cmake-preset: windows-ci-cl-cross
|
||||
native-cmake-preset: windows-ci-cl-native
|
||||
- name: macos-universal
|
||||
os: macos-15
|
||||
compiler: clang++
|
||||
shell: sh
|
||||
- name: ubuntu
|
||||
os: ubuntu-latest
|
||||
compiler: g++
|
||||
shell: sh
|
||||
install: cmake ccache xcbeautify
|
||||
target-cmake-preset: macos-ci-universal
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
defaults:
|
||||
@@ -67,250 +49,84 @@ jobs:
|
||||
steps:
|
||||
- name: Install MSYS2 Dependencies
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
uses: msys2/setup-msys2@v2
|
||||
uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: make ${{ matrix.platform.install }}
|
||||
install: ${{ matrix.platform.install }}
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && inputs.codesign
|
||||
uses: apple-actions/import-codesign-certs@65cfbc37e1464d733524cb555b724878f278b8c3
|
||||
continue-on-error: ${{ secrets.MACOS_CERTIFICATE_NAME == '' }}
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
- name: Setup MSYS2 Git Environment
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
run: |
|
||||
git config core.autocrlf true
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && github.event_name != 'pull_request'
|
||||
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
|
||||
uses: wpilibsuite/import-signing-certificate@2ac4f44d28045073d23153256efbb4c4b2d8aa22 # Don't use rolling branch for security reasons
|
||||
with:
|
||||
certificate-data: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
certificate-passphrase: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
keychain-name: ares-macos-keychain
|
||||
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Windows Dependencies
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
export PATH="/c/Users/runneradmin/.cargo/bin:$PATH" # correct on windows-latest as of 2024-02-19
|
||||
if [[ ${{ matrix.platform.name }} == *-arm64 ]]; then
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
rustup target add aarch64-pc-windows-msvc
|
||||
pushd thirdparty/librashader
|
||||
./build-librashader.sh aarch64-pc-windows-msvc
|
||||
popd
|
||||
else
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
pushd thirdparty/librashader
|
||||
./build-librashader.sh
|
||||
popd
|
||||
fi
|
||||
- name: "macOS: recover MoltenVK cache"
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: moltenvk
|
||||
with:
|
||||
path: thirdparty/MoltenVK/MoltenVK
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('thirdparty/MoltenVK/HEAD') }}
|
||||
sudo apt-get install ${{ matrix.platform.install }}
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
sudo xcode-select -s /Applications/Xcode_16.1.0.app/Contents/Developer
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.13
|
||||
brew install ninja cmake
|
||||
pip install --no-input setuptools
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
rustup target add x86_64-apple-darwin
|
||||
rustup target add aarch64-apple-darwin
|
||||
pushd thirdparty/SDL
|
||||
./build-SDL.sh
|
||||
popd
|
||||
pushd thirdparty/MoltenVK
|
||||
./build-moltenvk.sh
|
||||
popd
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
pushd thirdparty/librashader
|
||||
./build-librashader.sh
|
||||
popd
|
||||
- name: Set up MSVC environment
|
||||
if: matrix.platform.msvc-arch != ''
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: ${{ matrix.platform.msvc-arch }}
|
||||
- name: Make
|
||||
if: runner.os != 'macOS'
|
||||
run: ${MAKE:-make} -j4 -C desktop-ui build=optimized local=false compiler="${{ matrix.platform.compiler }}" windres="${{ matrix.platform.windres }}"
|
||||
- name: "macOS: Make universal app"
|
||||
if: runner.os == 'macOS'
|
||||
run: scripts/macos-make-universal.sh build=optimized local=false
|
||||
brew install ${{ matrix.platform.install }}
|
||||
- name: "Build: Windows"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: .github/scripts/build_windows.sh
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_KEYCHAIN_NAME: ares-macos-keychain
|
||||
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
ARES_BUILD_OFFICIAL: ${{ inputs.official }}
|
||||
ARES_PLATFORM_NAME: ${{ matrix.platform.name }}
|
||||
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
|
||||
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Windows: sign"
|
||||
if: runner.os == 'Windows' && github.event_name != 'pull_request'
|
||||
if: runner.os == 'Windows' && inputs.codesign
|
||||
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
|
||||
with:
|
||||
certificate: '${{ secrets.WIN_CERTIFICATE }}'
|
||||
password: '${{ secrets.WIN_PASSWORD }}'
|
||||
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
|
||||
certificatename: '${{ secrets.WIN_CERTNAME }}'
|
||||
folder: 'desktop-ui/out'
|
||||
folder: 'build/desktop-ui/rundir/'
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
- name: "macOS: notarize"
|
||||
if: false
|
||||
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
|
||||
run: |
|
||||
ditto -c -k --keepParent desktop-ui/out/ares.app /tmp/ares.zip
|
||||
xcrun notarytool submit /tmp/ares.zip --apple-id "$MACOS_NOTARIZATION_USERNAME" --password "$MACOS_NOTARIZATION_PASSWORD" --team-id "$MACOS_NOTARIZATION_TEAMID" --wait
|
||||
xcrun stapler staple desktop-ui/out/ares.app
|
||||
- name: "Build: macOS"
|
||||
if: runner.os == 'macOS'
|
||||
run: .github/scripts/build_macos.sh
|
||||
env:
|
||||
MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
|
||||
MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
|
||||
ARES_BUILD_OFFICIAL: ${{ inputs.official }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: "Compress Build Artifact (macOS)"
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/RelWithDebInfo/ .
|
||||
- name: "Compress Build Artifacts (Windows)"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: |
|
||||
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/rundir/ .
|
||||
- name: Upload Build
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: desktop-ui/out/*
|
||||
|
||||
|
||||
release:
|
||||
if: false
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
path: ares-${{ matrix.platform.name }}.tar.xz
|
||||
- name: Upload Debug Symbols (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
path: 'src'
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
|
||||
path: build/PDBs/*
|
||||
- name: Upload Debug Symbols (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
path: 'bin'
|
||||
- name: Package Artifacts
|
||||
run: |
|
||||
set -eu
|
||||
case ${GITHUB_REF} in
|
||||
refs/tags/*) suffix="-${GITHUB_REF#refs/tags/}" ;;
|
||||
refs/heads/master) suffix="-nightly" ;;
|
||||
*) suffix="" ;;
|
||||
esac
|
||||
|
||||
srcdir="${GITHUB_WORKSPACE}/src"
|
||||
bindir="${GITHUB_WORKSPACE}/bin"
|
||||
|
||||
# Hack: Workaround for GitHub artifacts losing attributes.
|
||||
chmod +x ${bindir}/ares-macos-universal/ares.app/Contents/MacOS/ares
|
||||
|
||||
for package in windows windows-msvc-arm64 macos-universal
|
||||
do
|
||||
mkdir "${package}"
|
||||
cd "${package}"
|
||||
|
||||
# Package ares.
|
||||
outdir=ares${suffix}
|
||||
mkdir ${outdir}
|
||||
cp -ar ${bindir}/ares-${package}/* ${outdir}
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
|
||||
cd -
|
||||
done
|
||||
- name: Create Release
|
||||
id: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -eu
|
||||
github_rest()
|
||||
{
|
||||
local method="${1}"
|
||||
local url="https://api.github.com${2}"
|
||||
shift 2
|
||||
>&2 echo "${method} ${url}"
|
||||
curl \
|
||||
--fail \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||
-X "${method}" \
|
||||
"${url}" \
|
||||
"$@"
|
||||
}
|
||||
github_get_release_id_for_tag()
|
||||
{
|
||||
payload=$(github_rest GET "/repos/${GITHUB_REPOSITORY}/releases/tags/${1}") || return
|
||||
echo "${payload}" | jq .id
|
||||
}
|
||||
github_delete_release_by_id()
|
||||
{
|
||||
github_rest DELETE "/repos/${GITHUB_REPOSITORY}/releases/${1}"
|
||||
}
|
||||
github_create_release()
|
||||
{
|
||||
local payload="{
|
||||
\"tag_name\": \"${1}\",
|
||||
\"target_commitish\": \"${2}\",
|
||||
\"name\": \"${3}\",
|
||||
\"body\": \"${4}\",
|
||||
\"draft\": ${5},
|
||||
\"prerelease\": ${6}
|
||||
}"
|
||||
github_rest POST "/repos/${GITHUB_REPOSITORY}/releases" -d "${payload}"
|
||||
}
|
||||
make_nightly_release()
|
||||
{
|
||||
github_create_release \
|
||||
nightly \
|
||||
"${GITHUB_SHA}" \
|
||||
"ares nightly $(date +"%Y-%m-%d")" \
|
||||
"Auto-generated nightly release on $(date -u +"%Y-%m-%d %T %Z")" \
|
||||
false \
|
||||
true
|
||||
}
|
||||
make_version_release()
|
||||
{
|
||||
github_create_release \
|
||||
"${1}" \
|
||||
"${GITHUB_SHA}" \
|
||||
"ares ${1}" \
|
||||
"This is ares ${1}, released on $(date +"%Y-%m-%d")." \
|
||||
false \
|
||||
false
|
||||
}
|
||||
case ${GITHUB_REF} in
|
||||
refs/tags/*)
|
||||
# Create a new version release using the current revision.
|
||||
echo "UPLOAD_URL=$(make_version_release ${GITHUB_REF#refs/tags/} | jq -r .upload_url)" >> $GITHUB_ENV
|
||||
;;
|
||||
refs/heads/master)
|
||||
# Check for an existing nightly release.
|
||||
{ release_id=$(github_get_release_id_for_tag nightly); status=$?; } || true
|
||||
# Delete existing nightly release if it exists.
|
||||
case ${status} in
|
||||
0) github_delete_release_by_id "${release_id}" ;;
|
||||
22) >&2 echo "No current nightly release; skipping tag deletion." ;;
|
||||
*) >&2 echo "API call failed unexpectedly." && exit 1 ;;
|
||||
esac
|
||||
# Create a new nightly release using the current revision.
|
||||
echo "UPLOAD_URL=$(make_nightly_release | jq -r .upload_url)" >> $GITHUB_ENV
|
||||
;;
|
||||
esac
|
||||
- name: Upload ares-windows
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows.zip', asset_name: 'ares-windows.zip', asset_content_type: 'application/zip' }
|
||||
- name: Upload ares-windows-msvc-arm64
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows-msvc-arm64.zip', asset_name: 'ares-windows-msvc-arm64.zip', asset_content_type: 'application/zip' }
|
||||
- name: Upload ares-macos-universal
|
||||
uses: actions/upload-release-asset@v1
|
||||
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-universal.zip', asset_name: 'ares-macos-universal.zip', asset_content_type: 'application/zip' }
|
||||
# - name: Upload ares-ubuntu
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
|
||||
# with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-ubuntu.zip', asset_name: 'ares-ubuntu.zip', asset_content_type: 'application/zip' }
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
|
||||
path: build/dSYMs/*
|
||||
@@ -1,153 +0,0 @@
|
||||
name: Build (New)
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
codesign:
|
||||
description: Enable codesigning
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
program:
|
||||
- ares
|
||||
config:
|
||||
- RelWithDebInfo
|
||||
platform:
|
||||
- name: windows-x64
|
||||
os: windows-latest
|
||||
compiler: clang++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: clang64
|
||||
install: mingw-w64-clang-x86_64-clang
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-x64-gcc
|
||||
os: windows-latest
|
||||
compiler: g++
|
||||
shell: 'msys2 {0}'
|
||||
msystem: mingw64
|
||||
install: mingw-w64-x86_64-toolchain
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-clang-cl-x64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-cl-native
|
||||
- name: windows-clang-cl-arm64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-cl-cross
|
||||
native-cmake-preset: windows-ci-cl-native
|
||||
- name: windows-msvc-x64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-msvc-native
|
||||
- name: windows-msvc-arm64
|
||||
os: windows-latest
|
||||
windres: rc
|
||||
shell: bash
|
||||
target-cmake-preset: windows-ci-msvc-cross
|
||||
native-cmake-preset: windows-ci-msvc-native
|
||||
- name: macos-universal
|
||||
os: macos-15
|
||||
compiler: clang++
|
||||
shell: sh
|
||||
install: cmake ccache xcbeautify
|
||||
target-cmake-preset: macos-ci-universal
|
||||
- name: ubuntu
|
||||
os: ubuntu-latest
|
||||
compiler: g++
|
||||
shell: bash
|
||||
install: cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
|
||||
target-cmake-preset: ubuntu-ci
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.platform.shell }}
|
||||
steps:
|
||||
- name: Install MSYS2 Dependencies
|
||||
if: matrix.platform.shell == 'msys2 {0}'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: make git cmake ccache ninja ${{ matrix.platform.install }}
|
||||
- name: "macOS: Import Certificate"
|
||||
if: runner.os == 'macOS' && inputs.codesign
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
continue-on-error: ${{ !inputs.codesign }}
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install ${{ matrix.platform.install }}
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install ${{ matrix.platform.install }}
|
||||
- name: "Build: Linux"
|
||||
if: runner.os == 'Linux'
|
||||
run: .github/scripts/build_ubuntu.sh
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Build: Windows"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: .github/scripts/build_windows.sh
|
||||
env:
|
||||
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
|
||||
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Windows: sign"
|
||||
if: runner.os == 'Windows' && inputs.codesign
|
||||
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
|
||||
with:
|
||||
certificate: '${{ secrets.WIN_CERTIFICATE }}'
|
||||
password: '${{ secrets.WIN_PASSWORD }}'
|
||||
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
|
||||
certificatename: '${{ secrets.WIN_CERTNAME }}'
|
||||
folder: 'build/desktop-ui/rundir/'
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
- name: "Build: macOS"
|
||||
if: runner.os == 'macOS'
|
||||
run: .github/scripts/build_macos.sh
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
|
||||
- name: Upload Build (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: build/desktop-ui/rundir/*
|
||||
- name: Upload Build (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
path: build/desktop-ui/RelWithDebInfo/
|
||||
- name: Upload Debug Symbols (Windows)
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
|
||||
path: build/PDBs/*
|
||||
- name: Upload Debug Symbols (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
|
||||
path: build/dSYMs/*
|
||||
@@ -11,7 +11,13 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
build-project:
|
||||
name: Build
|
||||
uses: ./.github/workflows/build_new.yml
|
||||
name: Build ares (primary)
|
||||
uses: ./.github/workflows/build.yml
|
||||
permissions:
|
||||
contents: read
|
||||
with:
|
||||
official: false
|
||||
build-aux:
|
||||
name: Build ares (auxiliary)
|
||||
uses: ./.github/workflows/build-aux.yml
|
||||
secrets: inherit
|
||||
@@ -1,8 +1,6 @@
|
||||
name: Push
|
||||
on:
|
||||
push:
|
||||
branches: [ '*' ]
|
||||
tags: [ 'v*' ]
|
||||
push
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
@@ -10,11 +8,16 @@ permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
name: Build ares
|
||||
uses: ./.github/workflows/build_new.yml
|
||||
name: Build ares (primary)
|
||||
uses: ./.github/workflows/build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
codesign: true
|
||||
official: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }}
|
||||
build-aux:
|
||||
name: Build ares (auxiliary)
|
||||
uses: ./.github/workflows/build-aux.yml
|
||||
secrets: inherit
|
||||
release:
|
||||
name: Release
|
||||
needs: build
|
||||
|
||||
@@ -12,13 +12,22 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
path: 'src'
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
path: 'bin'
|
||||
- name: "Decompress Build Artifacts"
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
for package in macos-universal windows-x64 windows-clang-cl-arm64; do
|
||||
pushd bin/ares-${package}
|
||||
tar -xJf ares-${package}.tar.xz
|
||||
rm -f ares-${package}.tar.xz
|
||||
popd
|
||||
done
|
||||
- name: "macOS: notarize"
|
||||
if: inputs.notarize
|
||||
run: |
|
||||
@@ -48,12 +57,18 @@ jobs:
|
||||
description="This is ares ${GITHUB_REF_NAME}, released on ${now}."
|
||||
echo "description=${description}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Update Git Tag
|
||||
if: steps.check.outputs.tag == 'nightly'
|
||||
id: update-tag
|
||||
run: |
|
||||
git -C src tag -f ${{ steps.check.outputs.tag }}
|
||||
git -C src push -f origin ${{ steps.check.outputs.tag }}
|
||||
|
||||
- name: Create Release 🛫
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
|
||||
with:
|
||||
draft: ${{ github.ref != 'refs/heads/master' }}
|
||||
prerelease: ${{ steps.check.outputs.tag == 'nightly' }}
|
||||
tag_name: ${{ steps.check.outputs.tag }}
|
||||
name: ares ${{ steps.check.outputs.versionName }}
|
||||
body: ${{ steps.check.outputs.description }}
|
||||
@@ -62,7 +77,5 @@ jobs:
|
||||
${{ github.workspace }}/ares-macos-universal-dSYMs.zip
|
||||
${{ github.workspace }}/ares-windows-x64.zip
|
||||
${{ github.workspace }}/ares-windows-x64-PDBs.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-x64.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-x64-PDBs.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-arm64.zip
|
||||
${{ github.workspace }}/ares-windows-clang-cl-arm64-PDBs.zip
|
||||
+12
-4
@@ -26,10 +26,10 @@
|
||||
!CMakeLists.txt
|
||||
!CMakePresets.json
|
||||
|
||||
thirdparty/SDL/SDL
|
||||
thirdparty/SDL/libSDL2-2.0.0.dylib
|
||||
desktop-ui/out
|
||||
desktop-ui/obj
|
||||
# Exclude old macOS Finder metadata
|
||||
.DS_Store
|
||||
|
||||
# Exclude generated sources that still reside in-tree
|
||||
ruby/video/metal/shaders.metallib
|
||||
ruby/video/metal/shaders.ir
|
||||
ares/ares/resource/resource.cpp
|
||||
@@ -38,5 +38,13 @@ hiro/resource/resource.cpp
|
||||
hiro/resource/resource.hpp
|
||||
desktop-ui/resource/resource.cpp
|
||||
desktop-ui/resource/resource.hpp
|
||||
mia/resource/resource.cpp
|
||||
mia/resource/resource.hpp
|
||||
|
||||
# Exclude fetched third-party processor test binaries
|
||||
tests/arm7tdmi/tests
|
||||
tests/m68000/tests
|
||||
|
||||
# Exclude unused legacy zlib header that is renamed by CMake
|
||||
thirdparty/libchdr/deps/zlib-*/zconf.h
|
||||
thirdparty/libchdr/deps/zlib-*/zconf.h.included
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.28...3.30)
|
||||
cmake_minimum_required(VERSION 3.28...4.0)
|
||||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE)
|
||||
|
||||
@@ -12,7 +12,7 @@ add_subdirectory(cmake)
|
||||
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
add_subdirectory(nall)
|
||||
add_subdirectory(nall/nall)
|
||||
add_subdirectory(libco)
|
||||
add_subdirectory(ruby)
|
||||
add_subdirectory(hiro)
|
||||
|
||||
+13
-2
@@ -12,7 +12,8 @@
|
||||
"cacheVariables": {
|
||||
"ARES_PROFILE_ACCURACY": false,
|
||||
"ARES_BUILD_LOCAL": true,
|
||||
"ENABLE_CCACHE": true
|
||||
"ENABLE_CCACHE": true,
|
||||
"ARES_BUILD_OFFICIAL": {"type": "BOOL", "value": "$penv{ARES_BUILD_OFFICIAL}"}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -81,7 +82,7 @@
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_OSX_ARCHITECTURES": {"type": "STRING", "value": "x86_64;arm64"},
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "10.13"},
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "10.15"},
|
||||
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{MACOS_CERTIFICATE_NAME}"},
|
||||
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{MACOS_NOTARIZATION_TEAMID}"},
|
||||
"ENABLE_CCACHE": true,
|
||||
@@ -162,6 +163,16 @@
|
||||
"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++"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
targets = all clean install uninstall verbose
|
||||
|
||||
$(targets):
|
||||
@$(MAKE) -C desktop-ui $@
|
||||
|
||||
.PHONY: $(targets)
|
||||
@@ -1,7 +1,7 @@
|
||||
----------------------------------------------------------------------
|
||||
ares
|
||||
|
||||
Copyright (c) 2004-2024 ares team, Near et al
|
||||
Copyright (c) 2004-2025 ares team, Near et al
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
**ares** is a multi-system emulator that began development on October 14th, 2004.
|
||||
It is a descendant of [higan](https://github.com/higan-emu/higan) and [bsnes](https://github.com/bsnes-emu/bsnes/), and focuses on accuracy and preservation.
|
||||
|
||||
It's worth noting that ares takes some uncommon design approaches that essentially trade speed for code clarity. We avoid state machines and bitmasks (when possible). Most cores end up being half the amount of code, but slower. The code is clearer and less spaghettified, especially for systems with lots of processors. C bitfields being non-portable incurs a speedhit. Windows also has a speedhit over Linux due to its ABI needing more instructions to switch contexts.
|
||||
|
||||
Official Releases
|
||||
-----------------
|
||||
|
||||
@@ -14,21 +16,19 @@ Official releases are available from
|
||||
Nightly Builds
|
||||
--------------
|
||||
|
||||
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/higan-emu/ares/releases/tag/nightly).
|
||||
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/ares-emulator/ares/releases/tag/nightly).
|
||||
Only the latest nightly build is kept.
|
||||
|
||||
Building ares
|
||||
-------------
|
||||
|
||||
Build instructions are available on the ares wiki. See build instructions for:
|
||||
ares supports building on Windows, macOS, and various Linux/BSD distributions. See build instructions for:
|
||||
|
||||
* [Windows](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-Windows)
|
||||
* [macOS](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-macOS)
|
||||
* [Linux](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-Linux)
|
||||
* [BSD](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-BSD)
|
||||
|
||||
For legacy Makefile build instructions, see [here](https://github.com/ares-emulator/ares/wiki/Legacy-Build-Instructions).
|
||||
|
||||
Command-line options
|
||||
--------------------
|
||||
|
||||
@@ -40,7 +40,7 @@ Usage: ./ares [options] game(s)
|
||||
--help Displays available options and exit
|
||||
--fullscreen Start in full screen mode
|
||||
--system system Specify the system name
|
||||
--shader shader Specify GLSL shader name to load (requires OpenGL driver)
|
||||
--shader shader Specify a slang shader to load (requires OpenGL or Metal)
|
||||
--setting name=value Specify a value for a setting
|
||||
--dump-all-settings Show a list of all existing settings and exit
|
||||
--no-file-prompt Do not prompt to load (optional) additional roms (eg: 64DD)
|
||||
|
||||
+10
-1
@@ -1,5 +1,7 @@
|
||||
add_library(ares STATIC ares/ares.cpp ares/memory/fixed-allocator.cpp)
|
||||
|
||||
configure_file(ares/ares.cpp.in ares/ares.cpp @ONLY)
|
||||
|
||||
add_library(ares::ares ALIAS ares)
|
||||
|
||||
option(ARES_PROFILE_ACCURACY "Build to prefer emulation accuracy over performance in certain specific areas" OFF)
|
||||
@@ -29,7 +31,7 @@ endif()
|
||||
|
||||
target_sources(
|
||||
ares
|
||||
PRIVATE ares/ares.cpp ares/ares.hpp ares/inline.hpp ares/platform.hpp ares/random.hpp ares/types.hpp
|
||||
PRIVATE ares/ares.cpp ares/ares.cpp.in ares/ares.hpp ares/inline.hpp ares/platform.hpp ares/random.hpp ares/types.hpp
|
||||
)
|
||||
|
||||
target_sources(
|
||||
@@ -291,6 +293,13 @@ set_source_files_properties(
|
||||
n64/vulkan/parallel-rdp/vulkan/device.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/command_buffer.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/render_pass.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/context.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/memory_allocator.cpp
|
||||
n64/vulkan/parallel-rdp/vulkan/semaphore.cpp
|
||||
n64/vulkan/parallel-rdp/util/logging.cpp
|
||||
n64/vulkan/parallel-rdp/util/environment.cpp
|
||||
n64/vulkan/parallel-rdp/util/thread_name.cpp
|
||||
n64/vulkan/parallel-rdp/util/timer.cpp
|
||||
PROPERTIES SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
ifeq ($(platform),windows)
|
||||
options += $(call lib,uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32)
|
||||
else ifeq ($(platform),macos)
|
||||
else ifneq ($(filter $(platform),linux bsd),)
|
||||
options += -Wl,-export-dynamic
|
||||
options += -lX11 -lXext
|
||||
else
|
||||
$(error "ares is a library and cannot be built directly.")
|
||||
endif
|
||||
|
||||
ares.objects := ares ares-fixed-allocator
|
||||
|
||||
$(object.path)/ares.o: $(ares.path)/ares/ares.cpp
|
||||
$(object.path)/ares-fixed-allocator.o: $(ares.path)/ares/memory/fixed-allocator.cpp
|
||||
|
||||
ifeq ($(vulkan),true)
|
||||
flags += -DVULKAN
|
||||
endif
|
||||
|
||||
ifeq ($(profile),accuracy)
|
||||
flags += -DPROFILE_ACCURACY
|
||||
endif
|
||||
|
||||
ifeq ($(profile),performance)
|
||||
flags += -DPROFILE_PERFORMANCE
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),a26),)
|
||||
include $(ares.path)/a26/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),fc),)
|
||||
include $(ares.path)/fc/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),sfc),)
|
||||
include $(ares.path)/sfc/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),n64),)
|
||||
include $(ares.path)/n64/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),sg),)
|
||||
include $(ares.path)/sg/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ms),)
|
||||
include $(ares.path)/ms/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),md),)
|
||||
include $(ares.path)/md/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),saturn),)
|
||||
include $(ares.path)/saturn/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ps1),)
|
||||
include $(ares.path)/ps1/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),pce),)
|
||||
include $(ares.path)/pce/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),msx),)
|
||||
include $(ares.path)/msx/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),cv),)
|
||||
include $(ares.path)/cv/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),myvision),)
|
||||
include $(ares.path)/myvision/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),gb),)
|
||||
include $(ares.path)/gb/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),gba),)
|
||||
include $(ares.path)/gba/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ws),)
|
||||
include $(ares.path)/ws/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ng),)
|
||||
include $(ares.path)/ng/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ngp),)
|
||||
include $(ares.path)/ngp/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),spec),)
|
||||
include $(ares.path)/spec/GNUmakefile
|
||||
endif
|
||||
|
||||
include $(ares.path)/component/GNUmakefile
|
||||
|
||||
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
|
||||
|
||||
ares.objects := $(ares.objects:%=$(object.path)/%.o)
|
||||
@@ -1,15 +0,0 @@
|
||||
ares.components += mos6502
|
||||
|
||||
ares.objects += ares-a26-system
|
||||
ares.objects += ares-a26-controller
|
||||
ares.objects += ares-a26-cartridge
|
||||
ares.objects += ares-a26-cpu
|
||||
ares.objects += ares-a26-tia
|
||||
ares.objects += ares-a26-riot
|
||||
|
||||
$(object.path)/ares-a26-system.o: $(ares.path)/a26/system/system.cpp
|
||||
$(object.path)/ares-a26-controller.o: $(ares.path)/a26/controller/controller.cpp
|
||||
$(object.path)/ares-a26-cartridge.o: $(ares.path)/a26/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-a26-cpu.o: $(ares.path)/a26/cpu/cpu.cpp
|
||||
$(object.path)/ares-a26-tia.o: $(ares.path)/a26/tia/tia.cpp
|
||||
$(object.path)/ares-a26-riot.o: $(ares.path)/a26/riot/riot.cpp
|
||||
@@ -54,6 +54,7 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
}
|
||||
|
||||
node = Node::System::create(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
namespace ares {
|
||||
|
||||
Platform* platform = nullptr;
|
||||
bool _runAhead = false;
|
||||
atomic<bool> _runAhead = false;
|
||||
|
||||
const string Name = "ares";
|
||||
const string Version = "142";
|
||||
const string Copyright = "ares team, Near";
|
||||
const string Name = "@ARES_NAME@";
|
||||
const string Version = "@ARES_VERSION@";
|
||||
const string Copyright = "@ARES_LEGAL_COPYRIGHT_SHORT@";
|
||||
const string License = "ISC";
|
||||
const string LicenseURI = "https://opensource.org/licenses/ISC";
|
||||
const string Website = "ares-emu.net";
|
||||
const string WebsiteURI = "https://ares-emu.net/";
|
||||
const string Website = "@ARES_WEBSITE@";
|
||||
const string WebsiteURI = "https://@ARES_WEBSITE@/";
|
||||
const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
|
||||
|
||||
}
|
||||
+13
-1
@@ -66,11 +66,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>
|
||||
|
||||
@@ -24,6 +24,7 @@ Screen::~Screen() {
|
||||
}
|
||||
|
||||
auto Screen::main(uintptr_t) -> void {
|
||||
thread::setName("dev.ares.screen");
|
||||
while(!_kill) {
|
||||
unique_lock<mutex> lock(_frameMutex);
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
build := stable
|
||||
nall.path := ../../../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
all:
|
||||
sourcery resource.bml resource.cpp resource.hpp
|
||||
|
||||
clean:
|
||||
$(call delete,resource.cpp)
|
||||
$(call delete,resource.hpp)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,34 +0,0 @@
|
||||
namespace Resource {
|
||||
namespace Ares {
|
||||
extern const unsigned char Icon1x[6562];
|
||||
extern const unsigned char Icon2x[9662];
|
||||
extern const unsigned char Logo1x[11533];
|
||||
extern const unsigned char Logo2x[18991];
|
||||
}
|
||||
namespace Sprite {
|
||||
namespace SuperFamicom {
|
||||
extern const unsigned char CrosshairBlue[332];
|
||||
extern const unsigned char CrosshairGreen[329];
|
||||
extern const unsigned char CrosshairRed[342];
|
||||
}
|
||||
namespace WonderSwan {
|
||||
extern const unsigned char Auxiliary0[117];
|
||||
extern const unsigned char Auxiliary1[134];
|
||||
extern const unsigned char Auxiliary2[136];
|
||||
extern const unsigned char Headphones[167];
|
||||
extern const unsigned char Initialized[136];
|
||||
extern const unsigned char LowBattery[144];
|
||||
extern const unsigned char Orientation0[148];
|
||||
extern const unsigned char Orientation1[150];
|
||||
extern const unsigned char PoweredOn[155];
|
||||
extern const unsigned char Sleeping[154];
|
||||
extern const unsigned char VolumeA0[129];
|
||||
extern const unsigned char VolumeA1[142];
|
||||
extern const unsigned char VolumeA2[146];
|
||||
extern const unsigned char VolumeB0[125];
|
||||
extern const unsigned char VolumeB1[137];
|
||||
extern const unsigned char VolumeB2[148];
|
||||
extern const unsigned char VolumeB3[153];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,6 +432,16 @@ component_sources(
|
||||
processor/z80/z80.hpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
s3511a
|
||||
PRIMARY
|
||||
rtc/s3511a/s3511a.cpp
|
||||
INCLUDED
|
||||
rtc/s3511a/s3511a.hpp
|
||||
rtc/s3511a/serialization.cpp
|
||||
)
|
||||
|
||||
component_sources(
|
||||
COMPONENT
|
||||
sst39sf0x0
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
ares.components := $(call unique,$(ares.components))
|
||||
|
||||
ares.objects += $(if $(findstring ay38910,$(ares.components)),ares-audio-ay38910)
|
||||
ares.objects += $(if $(findstring msm5205,$(ares.components)),ares-audio-msm5205)
|
||||
ares.objects += $(if $(findstring sn76489,$(ares.components)),ares-audio-sn76489)
|
||||
ares.objects += $(if $(findstring t6w28,$(ares.components)),ares-audio-t6w28)
|
||||
ares.objects += $(if $(findstring ym2149,$(ares.components)),ares-audio-ym2149)
|
||||
ares.objects += $(if $(findstring ym2413,$(ares.components)),ares-audio-ym2413)
|
||||
ares.objects += $(if $(findstring ym2610,$(ares.components)),ares-audio-ym2610)
|
||||
ares.objects += $(if $(findstring ym2612,$(ares.components)),ares-audio-ym2612)
|
||||
|
||||
ares.objects += $(if $(findstring m24c,$(ares.components)),ares-eeprom-m24c)
|
||||
ares.objects += $(if $(findstring m93lcx6,$(ares.components)),ares-eeprom-m93lcx6)
|
||||
|
||||
ares.objects += $(if $(findstring i8255,$(ares.components)),ares-io-i8255)
|
||||
|
||||
ares.objects += $(if $(findstring arm7tdmi,$(ares.components)),ares-processor-arm7tdmi)
|
||||
ares.objects += $(if $(findstring gsu,$(ares.components)),ares-processor-gsu)
|
||||
ares.objects += $(if $(findstring hg51b,$(ares.components)),ares-processor-hg51b)
|
||||
ares.objects += $(if $(findstring huc6280,$(ares.components)),ares-processor-huc6280)
|
||||
ares.objects += $(if $(findstring i8080,$(ares.components)),ares-processor-i8080)
|
||||
ares.objects += $(if $(findstring m68hc05,$(ares.components)),ares-processor-m68hc05)
|
||||
ares.objects += $(if $(findstring m68000,$(ares.components)),ares-processor-m68000)
|
||||
ares.objects += $(if $(findstring mos6502,$(ares.components)),ares-processor-mos6502)
|
||||
ares.objects += $(if $(findstring sh2,$(ares.components)),ares-processor-sh2)
|
||||
ares.objects += $(if $(findstring sm5k,$(ares.components)),ares-processor-sm5k)
|
||||
ares.objects += $(if $(findstring sm83,$(ares.components)),ares-processor-sm83)
|
||||
ares.objects += $(if $(findstring spc700,$(ares.components)),ares-processor-spc700)
|
||||
ares.objects += $(if $(findstring ssp1601,$(ares.components)),ares-processor-ssp1601)
|
||||
ares.objects += $(if $(findstring tlcs900h,$(ares.components)),ares-processor-tlcs900h)
|
||||
ares.objects += $(if $(findstring upd96050,$(ares.components)),ares-processor-upd96050)
|
||||
ares.objects += $(if $(findstring v30mz,$(ares.components)),ares-processor-v30mz)
|
||||
ares.objects += $(if $(findstring wdc65816,$(ares.components)),ares-processor-wdc65816)
|
||||
ares.objects += $(if $(findstring z80,$(ares.components)),ares-processor-z80)
|
||||
|
||||
ares.objects += $(if $(findstring sst39sf0x0,$(ares.components)),ares-flash-sst39sf0x0)
|
||||
|
||||
ares.objects += $(if $(findstring tms9918,$(ares.components)),ares-video-tms9918)
|
||||
ares.objects += $(if $(findstring v9938,$(ares.components)),ares-video-v9938)
|
||||
|
||||
$(object.path)/ares-audio-ay38910.o: $(ares.path)/component/audio/ay38910/ay38910.cpp
|
||||
$(object.path)/ares-audio-msm5205.o: $(ares.path)/component/audio/msm5205/msm5205.cpp
|
||||
$(object.path)/ares-audio-sn76489.o: $(ares.path)/component/audio/sn76489/sn76489.cpp
|
||||
$(object.path)/ares-audio-t6w28.o: $(ares.path)/component/audio/t6w28/t6w28.cpp
|
||||
$(object.path)/ares-audio-ym2149.o: $(ares.path)/component/audio/ym2149/ym2149.cpp
|
||||
$(object.path)/ares-audio-ym2413.o: $(ares.path)/component/audio/ym2413/ym2413.cpp
|
||||
$(object.path)/ares-audio-ym2612.o: $(ares.path)/component/audio/ym2612/ym2612.cpp
|
||||
|
||||
$(object.path)/ares-eeprom-m24c.o: $(ares.path)/component/eeprom/m24c/m24c.cpp
|
||||
$(object.path)/ares-eeprom-m93lcx6.o: $(ares.path)/component/eeprom/m93lcx6/m93lcx6.cpp
|
||||
|
||||
$(object.path)/ares-io-i8255.o: $(ares.path)/component/io/i8255/i8255.cpp
|
||||
|
||||
$(object.path)/ares-processor-arm7tdmi.o: $(ares.path)/component/processor/arm7tdmi/arm7tdmi.cpp
|
||||
$(object.path)/ares-processor-gsu.o: $(ares.path)/component/processor/gsu/gsu.cpp
|
||||
$(object.path)/ares-processor-hg51b.o: $(ares.path)/component/processor/hg51b/hg51b.cpp
|
||||
$(object.path)/ares-processor-huc6280.o: $(ares.path)/component/processor/huc6280/huc6280.cpp
|
||||
$(object.path)/ares-processor-i8080.o: $(ares.path)/component/processor/i8080/i8080.cpp
|
||||
$(object.path)/ares-processor-m68hc05.o: $(ares.path)/component/processor/m68hc05/m68hc05.cpp
|
||||
$(object.path)/ares-processor-m68000.o: $(ares.path)/component/processor/m68000/m68000.cpp
|
||||
$(object.path)/ares-processor-mos6502.o: $(ares.path)/component/processor/mos6502/mos6502.cpp
|
||||
$(object.path)/ares-processor-sh2.o: $(ares.path)/component/processor/sh2/sh2.cpp
|
||||
$(object.path)/ares-processor-sm5k.o: $(ares.path)/component/processor/sm5k/sm5k.cpp
|
||||
$(object.path)/ares-processor-sm83.o: $(ares.path)/component/processor/sm83/sm83.cpp
|
||||
$(object.path)/ares-processor-spc700.o: $(ares.path)/component/processor/spc700/spc700.cpp
|
||||
$(object.path)/ares-processor-ssp1601.o: $(ares.path)/component/processor/ssp1601/ssp1601.cpp
|
||||
$(object.path)/ares-processor-tlcs900h.o: $(ares.path)/component/processor/tlcs900h/tlcs900h.cpp
|
||||
$(object.path)/ares-processor-upd96050.o: $(ares.path)/component/processor/upd96050/upd96050.cpp
|
||||
$(object.path)/ares-processor-v30mz.o: $(ares.path)/component/processor/v30mz/v30mz.cpp
|
||||
$(object.path)/ares-processor-wdc65816.o: $(ares.path)/component/processor/wdc65816/wdc65816.cpp
|
||||
$(object.path)/ares-processor-z80.o: $(ares.path)/component/processor/z80/z80.cpp
|
||||
|
||||
$(object.path)/ares-flash-sst39sf0x0.o: $(ares.path)/component/flash/sst39sf0x0/sst39sf0x0.cpp
|
||||
|
||||
$(object.path)/ares-video-tms9918.o: $(ares.path)/component/video/tms9918/tms9918.cpp
|
||||
$(object.path)/ares-video-v9938.o: $(ares.path)/component/video/v9938/v9938.cpp
|
||||
@@ -125,7 +125,7 @@ auto YM2612::Channel::Operator::updatePhase() -> void {
|
||||
|
||||
auto YM2612::Channel::Operator::updateLevel() -> void {
|
||||
u32 lfo = ym2612.lfo.clock & 0x40 ? ym2612.lfo.clock & 0x3f : ~ym2612.lfo.clock & 0x3f;
|
||||
u32 depth = tremolos[channel.tremolo];
|
||||
u32 depth = tremolos[tremoloEnable * channel.tremolo];
|
||||
|
||||
bool invert = ssg.attack != ssg.invert && envelope.state != Release;
|
||||
n10 value = ssg.enable && invert ? 0x200 - envelope.value : 0 + envelope.value;
|
||||
@@ -147,7 +147,7 @@ auto YM2612::Channel::power() -> void {
|
||||
for(auto& op : operators) {
|
||||
op.keyOn = 0;
|
||||
op.keyLine = 0;
|
||||
op.lfoEnable = 0;
|
||||
op.tremoloEnable = 0;
|
||||
op.keyScale = 0;
|
||||
op.detune = 0;
|
||||
op.multiple = 0;
|
||||
|
||||
@@ -36,18 +36,14 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
//timer B period
|
||||
case 0x026: {
|
||||
timerB.period.bit(0,7) = data.bit(0,7);
|
||||
// Not sure if this is the right place for it, but...
|
||||
// handle a specific use case to reset the subticks on timer B
|
||||
if(!timerB.enable) timerB.divider = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
//timer control
|
||||
case 0x027: {
|
||||
//reload period on 0->1 transition
|
||||
if(!timerA.enable && data.bit(0)) timerA.counter = timerA.period;
|
||||
if(!timerB.enable && data.bit(1)) {
|
||||
timerB.counter = timerB.period;
|
||||
timerB.divider = 0;
|
||||
}
|
||||
|
||||
timerA.enable = data.bit(0);
|
||||
timerB.enable = data.bit(1);
|
||||
timerA.irq = data.bit(2);
|
||||
@@ -125,10 +121,10 @@ auto YM2612::writeData(n8 data) -> void {
|
||||
break;
|
||||
}
|
||||
|
||||
//LFO enable, decay rate
|
||||
//LFO AM enable, decay rate
|
||||
case 0x060: {
|
||||
op.envelope.decayRate = data.bit(0,4);
|
||||
op.lfoEnable = data.bit(7);
|
||||
op.tremoloEnable = data.bit(7);
|
||||
channel[index].updateEnvelope();
|
||||
channel[index].updateLevel();
|
||||
break;
|
||||
|
||||
@@ -13,12 +13,14 @@ auto YM2612::serialize(serializer& s) -> void {
|
||||
s(envelope.divider);
|
||||
|
||||
s(timerA.enable);
|
||||
s(timerA.enableLatch);
|
||||
s(timerA.irq);
|
||||
s(timerA.line);
|
||||
s(timerA.period);
|
||||
s(timerA.counter);
|
||||
|
||||
s(timerB.enable);
|
||||
s(timerB.enableLatch);
|
||||
s(timerB.irq);
|
||||
s(timerB.line);
|
||||
s(timerB.period);
|
||||
@@ -43,7 +45,7 @@ auto YM2612::Channel::serialize(serializer& s) -> void {
|
||||
auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
|
||||
s(keyOn);
|
||||
s(keyLine);
|
||||
s(lfoEnable);
|
||||
s(tremoloEnable);
|
||||
s(keyScale);
|
||||
s(detune);
|
||||
s(multiple);
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
auto YM2612::TimerA::run() -> void {
|
||||
if(!enable) return;
|
||||
if(++counter) return;
|
||||
|
||||
counter = period;
|
||||
line |= irq;
|
||||
if(!++counter)
|
||||
line |= irq & enableLatch;
|
||||
if(enableLatch < enable || !counter)
|
||||
counter = period;
|
||||
enableLatch = enable;
|
||||
}
|
||||
|
||||
auto YM2612::TimerB::run() -> void {
|
||||
if(!enable) return;
|
||||
if(++divider) return;
|
||||
if(++counter) return;
|
||||
|
||||
counter = period;
|
||||
line |= irq;
|
||||
if(!++divider && !++counter)
|
||||
line |= irq & enableLatch;
|
||||
if(enableLatch < enable || !counter && !divider)
|
||||
counter = period; // do not reset divider on reenable
|
||||
enableLatch = enable;
|
||||
}
|
||||
@@ -45,6 +45,7 @@ protected:
|
||||
auto run() -> void;
|
||||
|
||||
n1 enable = 0;
|
||||
n1 enableLatch = 0;
|
||||
n1 irq = 0;
|
||||
n1 line = 0;
|
||||
n10 period = 0;
|
||||
@@ -56,6 +57,7 @@ protected:
|
||||
auto run() -> void;
|
||||
|
||||
n1 enable = 0;
|
||||
n1 enableLatch = 0;
|
||||
n1 irq = 0;
|
||||
n1 line = 0;
|
||||
n8 period = 0;
|
||||
@@ -106,7 +108,7 @@ protected:
|
||||
|
||||
n1 keyOn = 0;
|
||||
n1 keyLine = 0;
|
||||
n1 lfoEnable = 0;
|
||||
n1 tremoloEnable = 0;
|
||||
n5 keyScale = 0;
|
||||
n3 detune = 0;
|
||||
n4 multiple = 0;
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace ares {
|
||||
io.portCHigherInput = 1;
|
||||
io.portAInput = 1;
|
||||
io.groupAMode = 0;
|
||||
io.ioMode = 0;
|
||||
state.portA = 0xff;
|
||||
state.portB = 0xff;
|
||||
state.portC = 0xff;
|
||||
@@ -43,15 +42,20 @@ namespace ares {
|
||||
}
|
||||
|
||||
auto I8255::writeControl(n8 data) -> void {
|
||||
if(data.bit(7) == 0) {
|
||||
n3 bitSelect = data.bit(1, 3);
|
||||
state.portC.bit(bitSelect) = data.bit(0);
|
||||
writePortC(state.portC);
|
||||
return;
|
||||
}
|
||||
|
||||
io.portCLowerInput = data.bit(0);
|
||||
io.portBInput = data.bit(1);
|
||||
io.groupBMode = data.bit(2);
|
||||
io.portCHigherInput = data.bit(3);
|
||||
io.portAInput = data.bit(4);
|
||||
io.groupAMode = data.bit(5,6);
|
||||
io.ioMode = data.bit(7);
|
||||
|
||||
if(!io.ioMode) debug(unimplemented, "[I8255] BSR Mode");
|
||||
if(io.groupAMode != 0) debug(unimplemented, "[I8255] Group A Mode != 0");
|
||||
if(io.groupBMode != 0) debug(unimplemented, "[I8255] Group B Mode != 0");
|
||||
}
|
||||
@@ -63,7 +67,6 @@ namespace ares {
|
||||
s(io.portCHigherInput);
|
||||
s(io.portAInput);
|
||||
s(io.groupAMode);
|
||||
s(io.ioMode);
|
||||
|
||||
s(state.portA);
|
||||
s(state.portB);
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace ares {
|
||||
n1 portCHigherInput;
|
||||
n1 portAInput;
|
||||
n2 groupAMode;
|
||||
n1 ioMode;
|
||||
} io;
|
||||
|
||||
struct State {
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace ares {
|
||||
#include "instruction.cpp"
|
||||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "coprocessor.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
@@ -19,7 +20,9 @@ ARM7TDMI::ARM7TDMI() {
|
||||
|
||||
auto ARM7TDMI::power() -> void {
|
||||
processor = {};
|
||||
processor.r15.modify = [&] { pipeline.reload = true; };
|
||||
processor.r15.modify = [&] { processor.r15.data &= ~1; pipeline.reload = true; };
|
||||
processor.rNULL.modify = [&] { processor.rNULL.data = 0; };
|
||||
processor.spsrNULL.readonly = true;
|
||||
pipeline = {};
|
||||
carry = 0;
|
||||
irq = 0;
|
||||
|
||||
@@ -6,15 +6,13 @@ namespace ares {
|
||||
|
||||
struct ARM7TDMI {
|
||||
enum : u32 {
|
||||
Nonsequential = 1 << 0, //N cycle
|
||||
Sequential = 1 << 1, //S cycle
|
||||
Load = 1 << 0, //load operation
|
||||
Store = 1 << 1, //store operation
|
||||
Prefetch = 1 << 2, //instruction fetch
|
||||
Byte = 1 << 3, // 8-bit access
|
||||
Half = 1 << 4, //16-bit access
|
||||
Word = 1 << 5, //32-bit access
|
||||
Load = 1 << 6, //load operation
|
||||
Store = 1 << 7, //store operation
|
||||
Signed = 1 << 8, //sign-extend
|
||||
Signed = 1 << 6, //sign-extend
|
||||
};
|
||||
|
||||
virtual auto step(u32 clocks) -> void = 0;
|
||||
@@ -44,6 +42,7 @@ struct ARM7TDMI {
|
||||
auto load(u32 mode, n32 address) -> n32;
|
||||
auto write(u32 mode, n32 address, n32 word) -> void;
|
||||
auto store(u32 mode, n32 address, n32 word) -> void;
|
||||
auto endBurst() -> void { nonsequential = true; return; }
|
||||
|
||||
//algorithms.cpp
|
||||
auto ADD(n32, n32, bool) -> n32;
|
||||
@@ -70,21 +69,25 @@ struct ARM7TDMI {
|
||||
auto armMoveToStatus(n4 field, n1 source, n32 data) -> void;
|
||||
|
||||
auto armInstructionBranch(i24, n1) -> void;
|
||||
auto armInstructionBranchExchangeRegister(n4) -> void;
|
||||
auto armInstructionBranchExchangeRegister(n4, n4, n4, n1) -> void;
|
||||
auto armInstructionCoprocessorDataProcessing(n4, n3, n4, n4, n4, n4) -> void;
|
||||
auto armInstructionDataImmediate(n8, n4, n4, n4, n1, n4) -> void;
|
||||
auto armInstructionDataImmediateShift(n4, n2, n5, n4, n4, n1, n4) -> void;
|
||||
auto armInstructionDataRegisterShift(n4, n2, n4, n4, n4, n1, n4) -> void;
|
||||
auto armInstructionLoadImmediate(n8, n1, n4, n4, n1, n1, n1) -> void;
|
||||
auto armInstructionLoadRegister(n4, n1, n4, n4, n1, n1, n1) -> void;
|
||||
auto armInstructionMemorySwap(n4, n4, n4, n1) -> void;
|
||||
auto armInstructionMoveHalfImmediate(n8, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveHalfRegister(n4, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveImmediateOffset(n12, n4, n4, n1, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveMultiple(n16, n4, n1, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveRegisterOffset(n4, n2, n5, n4, n4, n1, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveSignedImmediate(n8, n1, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveSignedRegister(n4, n1, n4, n4, n1, n1, n1, n1) -> void;
|
||||
auto armInstructionMoveToCoprocessorFromRegister(n4, n3, n4, n4, n4, n3) -> void;
|
||||
auto armInstructionMoveToRegisterFromCoprocessor(n4, n3, n4, n4, n4, n3) -> void;
|
||||
auto armInstructionMoveToRegisterFromRegister(n4, n4) -> void;
|
||||
auto armInstructionMoveToRegisterFromStatus(n4, n1) -> void;
|
||||
auto armInstructionMoveToStatusFromImmediate(n8, n4, n4, n1) -> void;
|
||||
auto armInstructionMoveToStatusFromRegister(n4, n4, n1) -> void;
|
||||
auto armInstructionMoveToStatusFromRegister(n4, n2, n5, n4, n1) -> void;
|
||||
auto armInstructionMultiply(n4, n4, n4, n4, n1, n1) -> void;
|
||||
auto armInstructionMultiplyLong(n4, n4, n4, n4, n1, n1, n1) -> void;
|
||||
auto armInstructionSoftwareInterrupt(n24 immediate) -> void;
|
||||
@@ -148,21 +151,31 @@ struct ARM7TDMI {
|
||||
};
|
||||
|
||||
operator u32() const {
|
||||
return m << 0 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
|
||||
return m << 0 | 1 << 4 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
|
||||
}
|
||||
|
||||
auto operator=(n32 data) -> PSR& {
|
||||
m = data.bit(0,4);
|
||||
t = data.bit(5);
|
||||
f = data.bit(6);
|
||||
i = data.bit(7);
|
||||
v = data.bit(28);
|
||||
c = data.bit(29);
|
||||
z = data.bit(30);
|
||||
n = data.bit(31);
|
||||
set(0b1111, data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto set(n4 field, n32 data) -> void {
|
||||
if(readonly) return;
|
||||
if(field.bit(0)) {
|
||||
m = data.bit(0,4) | 0x10;
|
||||
t = data.bit(5);
|
||||
f = data.bit(6);
|
||||
i = data.bit(7);
|
||||
}
|
||||
|
||||
if(field.bit(3)) {
|
||||
v = data.bit(28);
|
||||
c = data.bit(29);
|
||||
z = data.bit(30);
|
||||
n = data.bit(31);
|
||||
}
|
||||
}
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
@@ -174,6 +187,8 @@ struct ARM7TDMI {
|
||||
b1 c; //carry
|
||||
b1 z; //zero
|
||||
b1 n; //negative
|
||||
|
||||
b1 readonly;
|
||||
};
|
||||
|
||||
struct Processor {
|
||||
@@ -182,6 +197,8 @@ struct ARM7TDMI {
|
||||
|
||||
GPR r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
PSR cpsr;
|
||||
GPR rNULL; //read-only, used when no register is mapped to r(13) or r(14)
|
||||
PSR spsrNULL; //read-only, used when no SPSR is mapped
|
||||
|
||||
struct FIQ {
|
||||
GPR r8, r9, r10, r11, r12, r13, r14;
|
||||
@@ -221,7 +238,6 @@ struct ARM7TDMI {
|
||||
};
|
||||
|
||||
n1 reload = 1;
|
||||
n1 nonsequential = 1;
|
||||
Instruction fetch;
|
||||
Instruction decode;
|
||||
Instruction execute;
|
||||
@@ -230,27 +246,41 @@ struct ARM7TDMI {
|
||||
n32 opcode;
|
||||
b1 carry;
|
||||
b1 irq;
|
||||
b1 nonsequential;
|
||||
|
||||
function<void (n32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
|
||||
//coprocessor.cpp
|
||||
auto bindCDP(n4 id, function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void;
|
||||
auto bindMCR(n4 id, function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
auto bindMRC(n4 id, function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
|
||||
function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> CDP[16];
|
||||
function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> MCR[16];
|
||||
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;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
auto ARM7TDMI::bindCDP(n4 id, function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void {
|
||||
CDP[id] = handler;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::bindMCR(n4 id, function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
MCR[id] = handler;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::bindMRC(n4 id, function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
MRC[id] = handler;
|
||||
}
|
||||
@@ -17,12 +17,12 @@ auto ARM7TDMI::disassembleInstruction(maybe<n32> pc, maybe<boolean> thumb) -> st
|
||||
|
||||
_pc = pc();
|
||||
if(!thumb()) {
|
||||
n32 opcode = getDebugger(Word | Nonsequential, _pc & ~3);
|
||||
n32 opcode = getDebugger(Word, _pc & ~3);
|
||||
n12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
_c = _conditions[opcode >> 28];
|
||||
return pad(armDisassemble[index](opcode), -40);
|
||||
} else {
|
||||
n16 opcode = getDebugger(Half | Nonsequential, _pc & ~1);
|
||||
n16 opcode = getDebugger(Half, _pc & ~1);
|
||||
return pad(thumbDisassemble[opcode](), -40);
|
||||
}
|
||||
}
|
||||
@@ -64,10 +64,16 @@ auto ARM7TDMI::armDisassembleBranch
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleBranchExchangeRegister
|
||||
(n4 m) -> string {
|
||||
(n4 m, n4 d, n4 field, n1 mode) -> string {
|
||||
return {"bx", _c, " ", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleCoprocessorDataProcessing
|
||||
(n4 cm, n3 op2, n4 cpid, n4 cd, n4 cn, n4 op1) -> string {
|
||||
return {"cdp", _c, " p", cpid, ", ", op1, ", cr", cd,
|
||||
", cr", cn, ", cr", cm, ", ", op2};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleDataImmediate
|
||||
(n8 immediate, n4 shift, n4 d, n4 n, n1 save, n4 mode) -> string {
|
||||
static const string opcode[] = {
|
||||
@@ -118,30 +124,6 @@ auto ARM7TDMI::armDisassembleDataRegisterShift
|
||||
" ", _r[s]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte) | Nonsequential,
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> string {
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMemorySwap
|
||||
(n4 m, n4 d, n4 n, n1 byte) -> string {
|
||||
return {"swp", _c, byte ? "b" : "", " ", _r[d], ",", _r[m], ",[", _r[n], "]"};
|
||||
@@ -150,7 +132,7 @@ auto ARM7TDMI::armDisassembleMemorySwap
|
||||
auto ARM7TDMI::armDisassembleMoveHalfImmediate
|
||||
(n8 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger(Half | Nonsequential, _pc + (up ? +immediate : -immediate)), 4L)};
|
||||
if(n == 15) data = {" =0x", hex(getDebugger(Half, _pc + (up ? +immediate : -immediate)), 4L)};
|
||||
|
||||
return {mode ? "ldr" : "str", _c, "h ",
|
||||
_r[d], ",[", _r[n],
|
||||
@@ -173,7 +155,7 @@ auto ARM7TDMI::armDisassembleMoveHalfRegister
|
||||
auto ARM7TDMI::armDisassembleMoveImmediateOffset
|
||||
(n12 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 byte, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((byte ? Byte : Word) | Nonsequential,
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((byte ? Byte : Word),
|
||||
_pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)};
|
||||
return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
@@ -212,6 +194,47 @@ auto ARM7TDMI::armDisassembleMoveRegisterOffset
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveSignedImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte),
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {mode ? "ldr" : "str", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveSignedRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
|
||||
return {mode ? "ldr" : "str", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToCoprocessorFromRegister
|
||||
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> string {
|
||||
return {"mcr", _c, " p", cpid, ", ", op1, ", ", _r[d],
|
||||
", cr", cn, ", cr", cm, ", ", op2};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromCoprocessor
|
||||
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> string {
|
||||
return {"mrc", _c, " p", cpid, ", ", op1, ", ", _r[d],
|
||||
", cr", cn, ", cr", cm, ", ", op2};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromRegister
|
||||
(n4 d, n4 n) -> string {
|
||||
return {"mov", _c, " ", _r[d], ",", _r[n]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus
|
||||
(n4 d, n1 mode) -> string {
|
||||
return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"};
|
||||
@@ -229,13 +252,18 @@ auto ARM7TDMI::armDisassembleMoveToStatusFromImmediate
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToStatusFromRegister
|
||||
(n4 m, n4 field, n1 mode) -> string {
|
||||
(n4 m, n2 type, n5 shift, n4 field, n1 mode) -> string {
|
||||
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
|
||||
field.bit(0) ? "c" : "",
|
||||
field.bit(1) ? "x" : "",
|
||||
field.bit(2) ? "s" : "",
|
||||
field.bit(3) ? "f" : "",
|
||||
",", _r[m]};
|
||||
",", _r[m],
|
||||
type == 0 && shift ? string{" lsl #", shift} : string{},
|
||||
type == 1 ? string{" lsr #", shift ? (u32)shift : 32} : string{},
|
||||
type == 2 ? string{" asr #", shift ? (u32)shift : 32} : string{},
|
||||
type == 3 && shift ? string{" ror #", shift} : string{},
|
||||
type == 3 && !shift ? " rrx" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMultiply
|
||||
@@ -276,7 +304,7 @@ auto ARM7TDMI::thumbDisassembleALU
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleALUExtended
|
||||
(n4 d, n4 m, n2 mode) -> string {
|
||||
static const string opcode[] = {"add", "sub", "mov"};
|
||||
static const string opcode[] = {"add", "cmp", "mov"};
|
||||
if(d == 8 && m == 8 && mode == 2) return {"nop"};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m]};
|
||||
}
|
||||
@@ -308,7 +336,7 @@ auto ARM7TDMI::thumbDisassembleBranchExchange
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchFarPrefix
|
||||
(i11 displacementHi) -> string {
|
||||
n11 displacementLo = getDebugger(Half | Nonsequential, (_pc & ~1) + 2);
|
||||
n11 displacementLo = getDebugger(Half, (_pc & ~1) + 2);
|
||||
i22 displacement = displacementHi << 11 | displacementLo << 0;
|
||||
n32 address = _pc + 4 + displacement * 2;
|
||||
return {"bl 0x", hex(address, 8L)};
|
||||
@@ -340,7 +368,7 @@ auto ARM7TDMI::thumbDisassembleImmediate
|
||||
auto ARM7TDMI::thumbDisassembleLoadLiteral
|
||||
(n8 displacement, n3 d) -> string {
|
||||
n32 address = ((_pc + 4) & ~3) + (displacement << 2);
|
||||
n32 data = getDebugger(Word | Nonsequential, address);
|
||||
n32 data = getDebugger(Word, address);
|
||||
return {"ldr ", _r[d], ",[pc,#0x", hex(address, 8L), "] =0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
auto ARM7TDMI::reload() -> void {
|
||||
u32 mask = !cpsr().t ? 3 : 1;
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~mask;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
|
||||
endBurst();
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
|
||||
@@ -16,18 +14,10 @@ auto ARM7TDMI::fetch() -> void {
|
||||
pipeline.decode.thumb = cpsr().t;
|
||||
pipeline.decode.irq = !cpsr().i;
|
||||
|
||||
u32 sequential = Sequential;
|
||||
if(pipeline.nonsequential) {
|
||||
pipeline.nonsequential = false;
|
||||
sequential = Nonsequential;
|
||||
}
|
||||
|
||||
u32 mask = !cpsr().t ? 3 : 1;
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
r(15).data += size >> 3;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | sequential, pipeline.fetch.address);
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::instruction() -> void {
|
||||
@@ -85,13 +75,31 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) /* m */
|
||||
{
|
||||
auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????");
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* field */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(n3 _ : range(8))
|
||||
for(n1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0??0 ???? ???? ---- 0??1 ????") | _.bit(0,1) << 5 | _.bit(2) << 21 | mode << 22;
|
||||
bind(opcode, BranchExchangeRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* cm */ \
|
||||
opcode.bit( 5, 7), /* op2 */ \
|
||||
opcode.bit( 8,11), /* cpid */ \
|
||||
opcode.bit(12,15), /* cd */ \
|
||||
opcode.bit(16,19), /* cn */ \
|
||||
opcode.bit(20,23) /* op1 */
|
||||
for(n3 op2 : range(8))
|
||||
for(n4 op1 : range(16)) {
|
||||
auto opcode = pattern(".... 1110 ???? ???? ???? ???? ???0 ????") | op2 << 5 | op1 << 20;
|
||||
bind(opcode, CoprocessorDataProcessing);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 7), /* immediate */ \
|
||||
opcode.bit( 8,11), /* shift */ \
|
||||
@@ -143,47 +151,14 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?1 ???? ???? ???? 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?1 ???? ???? ---- 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(22) /* byte */
|
||||
for(n3 _ : range(8))
|
||||
for(n1 byte : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22;
|
||||
auto opcode = pattern(".... 0001 ???? ???? ???? ---- 1001 ????") | _.bit(0,1) << 20 | byte << 22 | _.bit(2) << 23;
|
||||
bind(opcode, MemorySwap);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -287,11 +262,88 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 mode : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?? ???? ???? ???? 11?1 ????") | half << 5 | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveSignedImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(n1 half : range(2))
|
||||
for(n1 mode : range(2))
|
||||
for(n1 writeback : range(2))
|
||||
for(n1 up : range(2))
|
||||
for(n1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?? ???? ???? ---- 11?1 ????") | half << 5 | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveSignedRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* cm */ \
|
||||
opcode.bit( 5, 7), /* op2 */ \
|
||||
opcode.bit( 8,11), /* cpid */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* cn */ \
|
||||
opcode.bit(21,23) /* op1 */
|
||||
for(n3 op2 : range(8))
|
||||
for(n3 op1 : range(8)) {
|
||||
auto opcode = pattern(".... 1110 ???0 ???? ???? ???? ???1 ????") | op2 << 5 | op1 << 21;
|
||||
bind(opcode, MoveToCoprocessorFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* cm */ \
|
||||
opcode.bit( 5, 7), /* op2 */ \
|
||||
opcode.bit( 8,11), /* cpid */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* cn */ \
|
||||
opcode.bit(21,23) /* op1 */
|
||||
for(n3 op2 : range(8))
|
||||
for(n3 op1 : range(8)) {
|
||||
auto opcode = pattern(".... 1110 ???1 ???? ???? ???? ???1 ????") | op2 << 5 | op1 << 21;
|
||||
bind(opcode, MoveToRegisterFromCoprocessor);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19) /* n */
|
||||
for(n5 _ : range(32)) {
|
||||
//undocumented instruction, equivalent to "mov rd, rn"
|
||||
auto opcode = pattern(".... 0011 0?00 ???? ???? ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4) << 22;
|
||||
bind(opcode, MoveToRegisterFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(n3 _ : range(8))
|
||||
for(n1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22;
|
||||
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- ???0 ----") | _ << 5 | mode << 22;
|
||||
bind(opcode, MoveToRegisterFromStatus);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -310,10 +362,14 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5, 6), /* type */ \
|
||||
opcode.bit( 7,11), /* shift */ \
|
||||
opcode.bit(16,19), /* field */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(n2 type : range(4))
|
||||
for(n1 shiftLo : range(2))
|
||||
for(n1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22;
|
||||
auto opcode = pattern(".... 0001 0?10 ???? ---- ???? ???0 ????") | type << 5 | shiftLo << 7 | mode << 22;
|
||||
bind(opcode, MoveToStatusFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -326,8 +382,9 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21) /* accumulate */
|
||||
for(n1 save : range(2))
|
||||
for(n1 accumulate : range(2)) {
|
||||
auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21;
|
||||
for(n1 accumulate : range(2))
|
||||
for(n1 _ : range(2)) {
|
||||
auto opcode = pattern(".... 0000 0??? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21 | _ << 22;
|
||||
bind(opcode, Multiply);
|
||||
}
|
||||
#undef arguments
|
||||
@@ -358,15 +415,28 @@ 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 {
|
||||
@@ -423,9 +493,9 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
||||
bind(opcode, AdjustStack, immediate, mode);
|
||||
}
|
||||
|
||||
for(n4 d : range(16))
|
||||
for(n4 _ : range(16))
|
||||
for(n4 m : range(16)) {
|
||||
auto opcode = pattern("0100 0111 ???? ?---") | d.bit(0,2) << 0 | m << 3 | d.bit(3) << 7;
|
||||
auto opcode = pattern("0100 0111 ???? ?---") | _.bit(0,2) << 0 | m << 3 | _.bit(3) << 7;
|
||||
bind(opcode, BranchExchange, m);
|
||||
}
|
||||
|
||||
@@ -446,6 +516,7 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
||||
|
||||
for(n8 displacement : range(256))
|
||||
for(n4 condition : range(16)) {
|
||||
if(condition == 14) continue; //BAL
|
||||
if(condition == 15) continue; //BNV
|
||||
auto opcode = pattern("1101 ???? ???? ????") | displacement << 0 | condition << 8;
|
||||
bind(opcode, BranchTest, displacement, condition);
|
||||
|
||||
@@ -24,24 +24,12 @@ auto ARM7TDMI::armALU(n4 mode, n4 d, n32 rn, n32 rm) -> void {
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armMoveToStatus(n4 field, n1 mode, n32 data) -> void {
|
||||
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
|
||||
PSR& psr = mode ? spsr() : cpsr();
|
||||
|
||||
if(field.bit(0)) {
|
||||
if(mode || privileged()) {
|
||||
psr.m = data.bit(0,4);
|
||||
psr.t = data.bit(5);
|
||||
psr.f = data.bit(6);
|
||||
psr.i = data.bit(7);
|
||||
if(!mode && psr.t) r(15).data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(field.bit(3)) {
|
||||
psr.v = data.bit(28);
|
||||
psr.c = data.bit(29);
|
||||
psr.z = data.bit(30);
|
||||
psr.n = data.bit(31);
|
||||
if(mode) {
|
||||
spsr().set(field, data);
|
||||
} else {
|
||||
if(!privileged()) field.bit(0) = 0;
|
||||
cpsr().set(field, data);
|
||||
if(cpsr().t) r(15).data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,10 +42,21 @@ auto ARM7TDMI::armInstructionBranch
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionBranchExchangeRegister
|
||||
(n4 m) -> void {
|
||||
(n4 m, n4 d, n4 field, n1 mode) -> void {
|
||||
n32 address = r(m);
|
||||
cpsr().t = address.bit(0);
|
||||
r(15) = address;
|
||||
if((field & 0b1001) == 0b1001) {
|
||||
PSR& psr = mode ? spsr() : cpsr();
|
||||
psr.t = address.bit(0);
|
||||
} else {
|
||||
armMoveToStatus(field, mode, address);
|
||||
}
|
||||
r(d) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionCoprocessorDataProcessing
|
||||
(n4 cm, n3 op2, n4 cpid, n4 cd, n4 cn, n4 op1) -> void {
|
||||
if(!CDP[cpid]) return armInstructionUndefined();
|
||||
CDP[cpid](cm, op2, cd, cn, op1);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionDataImmediate
|
||||
@@ -87,53 +86,28 @@ auto ARM7TDMI::armInstructionDataImmediateShift
|
||||
|
||||
auto ARM7TDMI::armInstructionDataRegisterShift
|
||||
(n4 m, n2 type, n4 s, n4 d, n4 n, n1 save, n4 mode) -> void {
|
||||
n8 rs = r(s) + (s == 15 ? 4 : 0);
|
||||
n8 rs = r(s);
|
||||
n32 rn = r(n) + (n == 15 ? 4 : 0);
|
||||
n32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||
carry = cpsr().c;
|
||||
|
||||
idle();
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, rs < 33 ? rs : (n8)33); break;
|
||||
case 1: rm = LSR(rm, rs < 33 ? rs : (n8)33); break;
|
||||
case 2: rm = ASR(rm, rs < 32 ? rs : (n8)32); break;
|
||||
case 3: if(rs) rm = ROR(rm, rs & 31 ? u32(rs & 31) : 32); break;
|
||||
case 0: rm = LSL(rm, rs); break;
|
||||
case 1: rm = LSR(rm, rs); break;
|
||||
case 2: rm = ASR(rm, rs); break;
|
||||
case 3: rm = ROR(rm, rs); break;
|
||||
}
|
||||
|
||||
armALU(mode, d, rn, rm);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadImmediate
|
||||
(n8 immediate, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadRegister
|
||||
(n4 m, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMemorySwap
|
||||
(n4 m, n4 d, n4 n, n1 byte) -> void {
|
||||
n32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||
lock();
|
||||
n32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
|
||||
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
|
||||
n32 word = load((byte ? Byte : Word), r(n));
|
||||
store((byte ? Byte : Word), r(n), rm);
|
||||
r(d) = word;
|
||||
unlock();
|
||||
}
|
||||
@@ -141,14 +115,14 @@ auto ARM7TDMI::armInstructionMemorySwap
|
||||
auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
(n8 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rd = r(d);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load(Half, rn);
|
||||
if(mode == 0) store(Half, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
@@ -156,14 +130,14 @@ auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
(n4 m, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load(Half, rn);
|
||||
if(mode == 0) store(Half, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
@@ -173,8 +147,8 @@ auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load((byte ? Byte : Word), rn);
|
||||
if(mode == 0) store((byte ? Byte : Word), rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
@@ -185,34 +159,32 @@ auto ARM7TDMI::armInstructionMoveMultiple
|
||||
(n16 list, n4 n, n1 mode, n1 writeback, n1 type, n1 up, n1 pre) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 bitCount = list ? bit::count(list) : 16;
|
||||
n32 rnEnd;
|
||||
if(up == 1) rnEnd = r(n) + bitCount * 4; //IA,IB
|
||||
if(up == 0) rnEnd = r(n) - bitCount * 4; //DA,DB
|
||||
if(pre == 0 && up == 1) rn = rn + 0; //IA
|
||||
if(pre == 1 && up == 1) rn = rn + 4; //IB
|
||||
if(pre == 1 && up == 0) rn = rn - bitCount * 4 + 0; //DB
|
||||
if(pre == 0 && up == 0) rn = rn - bitCount * 4 + 4; //DA
|
||||
|
||||
if(writeback && mode == 1 && !list.bit(n)) {
|
||||
if(up == 1) r(n) = r(n) + bitCount * 4; //IA,IB
|
||||
if(up == 0) r(n) = r(n) - bitCount * 4; //DA,DB
|
||||
}
|
||||
|
||||
auto cpsrMode = cpsr().m;
|
||||
bool usr = false;
|
||||
if(type && mode == 1 && !list.bit(15)) usr = true;
|
||||
if(type && mode == 0) usr = true;
|
||||
if(usr) cpsr().m = PSR::USR;
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(15) + 4);
|
||||
} else {
|
||||
for(u32 m : range(16)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(m) + (m == 15 ? 4 : 0));
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
if(writeback && mode == 1 && !list.bit(n)) r(n) = rnEnd;
|
||||
|
||||
endBurst();
|
||||
if(!list) list.bit(15) = 1;
|
||||
for(u32 m : range(16)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, rn);
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m) + (!(n == 15 && writeback) && m == 15 ? 4 : 0));
|
||||
if(writeback) r(n) = rnEnd; //writeback occurs after first access
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(usr) cpsr().m = cpsrMode;
|
||||
@@ -223,19 +195,14 @@ auto ARM7TDMI::armInstructionMoveMultiple
|
||||
cpsr() = spsr();
|
||||
}
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
}
|
||||
|
||||
if(writeback && mode == 0) {
|
||||
if(up == 1) r(n) = r(n) + bitCount * 4; //IA,IB
|
||||
if(up == 0) r(n) = r(n) - bitCount * 4; //DA,DB
|
||||
endBurst();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
(n4 m, n2 type, n5 shift, n4 d, n4 n, n1 mode, n1 writeback, n1 byte, n1 up, n1 pre) -> void {
|
||||
n32 rm = r(m);
|
||||
n32 rd = r(d);
|
||||
n32 rd = r(d) + (d == 15 ? 4 : 0);
|
||||
n32 rn = r(n);
|
||||
carry = cpsr().c;
|
||||
|
||||
@@ -247,14 +214,60 @@ auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
}
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
|
||||
if(mode == 1) rd = load((byte ? Byte : Word), rn);
|
||||
if(mode == 0) store((byte ? Byte : Word), rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
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) 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) 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
|
||||
(n4 d, n1 mode) -> void {
|
||||
r(d) = (mode && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) ? spsr() : cpsr();
|
||||
@@ -268,14 +281,25 @@ auto ARM7TDMI::armInstructionMoveToStatusFromImmediate
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToStatusFromRegister
|
||||
(n4 m, n4 field, n1 mode) -> void {
|
||||
armMoveToStatus(field, mode, r(m));
|
||||
(n4 m, n2 type, n5 shift, n4 field, n1 mode) -> void {
|
||||
n32 rm = r(m);
|
||||
carry = cpsr().c;
|
||||
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, shift); break;
|
||||
case 1: rm = LSR(rm, shift ? (u32)shift : 32); break;
|
||||
case 2: rm = ASR(rm, shift ? (u32)shift : 32); break;
|
||||
case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break;
|
||||
}
|
||||
|
||||
armMoveToStatus(field, mode, rm);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiply
|
||||
(n4 m, n4 s, n4 n, n4 d, n1 save, n1 accumulate) -> void {
|
||||
if(accumulate) idle();
|
||||
r(d) = MUL(accumulate ? r(n) : 0, r(m), r(s));
|
||||
n32 product = MUL(accumulate ? r(n) : 0, r(m), r(s));
|
||||
if(d != 15) r(d) = product;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiplyLong
|
||||
@@ -302,8 +326,8 @@ auto ARM7TDMI::armInstructionMultiplyLong
|
||||
n64 rd = rm * rs;
|
||||
if(accumulate) rd += (n64)r(h) << 32 | (n64)r(l) << 0;
|
||||
|
||||
r(l) = rd >> 0;
|
||||
r(h) = rd >> 32;
|
||||
if(l != 15) r(l) = rd >> 0;
|
||||
if(h != 15) r(h) = rd >> 32;
|
||||
|
||||
if(save) {
|
||||
cpsr().z = rd == 0;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
auto ARM7TDMI::thumbInstructionALU
|
||||
(n3 d, n3 m, n4 mode) -> void {
|
||||
carry = cpsr().c;
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(r(d) & r(m)); break; //AND
|
||||
case 1: r(d) = BIT(r(d) ^ r(m)); break; //EOR
|
||||
case 2: r(d) = BIT(LSL(r(d), r(m))); break; //LSL
|
||||
case 3: r(d) = BIT(LSR(r(d), r(m))); break; //LSR
|
||||
case 4: r(d) = BIT(ASR(r(d), r(m))); break; //ASR
|
||||
case 2: r(d) = BIT(LSL(r(d), r(m))); idle(); break; //LSL
|
||||
case 3: r(d) = BIT(LSR(r(d), r(m))); idle(); break; //LSR
|
||||
case 4: r(d) = BIT(ASR(r(d), r(m))); idle(); break; //ASR
|
||||
case 5: r(d) = ADD(r(d), r(m), cpsr().c); break; //ADC
|
||||
case 6: r(d) = SUB(r(d), r(m), cpsr().c); break; //SBC
|
||||
case 7: r(d) = BIT(ROR(r(d), r(m))); break; //ROR
|
||||
case 7: r(d) = BIT(ROR(r(d), r(m))); idle(); break; //ROR
|
||||
case 8: BIT(r(d) & r(m)); break; //TST
|
||||
case 9: r(d) = SUB(0, r(m), 1); break; //NEG
|
||||
case 10: SUB(r(d), r(m), 1); break; //CMP
|
||||
@@ -24,7 +25,7 @@ auto ARM7TDMI::thumbInstructionALUExtended
|
||||
(n4 d, n4 m, n2 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = r(d) + r(m); break; //ADD
|
||||
case 1: SUB(r(d), r(m), 1); break; //SUBS
|
||||
case 1: SUB(r(d), r(m), 1); break; //CMP
|
||||
case 2: r(d) = r(m); break; //MOV
|
||||
}
|
||||
}
|
||||
@@ -92,6 +93,7 @@ auto ARM7TDMI::thumbInstructionBranchTest
|
||||
|
||||
auto ARM7TDMI::thumbInstructionImmediate
|
||||
(n8 immediate, n3 d, n2 mode) -> void {
|
||||
carry = cpsr().c;
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(immediate); break; //MOV
|
||||
case 1: SUB(r(d), immediate, 1); break; //CMP
|
||||
@@ -103,81 +105,80 @@ auto ARM7TDMI::thumbInstructionImmediate
|
||||
auto ARM7TDMI::thumbInstructionLoadLiteral
|
||||
(n8 displacement, n3 d) -> void {
|
||||
n32 address = (r(15) & ~3) + (displacement << 2);
|
||||
r(d) = load(Word | Nonsequential, address);
|
||||
r(d) = load(Word, address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveByteImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Byte | Nonsequential, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte | Nonsequential, r(n) + offset); break; //LDRB
|
||||
case 0: store(Byte, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte, r(n) + offset); break; //LDRB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveHalfImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Half | Nonsequential, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half | Nonsequential, r(n) + offset * 2); break; //LDRH
|
||||
case 0: store(Half, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half, r(n) + offset * 2); break; //LDRH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveMultiple
|
||||
(n8 list, n3 n, n1 mode) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 bitCount = list ? bit::count(list) : 16;
|
||||
n16 rlist = list;
|
||||
n32 bitCount = rlist ? bit::count(rlist) : 16;
|
||||
n32 rnEnd = r(n) + bitCount * 4;
|
||||
|
||||
if(mode == 1 && !list.bit(n)) r(n) = r(n) + bitCount * 4;
|
||||
if(mode == 1 && !rlist.bit(n)) r(n) = rnEnd;
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(15) + 2);
|
||||
} else {
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn); //LDMIA
|
||||
if(mode == 0) write(Word | sequential, rn, r(m)); //STMIA
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
endBurst();
|
||||
if(!rlist) rlist.bit(15) = 1;
|
||||
for(u32 m : range(16)) {
|
||||
if(!rlist.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, rn); //LDMIA
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m) + (m == 15 ? 2 : 0)); //STMIA
|
||||
r(n) = rnEnd; //writeback occurs after first access
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(mode) {
|
||||
idle();
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
r(n) = r(n) + bitCount * 4;
|
||||
endBurst();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveRegisterOffset
|
||||
(n3 d, n3 n, n3 m, n3 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
|
||||
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
|
||||
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
|
||||
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
|
||||
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
|
||||
case 0: store(Word, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Signed, r(n) + r(m)); 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
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveStack
|
||||
(n8 immediate, n3 d, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(13) + immediate * 4); break; //LDR
|
||||
case 0: store(Word, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(13) + immediate * 4); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveWordImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(n) + offset * 4); break; //LDR
|
||||
case 0: store(Word, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(n) + offset * 4); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,33 +199,28 @@ auto ARM7TDMI::thumbInstructionSoftwareInterrupt
|
||||
auto ARM7TDMI::thumbInstructionStackMultiple
|
||||
(n8 list, n1 lrpc, n1 mode) -> void {
|
||||
n32 sp = r(13);
|
||||
n32 bitCount = (list | lrpc) ? (bit::count(list) + lrpc) : 16;
|
||||
n16 rlist = list;
|
||||
if(lrpc) {
|
||||
if(mode == 1) rlist.bit(15) = 1; //POP
|
||||
if(mode == 0) rlist.bit(14) = 1; //PUSH
|
||||
}
|
||||
n32 bitCount = rlist ? bit::count(rlist) : 16;
|
||||
if(mode == 1) r(13) = r(13) + bitCount * 4; //POP
|
||||
if(mode == 0) sp = sp - bitCount * 4 + 0; //PUSH
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
if(bitCount == 16) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(15) + 2); //PUSH
|
||||
} else {
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(m)); //PUSH
|
||||
sp += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
}
|
||||
if(lrpc) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(14)); //PUSH
|
||||
endBurst();
|
||||
if(!rlist) rlist.bit(15) = 1;
|
||||
for(u32 m : range(16)) {
|
||||
if(!rlist.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(m) + (m == 15 ? 2 : 0)); //PUSH
|
||||
sp += 4;
|
||||
}
|
||||
|
||||
if(mode) {
|
||||
idle();
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
r(13) = r(13) - bitCount * 4; //PUSH
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
auto ARM7TDMI::idle() -> void {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
sleep();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::read(u32 mode, n32 address) -> n32 {
|
||||
return get(mode, address);
|
||||
n32 word = get(mode, address);
|
||||
nonsequential = false; //allows burst transfer to continue
|
||||
return word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
auto word = get(Load | mode, address);
|
||||
if(mode & Half) {
|
||||
address &= 1;
|
||||
@@ -28,12 +30,13 @@ auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
|
||||
}
|
||||
|
||||
auto ARM7TDMI::write(u32 mode, n32 address, n32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
return set(mode, address, word);
|
||||
set(mode, address, word);
|
||||
nonsequential = false; //allows burst transfer to continue
|
||||
return;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::store(u32 mode, n32 address, n32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
endBurst();
|
||||
if(mode & Half) { word &= 0xffff; word |= word << 16; }
|
||||
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||
return set(Store | mode, address, word);
|
||||
|
||||
@@ -14,20 +14,24 @@ inline auto ARM7TDMI::r(n4 index) -> GPR& {
|
||||
case 11: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r11 : processor.r11;
|
||||
case 12: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r12 : processor.r12;
|
||||
case 13: switch(processor.cpsr.m) {
|
||||
case PSR::USR: return processor.r13;
|
||||
case PSR::FIQ: return processor.fiq.r13;
|
||||
case PSR::IRQ: return processor.irq.r13;
|
||||
case PSR::SVC: return processor.svc.r13;
|
||||
case PSR::ABT: return processor.abt.r13;
|
||||
case PSR::UND: return processor.und.r13;
|
||||
default: return processor.r13;
|
||||
case PSR::SYS: return processor.r13;
|
||||
default: return processor.rNULL;
|
||||
}
|
||||
case 14: switch(processor.cpsr.m) {
|
||||
case PSR::USR: return processor.r14;
|
||||
case PSR::FIQ: return processor.fiq.r14;
|
||||
case PSR::IRQ: return processor.irq.r14;
|
||||
case PSR::SVC: return processor.svc.r14;
|
||||
case PSR::ABT: return processor.abt.r14;
|
||||
case PSR::UND: return processor.und.r14;
|
||||
default: return processor.r14;
|
||||
case PSR::SYS: return processor.r14;
|
||||
default: return processor.rNULL;
|
||||
}
|
||||
case 15: return processor.r15;
|
||||
}
|
||||
@@ -46,7 +50,7 @@ inline auto ARM7TDMI::spsr() -> PSR& {
|
||||
case PSR::ABT: return processor.abt.spsr;
|
||||
case PSR::UND: return processor.und.spsr;
|
||||
}
|
||||
throw;
|
||||
return processor.spsrNULL;
|
||||
}
|
||||
|
||||
inline auto ARM7TDMI::privileged() const -> bool {
|
||||
|
||||
@@ -3,6 +3,7 @@ auto ARM7TDMI::serialize(serializer& s) -> void {
|
||||
s(pipeline);
|
||||
s(carry);
|
||||
s(irq);
|
||||
s(nonsequential);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
|
||||
@@ -23,6 +24,8 @@ auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
|
||||
s(r14.data);
|
||||
s(r15.data);
|
||||
s(cpsr);
|
||||
s(rNULL.data);
|
||||
s(spsrNULL);
|
||||
s(fiq.r8.data);
|
||||
s(fiq.r9.data);
|
||||
s(fiq.r10.data);
|
||||
@@ -54,11 +57,11 @@ auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
||||
s(c);
|
||||
s(z);
|
||||
s(n);
|
||||
s(readonly);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
||||
s(reload);
|
||||
s(nonsequential);
|
||||
s(fetch.address);
|
||||
s(fetch.instruction);
|
||||
s(fetch.thumb);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ auto SH2::internalReadByte(u32 address, n8 data) -> n8 {
|
||||
data.bit(5) = wdt.wtcsr.tme;
|
||||
data.bit(6) = wdt.wtcsr.wtit;
|
||||
data.bit(7) = wdt.wtcsr.ovf;
|
||||
if(wdt.wtcsr.wtit) debug(unimplemented, "SH2: wdt.wtit = 1");
|
||||
return data;
|
||||
|
||||
//WTCNT: watchdog timer counter
|
||||
|
||||
@@ -42,17 +42,20 @@ auto V30MZ::interrupt(u8 vector, InterruptSource source) -> bool {
|
||||
|
||||
auto V30MZ::interrupt(u8 vector) -> bool {
|
||||
state.halt = false;
|
||||
if(!PSW.IE) return false;
|
||||
if(!state.interrupt || !PSW.IE) return false;
|
||||
return interrupt(vector, InterruptSource::INT);
|
||||
}
|
||||
|
||||
auto V30MZ::nonMaskableInterrupt() -> bool {
|
||||
return interrupt(2, InterruptSource::NMI);
|
||||
auto V30MZ::nonMaskableInterrupt(bool value) -> bool {
|
||||
state.nmi = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define op(id, name, ...) case id: instruction##name(__VA_ARGS__); break;
|
||||
|
||||
auto V30MZ::instruction() -> void {
|
||||
state.brk = PSW.BRK;
|
||||
state.interrupt = PSW.IE;
|
||||
state.poll = 1;
|
||||
state.prefix = 0;
|
||||
if(state.halt) return wait(1);
|
||||
@@ -317,7 +320,8 @@ auto V30MZ::instruction() -> void {
|
||||
}
|
||||
|
||||
if(!state.prefix) prefixFlush();
|
||||
if(PSW.BRK) interrupt(1, InterruptSource::SingleStep);
|
||||
if(state.poll && state.nmi) interrupt(2, InterruptSource::NMI);
|
||||
if(state.poll && state.brk) interrupt(1, InterruptSource::SingleStep);
|
||||
}
|
||||
|
||||
#undef op
|
||||
@@ -105,7 +105,6 @@ auto V30MZ::instructionReturnInt() -> void {
|
||||
PS = pop();
|
||||
PSW = pop();
|
||||
flush();
|
||||
state.poll = 0;
|
||||
}
|
||||
|
||||
auto V30MZ::instructionInt3() -> void {
|
||||
@@ -182,7 +181,6 @@ auto V30MZ::instructionPushFlags() -> void {
|
||||
auto V30MZ::instructionPopFlags() -> void {
|
||||
wait(2);
|
||||
PSW = pop();
|
||||
state.poll = 0;
|
||||
}
|
||||
|
||||
auto V30MZ::instructionPushAll() -> void {
|
||||
|
||||
@@ -21,5 +21,4 @@ auto V30MZ::instructionClearFlag(u32 bit) -> void {
|
||||
auto V30MZ::instructionSetFlag(u32 bit) -> void {
|
||||
wait(4);
|
||||
PSW |= 1 << bit;
|
||||
if(bit == PSW.IE.bit()) state.poll = 0;
|
||||
}
|
||||
@@ -43,21 +43,27 @@ auto V30MZ::instructionUndefined1() -> void {
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionIn() -> void {
|
||||
wait(6);
|
||||
// TODO: The exact cycle on which I/O access is performed remains unknown.
|
||||
wait(5);
|
||||
setAccumulator<size>(in<size>(fetch<Byte>()));
|
||||
wait(1);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionOut() -> void {
|
||||
// TODO: The exact cycle on which I/O access is performed remains unknown.
|
||||
wait(6);
|
||||
out<size>(fetch<Byte>(), getAccumulator<size>());
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionInDW() -> void {
|
||||
wait(5);
|
||||
// TODO: The exact cycle on which I/O access is performed remains unknown.
|
||||
wait(4);
|
||||
setAccumulator<size>(in<size>(DW));
|
||||
wait(1);
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionOutDW() -> void {
|
||||
// TODO: The exact cycle on which I/O access is performed remains unknown.
|
||||
wait(5);
|
||||
out<size>(DW, getAccumulator<size>());
|
||||
}
|
||||
|
||||
@@ -14,14 +14,14 @@ auto V30MZ::instructionMoveMemSeg() -> void {
|
||||
wait(1);
|
||||
modRM();
|
||||
setMemory<Word>(getSegment());
|
||||
state.poll = 0;
|
||||
}
|
||||
|
||||
auto V30MZ::instructionMoveSegMem() -> void {
|
||||
wait(2);
|
||||
modRM();
|
||||
setSegment(getMemory<Word>());
|
||||
if((modrm.reg & 3) == 3) state.poll = 0;
|
||||
// delay interrupt polling if stack segment changed
|
||||
if((modrm.reg & 3) == 2) state.poll = 0;
|
||||
}
|
||||
|
||||
template<u32 size> auto V30MZ::instructionMoveAccMem() -> void {
|
||||
|
||||
@@ -2,6 +2,9 @@ auto V30MZ::serialize(serializer& s) -> void {
|
||||
s(state.halt);
|
||||
s(state.poll);
|
||||
s(state.prefix);
|
||||
s(state.interrupt);
|
||||
s(state.brk);
|
||||
s(state.nmi);
|
||||
|
||||
s(opcode);
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ auto V30MZ::power() -> void {
|
||||
state.halt = 0;
|
||||
state.poll = 1;
|
||||
state.prefix = 0;
|
||||
state.interrupt = 0;
|
||||
state.brk = 0;
|
||||
state.nmi = 0;
|
||||
|
||||
opcode = 0;
|
||||
prefixFlush();
|
||||
|
||||
@@ -41,7 +41,7 @@ struct V30MZ {
|
||||
//instruction.cpp
|
||||
auto prefixFlush() -> void;
|
||||
auto interrupt(u8 vector) -> bool;
|
||||
auto nonMaskableInterrupt() -> bool;
|
||||
auto nonMaskableInterrupt(bool value) -> bool;
|
||||
auto instruction() -> void;
|
||||
|
||||
//registers.cpp
|
||||
@@ -237,9 +237,12 @@ struct V30MZ {
|
||||
auto disassembleContext() -> string;
|
||||
|
||||
struct State {
|
||||
bool halt; //set to true for hlt instruction; blocks execution until next interrupt
|
||||
bool poll; //set to false to suppress interrupt polling between CPU instructions
|
||||
bool prefix; //set to true for prefix instructions; prevents flushing of Prefix struct
|
||||
bool halt; //set to true for hlt instruction; blocks execution until next interrupt
|
||||
bool poll; //set to false to suppress interrupt polling between CPU instructions
|
||||
bool prefix; //set to true for prefix instructions; prevents flushing of Prefix struct
|
||||
bool interrupt; //interrupt enable processor status before CPU instruction execution
|
||||
bool brk; //breakpoint enable processor status before CPU instruction execution
|
||||
bool nmi; //non-maskable interrupt requested
|
||||
} state;
|
||||
|
||||
u8 opcode;
|
||||
|
||||
@@ -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(array_span<u8>{data, size});
|
||||
|
||||
s(cs);
|
||||
s(sio);
|
||||
s(sck);
|
||||
s(inBuffer);
|
||||
s(outBuffer);
|
||||
s(shift);
|
||||
s(index);
|
||||
s(rwSelect);
|
||||
s(regSelect);
|
||||
s(cmdLatched);
|
||||
s(counter);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
ares.components += z80
|
||||
ares.components += tms9918
|
||||
ares.components += sn76489
|
||||
|
||||
ares.objects += ares-cv-cpu
|
||||
ares.objects += ares-cv-vdp
|
||||
ares.objects += ares-cv-psg
|
||||
ares.objects += ares-cv-system
|
||||
ares.objects += ares-cv-cartridge
|
||||
ares.objects += ares-cv-controller
|
||||
|
||||
$(object.path)/ares-cv-cpu.o: $(ares.path)/cv/cpu/cpu.cpp
|
||||
$(object.path)/ares-cv-vdp.o: $(ares.path)/cv/vdp/vdp.cpp
|
||||
$(object.path)/ares-cv-psg.o: $(ares.path)/cv/psg/psg.cpp
|
||||
$(object.path)/ares-cv-system.o: $(ares.path)/cv/system/system.cpp
|
||||
$(object.path)/ares-cv-cartridge.o: $(ares.path)/cv/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-cv-controller.o: $(ares.path)/cv/controller/controller.cpp
|
||||
@@ -56,6 +56,7 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
}
|
||||
|
||||
node = Node::System::create(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
ares.components += mos6502
|
||||
ares.components += ym2149
|
||||
ares.components += ym2413
|
||||
ares.components += m24c
|
||||
ares.components += sst39sf0x0
|
||||
|
||||
ares.objects += ares-fc-system
|
||||
ares.objects += ares-fc-controller
|
||||
ares.objects += ares-fc-expansion
|
||||
ares.objects += ares-fc-cartridge
|
||||
ares.objects += ares-fc-cpu
|
||||
ares.objects += ares-fc-apu
|
||||
ares.objects += ares-fc-ppu
|
||||
ares.objects += ares-fc-fds
|
||||
|
||||
$(object.path)/ares-fc-system.o: $(ares.path)/fc/system/system.cpp
|
||||
$(object.path)/ares-fc-controller.o: $(ares.path)/fc/controller/controller.cpp
|
||||
$(object.path)/ares-fc-expansion.o: $(ares.path)/fc/expansion/expansion.cpp
|
||||
$(object.path)/ares-fc-cartridge.o: $(ares.path)/fc/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-fc-cpu.o: $(ares.path)/fc/cpu/cpu.cpp
|
||||
$(object.path)/ares-fc-apu.o: $(ares.path)/fc/apu/apu.cpp
|
||||
$(object.path)/ares-fc-ppu.o: $(ares.path)/fc/ppu/ppu.cpp
|
||||
$(object.path)/ares-fc-fds.o: $(ares.path)/fc/fds/fds.cpp
|
||||
@@ -61,6 +61,7 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
}
|
||||
|
||||
node = Node::System::create(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
ares.components += sm83
|
||||
ares.components += m93lcx6
|
||||
|
||||
ares.objects += ares-gb-system
|
||||
ares.objects += ares-gb-bus
|
||||
ares.objects += ares-gb-cartridge
|
||||
ares.objects += ares-gb-cpu
|
||||
ares.objects += ares-gb-ppu
|
||||
ares.objects += ares-gb-apu
|
||||
|
||||
$(object.path)/ares-gb-system.o: $(ares.path)/gb/system/system.cpp
|
||||
$(object.path)/ares-gb-cartridge.o: $(ares.path)/gb/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-gb-bus.o: $(ares.path)/gb/bus/bus.cpp
|
||||
$(object.path)/ares-gb-cpu.o: $(ares.path)/gb/cpu/cpu.cpp
|
||||
$(object.path)/ares-gb-ppu.o: $(ares.path)/gb/ppu/ppu.cpp
|
||||
$(object.path)/ares-gb-apu.o: $(ares.path)/gb/apu/apu.cpp
|
||||
@@ -44,6 +44,7 @@ struct APU : Thread {
|
||||
n11 frequency;
|
||||
bool counter;
|
||||
|
||||
n4 sample;
|
||||
i16 output;
|
||||
bool dutyOutput;
|
||||
n3 phase;
|
||||
@@ -77,6 +78,7 @@ struct APU : Thread {
|
||||
n11 frequency;
|
||||
bool counter;
|
||||
|
||||
n4 sample;
|
||||
i16 output;
|
||||
bool dutyOutput;
|
||||
n3 phase;
|
||||
@@ -105,6 +107,7 @@ struct APU : Thread {
|
||||
bool counter;
|
||||
n8 pattern[16];
|
||||
|
||||
n4 sample;
|
||||
i16 output;
|
||||
u32 length;
|
||||
u32 period;
|
||||
@@ -135,6 +138,7 @@ struct APU : Thread {
|
||||
n3 divisor;
|
||||
bool counter;
|
||||
|
||||
n4 sample;
|
||||
i16 output;
|
||||
u32 length;
|
||||
n3 envelopePeriod;
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
auto APU::readIO(u32 cycle, n16 address, n8 data) -> n8 {
|
||||
if(Model::GameBoyColor()) {
|
||||
//PCM12
|
||||
if(address == 0xff76 && cycle == 2) {
|
||||
data.bit(0,3) = square1.sample;
|
||||
data.bit(4,7) = square2.sample;
|
||||
return data;
|
||||
}
|
||||
|
||||
//PCM34
|
||||
if(address == 0xff77 && cycle == 2) {
|
||||
data.bit(0,3) = wave.sample;
|
||||
data.bit(4,7) = noise.sample;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if(address < 0xff10 || address > 0xff3f) return data;
|
||||
|
||||
//NR10
|
||||
|
||||
@@ -16,7 +16,7 @@ auto APU::Noise::run() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
n4 sample = lfsr & 1 ? 0 : (u32)volume;
|
||||
sample = lfsr & 1 ? 0 : (u32)volume;
|
||||
if(!enable) sample = 0;
|
||||
|
||||
output = sample;
|
||||
@@ -79,6 +79,7 @@ auto APU::Noise::serialize(serializer& s) -> void {
|
||||
s(divisor);
|
||||
s(counter);
|
||||
|
||||
s(sample);
|
||||
s(output);
|
||||
s(length);
|
||||
s(envelopePeriod);
|
||||
|
||||
@@ -14,7 +14,7 @@ auto APU::Square1::run() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
n4 sample = dutyOutput ? (u32)volume : 0;
|
||||
sample = dutyOutput ? (u32)volume : 0;
|
||||
if(!enable) sample = 0;
|
||||
|
||||
output = sample;
|
||||
@@ -120,6 +120,7 @@ auto APU::Square1::serialize(serializer& s) -> void {
|
||||
s(frequency);
|
||||
s(counter);
|
||||
|
||||
s(sample);
|
||||
s(output);
|
||||
s(dutyOutput);
|
||||
s(phase);
|
||||
|
||||
@@ -14,7 +14,7 @@ auto APU::Square2::run() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
n4 sample = dutyOutput ? (u32)volume : 0;
|
||||
sample = dutyOutput ? (u32)volume : 0;
|
||||
if(!enable) sample = 0;
|
||||
|
||||
output = sample;
|
||||
@@ -77,6 +77,7 @@ auto APU::Square2::serialize(serializer& s) -> void {
|
||||
s(frequency);
|
||||
s(counter);
|
||||
|
||||
s(sample);
|
||||
s(output);
|
||||
s(dutyOutput);
|
||||
s(phase);
|
||||
|
||||
@@ -12,7 +12,7 @@ auto APU::Wave::run() -> void {
|
||||
}
|
||||
|
||||
static const u32 shift[] = {4, 0, 1, 2}; //0%, 100%, 50%, 25%
|
||||
n4 sample = patternSample >> shift[volume];
|
||||
sample = patternSample >> shift[volume];
|
||||
if(!enable) sample = 0;
|
||||
|
||||
output = sample;
|
||||
@@ -95,6 +95,7 @@ auto APU::Wave::serialize(serializer& s) -> void {
|
||||
s(counter);
|
||||
s(pattern);
|
||||
|
||||
s(sample);
|
||||
s(output);
|
||||
s(length);
|
||||
s(period);
|
||||
|
||||
+3
-3
@@ -61,9 +61,9 @@ auto CPU::unload() -> void {
|
||||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
if(status.hblankPending) {
|
||||
status.hblankPending = 0;
|
||||
hblankTrigger();
|
||||
if(ppu.status.ly < 144 && status.hdmaPending) {
|
||||
performHdma();
|
||||
status.hdmaPending = 0;
|
||||
}
|
||||
|
||||
//are interrupts enabled?
|
||||
|
||||
+8
-7
@@ -66,19 +66,20 @@ struct CPU : SM83, Thread {
|
||||
//timing.cpp
|
||||
auto step() -> void;
|
||||
auto step(u32 clocks) -> void;
|
||||
auto timer262144hz() -> void;
|
||||
auto timer65536hz() -> void;
|
||||
auto timer16384hz() -> void;
|
||||
auto timerTick() -> void;
|
||||
auto timer8192hz() -> void;
|
||||
auto timer4096hz() -> void;
|
||||
auto timer1024hz() -> void;
|
||||
auto hblank() -> void;
|
||||
auto hblankTrigger() -> void;
|
||||
auto hblankIn() -> void;
|
||||
auto hblankOut() -> void;
|
||||
auto hdmaTrigger(n1 hblank, n1 active) -> void;
|
||||
auto performHdma() -> void;
|
||||
|
||||
struct Status {
|
||||
n22 clock;
|
||||
n8 interruptLatch;
|
||||
n1 hblankPending;
|
||||
n1 hblank;
|
||||
n1 hdmaPending;
|
||||
n1 timerLine;
|
||||
|
||||
//$ff00 JOYP
|
||||
n4 joyp;
|
||||
|
||||
+3
-11
@@ -139,16 +139,6 @@ auto CPU::readIO(u32 cycle, n16 address, n8 data) -> n8 {
|
||||
return data;
|
||||
}
|
||||
|
||||
if(Model::GameBoyColor())
|
||||
if(address == 0xff76 && cycle == 2) { //???
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
if(Model::GameBoyColor())
|
||||
if(address == 0xff77 && cycle == 2) { //???
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
if(address == 0xffff && cycle == 2) { //IE
|
||||
return status.interruptEnable;
|
||||
}
|
||||
@@ -254,15 +244,17 @@ auto CPU::writeIO(u32 cycle, n16 address, n8 data) -> void {
|
||||
}
|
||||
|
||||
status.dmaLength = data.bit(0,6);
|
||||
hdmaTrigger(status.hblank, 1);
|
||||
status.hdmaActive = data.bit(7);
|
||||
|
||||
//GDMA
|
||||
if(!data.bit(7)) {
|
||||
step(4);
|
||||
do {
|
||||
for(u32 loop : range(16)) {
|
||||
writeDMA(status.dmaTarget++, readDMA(status.dmaSource++, 0xff));
|
||||
}
|
||||
step(8 << status.speedDouble);
|
||||
step(2 << status.speedDouble);
|
||||
} while(status.dmaLength--);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -7,7 +7,9 @@ auto CPU::serialize(serializer& s) -> void {
|
||||
|
||||
s(status.clock);
|
||||
s(status.interruptLatch);
|
||||
s(status.hblankPending);
|
||||
s(status.hblank);
|
||||
s(status.hdmaPending);
|
||||
s(status.timerLine);
|
||||
|
||||
s(status.joyp);
|
||||
s(status.p14);
|
||||
|
||||
+39
-50
@@ -7,14 +7,21 @@ auto CPU::step() -> void {
|
||||
}
|
||||
|
||||
auto CPU::step(u32 clocks) -> void {
|
||||
//determine which bit of DIV is used to check timer state
|
||||
n32 timerBit = 9;
|
||||
if(status.timerClock != 0) timerBit = status.timerClock * 2 + 1;
|
||||
|
||||
for(auto n : range(clocks)) {
|
||||
if(!r.stop) status.div++;
|
||||
if((n4 )status.div == 0) timer262144hz();
|
||||
if((n6 )status.div == 0) timer65536hz();
|
||||
if((n8 )status.div == 0) timer16384hz();
|
||||
if((n9 )status.div == 0) timer8192hz();
|
||||
if((n10)status.div == 0) timer4096hz();
|
||||
if((n12)status.div == 0) timer1024hz();
|
||||
|
||||
//tick timer on falling edge
|
||||
n1 timerLineNew = status.div.bit(timerBit) & status.timerEnable;
|
||||
if(timerLineNew == 0 && status.timerLine == 1) timerTick();
|
||||
|
||||
if((n9 )status.div == 0) timer8192hz(); //serial
|
||||
if((n12)status.div == 0) timer1024hz(); //joypad
|
||||
|
||||
status.timerLine = timerLineNew;
|
||||
|
||||
Thread::step(1);
|
||||
Thread::synchronize();
|
||||
@@ -25,30 +32,10 @@ auto CPU::step(u32 clocks) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::timer262144hz() -> void {
|
||||
if(status.timerEnable && status.timerClock == 1) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::timer65536hz() -> void {
|
||||
if(status.timerEnable && status.timerClock == 2) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::timer16384hz() -> void {
|
||||
if(status.timerEnable && status.timerClock == 3) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
auto CPU::timerTick() -> void {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,31 +50,33 @@ auto CPU::timer8192hz() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::timer4096hz() -> void {
|
||||
if(status.timerEnable && status.timerClock == 0) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::timer1024hz() -> void {
|
||||
joypPoll();
|
||||
}
|
||||
|
||||
auto CPU::hblank() -> void {
|
||||
status.hblankPending = 1;
|
||||
auto CPU::hblankIn() -> void {
|
||||
hdmaTrigger(1, status.hdmaActive);
|
||||
status.hblank = 1;
|
||||
}
|
||||
|
||||
auto CPU::hblankTrigger() -> void {
|
||||
if(status.hdmaActive && ppu.status.ly < 144) {
|
||||
for(u32 loop : range(16)) {
|
||||
writeDMA(status.dmaTarget++, readDMA(status.dmaSource++, 0xff));
|
||||
if(loop & 1) step(1 << status.speedDouble);
|
||||
}
|
||||
if(status.dmaLength-- == 0) {
|
||||
status.hdmaActive = 0;
|
||||
}
|
||||
auto CPU::hblankOut() -> void {
|
||||
status.hblank = 0;
|
||||
}
|
||||
|
||||
auto CPU::hdmaTrigger(n1 hblank, n1 active) -> void {
|
||||
//HDMA is triggered on rising edge of combined signal
|
||||
n1 previousState = status.hdmaActive && status.hblank;
|
||||
n1 newState = active && hblank;
|
||||
status.hdmaPending = previousState == 0 && newState == 1;
|
||||
}
|
||||
|
||||
auto CPU::performHdma() -> void {
|
||||
step(4);
|
||||
for(u32 loop : range(16)) {
|
||||
writeDMA(status.dmaTarget++, readDMA(status.dmaSource++, 0xff));
|
||||
step(2 << status.speedDouble);
|
||||
}
|
||||
if(status.dmaLength-- == 0) {
|
||||
status.hdmaActive = 0;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -103,7 +103,6 @@ auto PPU::main() -> void {
|
||||
step(172);
|
||||
|
||||
mode(0);
|
||||
cpu.hblank();
|
||||
step(456 - 8 - status.lx);
|
||||
} else if(status.ly <= 143) {
|
||||
mode(2);
|
||||
@@ -123,7 +122,6 @@ auto PPU::main() -> void {
|
||||
step(12);
|
||||
|
||||
mode(0);
|
||||
cpu.hblank();
|
||||
step(456 - status.lx);
|
||||
} else {
|
||||
mode(1);
|
||||
@@ -146,6 +144,9 @@ auto PPU::main() -> void {
|
||||
}
|
||||
|
||||
auto PPU::mode(n2 mode) -> void {
|
||||
if(mode == 0) cpu.hblankIn();
|
||||
if(mode != 0) cpu.hblankOut();
|
||||
|
||||
if(status.mode == 0 && mode != 0) {
|
||||
if(Model::SuperGameBoy()) superGameBoy->ppuHreset();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
static const string SerializerVersion = "v131";
|
||||
static const string SerializerVersion = "v144";
|
||||
|
||||
auto System::serialize(bool synchronize) -> serializer {
|
||||
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
||||
|
||||
@@ -58,6 +58,7 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
|
||||
if(information.name == "Game Boy" || information.name == "Game Boy Color") {
|
||||
node = Node::System::create(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
ares_components(arm7tdmi)
|
||||
ares_components(
|
||||
arm7tdmi
|
||||
s3511a
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
@@ -47,8 +50,10 @@ ares_add_sources(
|
||||
cartridge/cartridge.hpp
|
||||
cartridge/eeprom.cpp
|
||||
cartridge/flash.cpp
|
||||
cartridge/gpio.cpp
|
||||
cartridge/memory.hpp
|
||||
cartridge/mrom.cpp
|
||||
cartridge/rtc.cpp
|
||||
cartridge/serialization.cpp
|
||||
cartridge/slot.cpp
|
||||
cartridge/slot.hpp
|
||||
@@ -60,6 +65,7 @@ ares_add_sources(
|
||||
gba
|
||||
INCLUDED #
|
||||
cpu/bus.cpp
|
||||
cpu/coprocessor.cpp
|
||||
cpu/cpu.hpp
|
||||
cpu/debugger.cpp
|
||||
cpu/dma.cpp
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
ares.components += arm7tdmi
|
||||
|
||||
ares.objects += ares-gba-memory
|
||||
ares.objects += ares-gba-system
|
||||
ares.objects += ares-gba-cartridge
|
||||
ares.objects += ares-gba-player
|
||||
ares.objects += ares-gba-cpu
|
||||
ares.objects += ares-gba-ppu
|
||||
ares.objects += ares-gba-apu
|
||||
ares.objects += ares-gba-display
|
||||
|
||||
$(object.path)/ares-gba-memory.o: $(ares.path)/gba/memory/memory.cpp
|
||||
$(object.path)/ares-gba-system.o: $(ares.path)/gba/system/system.cpp
|
||||
$(object.path)/ares-gba-cartridge.o: $(ares.path)/gba/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-gba-player.o: $(ares.path)/gba/player/player.cpp
|
||||
$(object.path)/ares-gba-cpu.o: $(ares.path)/gba/cpu/cpu.cpp
|
||||
$(object.path)/ares-gba-ppu.o: $(ares.path)/gba/ppu/ppu.cpp
|
||||
$(object.path)/ares-gba-apu.o: $(ares.path)/gba/apu/apu.cpp
|
||||
$(object.path)/ares-gba-display.o: $(ares.path)/gba/display/display.cpp
|
||||
+10
-7
@@ -93,6 +93,7 @@ struct APU : Thread, IO {
|
||||
auto clockLength() -> void;
|
||||
auto read(u32 address) const -> n8;
|
||||
auto write(u32 address, n8 byte) -> void;
|
||||
auto freeBank() const -> n1;
|
||||
auto readRAM(u32 address) const -> n8;
|
||||
auto writeRAM(u32 address, n8 byte) -> void;
|
||||
auto power() -> void;
|
||||
@@ -169,17 +170,19 @@ struct APU : Thread, IO {
|
||||
//fifo.cpp
|
||||
auto sample() -> void;
|
||||
auto read() -> void;
|
||||
auto write(i8 byte) -> void;
|
||||
auto write(n2 address, n8 byte) -> void;
|
||||
auto reset() -> void;
|
||||
auto power() -> void;
|
||||
auto size() -> n3 { return wroffset - rdoffset; }
|
||||
|
||||
i8 samples[32];
|
||||
i8 active;
|
||||
i8 output;
|
||||
n32 buffer;
|
||||
n32 samples[8];
|
||||
i8 active;
|
||||
i8 output;
|
||||
|
||||
n5 rdoffset;
|
||||
n5 wroffset;
|
||||
n6 size;
|
||||
n3 rdoffset;
|
||||
n3 wroffset;
|
||||
n3 samplesRead;
|
||||
|
||||
n1 volume; //0 = 50%, 1 = 100%
|
||||
n1 lenable;
|
||||
|
||||
+13
-9
@@ -3,25 +3,29 @@ auto APU::FIFO::sample() -> void {
|
||||
}
|
||||
|
||||
auto APU::FIFO::read() -> void {
|
||||
if(size == 0) return;
|
||||
size--;
|
||||
active = samples[rdoffset++];
|
||||
if(samplesRead < 4) active = buffer.byte(samplesRead++);
|
||||
if(size() > 0) {
|
||||
if(samplesRead >= 4) {
|
||||
samplesRead = 0;
|
||||
buffer = samples[rdoffset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::FIFO::write(i8 byte) -> void {
|
||||
if(size == 32) rdoffset++;
|
||||
else size++;
|
||||
samples[wroffset++] = byte;
|
||||
auto APU::FIFO::write(n2 address, n8 byte) -> void {
|
||||
samples[wroffset].byte(address) = byte;
|
||||
if(address == 3) wroffset++;
|
||||
}
|
||||
|
||||
auto APU::FIFO::reset() -> void {
|
||||
for(auto& byte : samples) byte = 0;
|
||||
buffer = 0;
|
||||
for(auto& word : samples) word = 0;
|
||||
active = 0;
|
||||
output = 0;
|
||||
|
||||
rdoffset = 0;
|
||||
wroffset = 0;
|
||||
size = 0;
|
||||
samplesRead = 0;
|
||||
}
|
||||
|
||||
auto APU::FIFO::power() -> void {
|
||||
|
||||
+3
-2
@@ -146,6 +146,7 @@ auto APU::readIO(n32 address) -> n8 {
|
||||
}
|
||||
|
||||
auto APU::writeIO(n32 address, n8 data) -> void {
|
||||
if(!sequencer.masterenable && (address < 0x0400'0080 || address >= 0x0400'00a0)) return;
|
||||
cpu.synchronize(apu);
|
||||
|
||||
switch(address) {
|
||||
@@ -260,12 +261,12 @@ auto APU::writeIO(n32 address, n8 data) -> void {
|
||||
//FIFO_A_H
|
||||
case 0x0400'00a0: case 0x0400'00a1:
|
||||
case 0x0400'00a2: case 0x0400'00a3:
|
||||
return fifo[0].write(data);
|
||||
return fifo[0].write(address, data);
|
||||
|
||||
//FIFO_B_L
|
||||
//FIFO_B_H
|
||||
case 0x0400'00a4: case 0x0400'00a5:
|
||||
case 0x0400'00a6: case 0x0400'00a7:
|
||||
return fifo[1].write(data);
|
||||
return fifo[1].write(address, data);
|
||||
}
|
||||
}
|
||||
@@ -96,12 +96,13 @@ auto APU::serialize(serializer& s) -> void {
|
||||
s(sequencer.routput);
|
||||
|
||||
for(auto& f : fifo) {
|
||||
s(f.buffer);
|
||||
s(f.samples);
|
||||
s(f.active);
|
||||
s(f.output);
|
||||
s(f.rdoffset);
|
||||
s(f.wroffset);
|
||||
s(f.size);
|
||||
s(f.samplesRead);
|
||||
s(f.volume);
|
||||
s(f.lenable);
|
||||
s(f.renable);
|
||||
|
||||
@@ -65,16 +65,20 @@ auto APU::Wave::write(u32 address, n8 byte) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::Wave::freeBank() const -> n1 {
|
||||
return bank && apu.sequencer.masterenable;
|
||||
}
|
||||
|
||||
auto APU::Wave::readRAM(u32 address) const -> n8 {
|
||||
n8 byte = 0;
|
||||
byte |= pattern[!bank << 5 | address << 1 | 0] << 4;
|
||||
byte |= pattern[!bank << 5 | address << 1 | 1] << 0;
|
||||
byte |= pattern[freeBank() << 5 | address << 1 | 0] << 4;
|
||||
byte |= pattern[freeBank() << 5 | address << 1 | 1] << 0;
|
||||
return byte;
|
||||
}
|
||||
|
||||
auto APU::Wave::writeRAM(u32 address, n8 byte) -> void {
|
||||
pattern[!bank << 5 | address << 1 | 0] = byte >> 4;
|
||||
pattern[!bank << 5 | address << 1 | 1] = byte >> 0;
|
||||
pattern[freeBank() << 5 | address << 1 | 0] = byte >> 4;
|
||||
pattern[freeBank() << 5 | address << 1 | 1] = byte >> 0;
|
||||
}
|
||||
|
||||
auto APU::Wave::power() -> void {
|
||||
|
||||
@@ -8,17 +8,17 @@ Cartridge& cartridge = cartridgeSlot.cartridge;
|
||||
#include "sram.cpp"
|
||||
#include "eeprom.cpp"
|
||||
#include "flash.cpp"
|
||||
#include "gpio.cpp"
|
||||
#include "rtc.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
mrom.data = new n8[mrom.size = 32 * 1024 * 1024];
|
||||
sram.data = new n8[sram.size = 32 * 1024];
|
||||
eeprom.data = new n8[eeprom.size = 8 * 1024];
|
||||
flash.data = new n8[flash.size = 128 * 1024];
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
delete[] mrom.data;
|
||||
delete[] sram.data;
|
||||
delete[] eeprom.data;
|
||||
delete[] flash.data;
|
||||
@@ -37,7 +37,8 @@ auto Cartridge::connect() -> void {
|
||||
|
||||
if(auto fp = pak->read("program.rom")) {
|
||||
mrom.size = min(32_MiB, fp->size());
|
||||
fp->read({mrom.data, mrom.size});
|
||||
mrom.data.allocate(mrom.size >> 1);
|
||||
mrom.data.load(fp);
|
||||
mrom.mirror = pak->attribute("mirror").boolean();
|
||||
}
|
||||
|
||||
@@ -57,7 +58,7 @@ auto Cartridge::connect() -> void {
|
||||
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
||||
fp->read({eeprom.data, eeprom.size});
|
||||
if(!fp->end()) fp->read({eeprom.data, eeprom.size}); //only load save file if already present
|
||||
}
|
||||
|
||||
if(auto fp = pak->read("save.flash")) {
|
||||
@@ -75,15 +76,23 @@ auto Cartridge::connect() -> void {
|
||||
fp->read({flash.data, flash.size});
|
||||
}
|
||||
|
||||
if(auto fp = pak->read("time.rtc")) {
|
||||
has.rtc = true;
|
||||
for(auto n : range(rtc.size)) rtc.data[n] = 0x00;
|
||||
if(!fp->end()) fp->read({rtc.data, rtc.size}); //only load save file if already present
|
||||
rtc.load();
|
||||
}
|
||||
|
||||
power();
|
||||
}
|
||||
|
||||
auto Cartridge::disconnect() -> void {
|
||||
if(!node) return;
|
||||
memory::fill<u8>(mrom.data, mrom.size);
|
||||
mrom.data.reset();
|
||||
memory::fill<u8>(sram.data, sram.size);
|
||||
memory::fill<u8>(eeprom.data, eeprom.size);
|
||||
memory::fill<u8>(flash.data, flash.size);
|
||||
memory::fill<u8>(rtc.data, rtc.size);
|
||||
has = {};
|
||||
pak.reset();
|
||||
node.reset();
|
||||
@@ -104,39 +113,17 @@ auto Cartridge::save() -> void {
|
||||
if(auto fp = pak->write("save.flash")) {
|
||||
fp->write({flash.data, flash.size});
|
||||
}
|
||||
|
||||
if(auto fp = pak->write("time.rtc")) {
|
||||
rtc.save();
|
||||
fp->write({rtc.data, rtc.size});
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::power() -> void {
|
||||
eeprom.power();
|
||||
flash.power();
|
||||
}
|
||||
|
||||
#define RAM_ANALYZE
|
||||
|
||||
auto Cartridge::read(u32 mode, n32 address) -> n32 {
|
||||
if(address < 0x0e00'0000) {
|
||||
if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.read();
|
||||
return mrom.read(mode, address);
|
||||
} else {
|
||||
n32 word = 0xff;
|
||||
if(has.sram) word = sram.read(address);
|
||||
if(has.flash) word = flash.read(address);
|
||||
word |= word << 8;
|
||||
word |= word << 16;
|
||||
return word;
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::write(u32 mode, n32 address, n32 word) -> void {
|
||||
if(address < 0x0e00'0000) {
|
||||
if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
||||
return mrom.write(mode, address, word);
|
||||
} else {
|
||||
if(mode & Word) word = word >> (8 * (address & 3));
|
||||
if(mode & Half) word = word >> (8 * (address & 1));
|
||||
if(has.sram) return sram.write(address, word);
|
||||
if(has.flash) return flash.write(address, word);
|
||||
}
|
||||
if(has.rtc) rtc.power();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,8 +17,66 @@ struct Cartridge {
|
||||
auto save() -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto read(u32 mode, n32 address) -> n32;
|
||||
auto write(u32 mode, n32 address, n32 word) -> void;
|
||||
template<bool UseDebugger>
|
||||
auto readRom(u32 mode, n32 address) -> n32 {
|
||||
if(mode & Word) {
|
||||
n32 word = 0;
|
||||
word |= readRom<UseDebugger>(mode & ~Word | Half, (address & ~3) + 0) << 0;
|
||||
word |= readRom<UseDebugger>(Sequential | Half, (address & ~3) + 2) << 16;
|
||||
return word;
|
||||
}
|
||||
|
||||
if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.read();
|
||||
if(has.rtc) {
|
||||
if((address & 0x1fffffe) == 0xc4) return gpio.readData();
|
||||
if((address & 0x1fffffe) == 0xc6) return gpio.readDirection();
|
||||
if((address & 0x1fffffe) == 0xc8) return gpio.readControl();
|
||||
}
|
||||
|
||||
n32 romAddr;
|
||||
if constexpr(!UseDebugger) romAddr = mrom.burstAddr(mode, address);
|
||||
if constexpr( UseDebugger) romAddr = address & 0x1ff'fffe;
|
||||
n16 half = mrom.read(mode, romAddr);
|
||||
if constexpr(!UseDebugger) mrom.pageAddr++;
|
||||
|
||||
if(mode & Byte) return half.byte(address & 1);
|
||||
return half;
|
||||
}
|
||||
|
||||
auto readBackup(u32 mode, n32 address) -> n32 {
|
||||
n32 word = 0xff;
|
||||
if(has.sram) word = sram.read(address);
|
||||
if(has.flash) word = flash.read(address);
|
||||
word *= 0x01010101;
|
||||
return word;
|
||||
}
|
||||
|
||||
auto writeRom(u32 mode, n32 address, n32 word) -> void {
|
||||
if(mode & Word) {
|
||||
writeRom(mode & ~Word | Half, (address & ~3) + 0, word >> 0);
|
||||
writeRom(Sequential | Half, (address & ~3) + 2, word >> 16);
|
||||
}
|
||||
|
||||
if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
||||
|
||||
if(has.rtc) {
|
||||
if((address & 0x1fffffe) == 0xc4) return gpio.writeData(word);
|
||||
if((address & 0x1fffffe) == 0xc6) return gpio.writeDirection(word);
|
||||
if((address & 0x1fffffe) == 0xc8) return gpio.writeControl(word);
|
||||
}
|
||||
|
||||
n32 romAddr = mrom.burstAddr(mode, address);
|
||||
mrom.write(mode, romAddr, word);
|
||||
mrom.pageAddr++;
|
||||
return;
|
||||
}
|
||||
|
||||
auto writeBackup(u32 mode, n32 address, n32 word) -> void {
|
||||
if(mode & Word) word = word >> (8 * (address & 3));
|
||||
if(mode & Half) word = word >> (8 * (address & 1));
|
||||
if(has.sram) return sram.write(address, word);
|
||||
if(has.flash) return flash.write(address, word);
|
||||
}
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
@@ -31,6 +89,7 @@ private:
|
||||
n1 sram;
|
||||
n1 eeprom;
|
||||
n1 flash;
|
||||
n1 rtc;
|
||||
} has;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
auto Cartridge::GPIO::readData() -> n4 {
|
||||
if(!readEnable) return 0;
|
||||
|
||||
cpu.synchronize(cartridge.rtc);
|
||||
n4 data = latch & direction;
|
||||
if(!direction.bit(1)) data.bit(1) = cartridge.rtc.readSIO();
|
||||
return data;
|
||||
}
|
||||
|
||||
auto Cartridge::GPIO::readDirection() -> n4 {
|
||||
if(!readEnable) return 0;
|
||||
return direction;
|
||||
}
|
||||
|
||||
auto Cartridge::GPIO::readControl() -> n1 {
|
||||
return readEnable;
|
||||
}
|
||||
|
||||
auto Cartridge::GPIO::writeData(n4 data) -> void {
|
||||
cpu.synchronize(cartridge.rtc);
|
||||
latch = data;
|
||||
if(direction.bit(0)) cartridge.rtc.writeSCK(latch >> 0);
|
||||
if(direction.bit(2)) cartridge.rtc.writeCS( latch >> 2);
|
||||
if(direction.bit(1)) cartridge.rtc.writeSIO(latch >> 1);
|
||||
}
|
||||
|
||||
auto Cartridge::GPIO::writeDirection(n4 data) -> void {
|
||||
direction = data;
|
||||
}
|
||||
|
||||
auto Cartridge::GPIO::writeControl(n1 data) -> void {
|
||||
readEnable = data;
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
struct MROM {
|
||||
//mrom.cpp
|
||||
auto read(u32 mode, n32 address) -> n32;
|
||||
auto readBus(u32 mode, n32 address) -> n16;
|
||||
auto write(u32 mode, n32 address, n32 word) -> void;
|
||||
auto read(u32 mode, n32 address) -> n16;
|
||||
auto write(u32 mode, n32 address, n16 half) -> void;
|
||||
auto burstAddr(u32 mode, n32 address) -> n32;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
n8* data = nullptr;
|
||||
Memory::Readable<n16> data;
|
||||
u32 size;
|
||||
u32 mask;
|
||||
n16 pageAddr;
|
||||
n1 burst;
|
||||
bool mirror;
|
||||
} mrom;
|
||||
|
||||
@@ -76,3 +78,33 @@ struct FLASH {
|
||||
bool writeselect;
|
||||
bool bank;
|
||||
} flash;
|
||||
|
||||
struct GPIO {
|
||||
//gpio.cpp
|
||||
auto readData() -> n4;
|
||||
auto readDirection() -> n4;
|
||||
auto readControl() -> n1;
|
||||
auto writeData(n4 data) -> void;
|
||||
auto writeDirection(n4 data) -> void;
|
||||
auto writeControl(n1 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
n4 latch;
|
||||
n4 direction;
|
||||
n1 readEnable;
|
||||
} gpio;
|
||||
|
||||
struct RTC : S3511A, Thread {
|
||||
//rtc.cpp
|
||||
auto irqLevel(bool value) -> void override;
|
||||
auto power() -> void;
|
||||
auto main() -> void;
|
||||
auto step(u32 clocks) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool irq;
|
||||
} rtc;
|
||||
+20
-22
@@ -1,28 +1,26 @@
|
||||
auto Cartridge::MROM::read(u32 mode, n32 address) -> n32 {
|
||||
if(mode & Word) {
|
||||
n32 word = 0;
|
||||
word |= readBus(mode & ~Word | Half, (address & ~3) + 0) << 0;
|
||||
word |= readBus(mode & ~Word | Half, (address & ~3) + 2) << 16;
|
||||
return word;
|
||||
}
|
||||
|
||||
return readBus(mode, address);
|
||||
}
|
||||
|
||||
auto Cartridge::MROM::readBus(u32 mode, n32 address) -> n16 {
|
||||
address &= 0x01ff'ffff;
|
||||
|
||||
auto Cartridge::MROM::read(u32 mode, n32 address) -> n16 {
|
||||
//out-of-bounds accesses
|
||||
if(address >= size) {
|
||||
if(!mirror) return (n16)(address >> 1);
|
||||
address &= size - 1;
|
||||
if(!mirror) return pageAddr;
|
||||
address &= (size - 1);
|
||||
}
|
||||
|
||||
if(mode & Half) address &= ~1;
|
||||
auto p = data + address;
|
||||
if(mode & Half) return p[0] << 0 | p[1] << 8;
|
||||
if(mode & Byte) return p[0] << 0;
|
||||
return 0; //should never occur
|
||||
return data[address >> 1];
|
||||
}
|
||||
|
||||
auto Cartridge::MROM::write(u32 mode, n32 address, n32 word) -> void {
|
||||
auto Cartridge::MROM::write(u32 mode, n32 address, n16 half) -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::MROM::burstAddr(u32 mode, n32 address) -> n32 {
|
||||
//use latched lower 16 bits of address lines if sequential
|
||||
n8 page = address >> 17;
|
||||
if(mode & Nonsequential) {
|
||||
pageAddr = address >> 1;
|
||||
burst = true;
|
||||
}
|
||||
|
||||
//end burst transfer if requesting last address on page
|
||||
if((address & 0x1fffe) == 0x1fffe) burst = false;
|
||||
|
||||
return (page << 17) | (pageAddr << 1);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
auto Cartridge::RTC::irqLevel(bool value) -> void {
|
||||
//trigger IRQ on rising edge
|
||||
bool irqPrev = irq;
|
||||
irq = value;
|
||||
if(!irqPrev && irq) cpu.setInterruptFlag(CPU::Interrupt::Cartridge);
|
||||
}
|
||||
|
||||
auto Cartridge::RTC::power() -> void {
|
||||
S3511A::power();
|
||||
Thread::create(32'768, {&Cartridge::RTC::main, this});
|
||||
}
|
||||
|
||||
auto Cartridge::RTC::main() -> void {
|
||||
if(++counter == 0) tickSecond();
|
||||
checkAlarm();
|
||||
step(1);
|
||||
}
|
||||
|
||||
auto Cartridge::RTC::step(u32 clocks) -> void {
|
||||
Thread::step(clocks);
|
||||
synchronize(cpu);
|
||||
}
|
||||
@@ -3,11 +3,15 @@ auto Cartridge::serialize(serializer& s) -> void {
|
||||
if(has.sram) s(sram);
|
||||
if(has.eeprom) s(eeprom);
|
||||
if(has.flash) s(flash);
|
||||
if(has.rtc) s(gpio);
|
||||
if(has.rtc) s(rtc);
|
||||
}
|
||||
|
||||
auto Cartridge::MROM::serialize(serializer& s) -> void {
|
||||
s(size);
|
||||
s(mask);
|
||||
s(pageAddr);
|
||||
s(burst);
|
||||
}
|
||||
|
||||
auto Cartridge::SRAM::serialize(serializer& s) -> void {
|
||||
@@ -40,3 +44,15 @@ auto Cartridge::FLASH::serialize(serializer& s) -> void {
|
||||
s(writeselect);
|
||||
s(bank);
|
||||
}
|
||||
|
||||
auto Cartridge::GPIO::serialize(serializer& s) -> void {
|
||||
s(latch);
|
||||
s(direction);
|
||||
s(readEnable);
|
||||
}
|
||||
|
||||
auto Cartridge::RTC::serialize(serializer& s) -> void {
|
||||
S3511A::serialize(s);
|
||||
Thread::serialize(s);
|
||||
s(irq);
|
||||
}
|
||||
+50
-10
@@ -43,19 +43,31 @@ inline auto CPU::getBus(u32 mode, n32 address) -> n32 {
|
||||
word = ppu.readOAM(mode, address);
|
||||
break;
|
||||
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d:
|
||||
if constexpr(UseDebugger) return cartridge.readRom<true>(mode, address);
|
||||
mode = cartMode(mode, address);
|
||||
context.romAccess = true;
|
||||
if(mode & Prefetch && wait.prefetch) {
|
||||
if(mode & Word) address &= ~3; //prevents misaligned PC from reading incorrect values
|
||||
if(mode & Nonsequential && prefetch.cycle == 0 && prefetch.empty()) prefetchReset();
|
||||
prefetchSync(address);
|
||||
prefetchStep(1);
|
||||
word = prefetchRead();
|
||||
if(mode & Word) word |= prefetchRead() << 16;
|
||||
} else {
|
||||
if constexpr(!UseDebugger) prefetchReset();
|
||||
if constexpr(!UseDebugger) step(waitCartridge(mode, address));
|
||||
word = cartridge.read(mode, address);
|
||||
if(context.dmaActive) context.dmaRomAccess = true;
|
||||
prefetchReset();
|
||||
step(waitCartridge(mode, address));
|
||||
word = cartridge.readRom<false>(mode, address);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0e: case 0x0f:
|
||||
if constexpr(!UseDebugger) prefetchReset();
|
||||
if constexpr(!UseDebugger) step(waitCartridge(mode, address));
|
||||
word = cartridge.readBackup(mode, address);
|
||||
break;
|
||||
|
||||
default:
|
||||
if constexpr(!UseDebugger) prefetchStep(1);
|
||||
return openBus.get(mode, address);
|
||||
@@ -71,7 +83,10 @@ inline auto CPU::getBus(u32 mode, n32 address) -> n32 {
|
||||
auto CPU::get(u32 mode, n32 address) -> n32 {
|
||||
dmaRun();
|
||||
ARM7TDMI::irq = irq.synchronizer;
|
||||
return getBus<false>(mode, address);
|
||||
context.romAccess = false;
|
||||
u32 word = getBus<false>(mode, address);
|
||||
if(!context.romAccess && !context.dmaActive) cartridge.mrom.burst = false;
|
||||
return word;
|
||||
}
|
||||
|
||||
auto CPU::getDebugger(u32 mode, n32 address) -> n32 {
|
||||
@@ -81,6 +96,7 @@ auto CPU::getDebugger(u32 mode, n32 address) -> n32 {
|
||||
auto CPU::set(u32 mode, n32 address, n32 word) -> void {
|
||||
dmaRun();
|
||||
ARM7TDMI::irq = irq.synchronizer;
|
||||
context.romAccess = false;
|
||||
|
||||
if(memory.biosSwap && address < 0x0400'0000) address ^= 0x0200'0000;
|
||||
|
||||
@@ -117,10 +133,19 @@ auto CPU::set(u32 mode, n32 address, n32 word) -> void {
|
||||
ppu.writeOAM(mode, address, word);
|
||||
break;
|
||||
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d:
|
||||
mode = cartMode(mode, address);
|
||||
context.romAccess = true;
|
||||
if(context.dmaActive) context.dmaRomAccess = true;
|
||||
prefetchReset();
|
||||
step(waitCartridge(mode, address));
|
||||
cartridge.write(mode, address, word);
|
||||
cartridge.writeRom(mode, address, word);
|
||||
break;
|
||||
|
||||
case 0x0e: case 0x0f:
|
||||
prefetchReset();
|
||||
step(waitCartridge(mode, address));
|
||||
cartridge.writeBackup(mode, address, word);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -130,6 +155,7 @@ auto CPU::set(u32 mode, n32 address, n32 word) -> void {
|
||||
}
|
||||
|
||||
openBus.set(mode, address, word);
|
||||
if(!context.romAccess && !context.dmaActive) cartridge.mrom.burst = false;
|
||||
}
|
||||
|
||||
auto CPU::lock() -> void {
|
||||
@@ -158,13 +184,27 @@ auto CPU::waitCartridge(u32 mode, n32 address) -> u32 {
|
||||
}
|
||||
|
||||
bool sequential = (mode & Sequential);
|
||||
if((address & 0x1fffe) == 0) sequential = false; //N cycle on 16-bit ROM crossing 128KB page boundary (RAM S==N)
|
||||
|
||||
u32 clocks = sequential ? s : n;
|
||||
u32 clocks = (mode & Sequential) ? s : n;
|
||||
if(mode & Word) clocks += s; //16-bit bus requires two transfers for words
|
||||
return clocks;
|
||||
}
|
||||
|
||||
auto CPU::cartMode(u32 mode, n32 address) -> u32 {
|
||||
//if no burst transfer is active, start a new burst transfer
|
||||
if(cartridge.mrom.burst == false) return mode | Nonsequential;
|
||||
|
||||
//determine whether sequential access may be performed
|
||||
if(!context.dmaActive) {
|
||||
u32 sequential = nonsequential ? Nonsequential : Sequential;
|
||||
mode |= sequential;
|
||||
} else {
|
||||
u32 sequential = context.dmaRomAccess ? Sequential : Nonsequential;
|
||||
mode |= sequential;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
auto CPU::OpenBus::get(u32 mode, n32 address) -> n32 {
|
||||
if(mode & Word) address &= ~3;
|
||||
if(mode & Half) address &= ~1;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
auto CPU::Coprocessor::vcCDP() -> void {
|
||||
static bool warnVC = false;
|
||||
if(!warnVC) {
|
||||
warnVC = true;
|
||||
print("Warning: CP0 instruction executed. This likely signifies a Virtual Console ROM which may not function correctly on real hardware.\n");
|
||||
}
|
||||
cpu.armInstructionUndefined();
|
||||
}
|
||||
|
||||
auto CPU::Coprocessor::debugMCR() -> void {
|
||||
return;
|
||||
}
|
||||
|
||||
auto CPU::Coprocessor::debugMRC() -> n32 {
|
||||
return cpu.openBus.get(Word, 0);
|
||||
}
|
||||
+23
-8
@@ -10,6 +10,7 @@ CPU cpu;
|
||||
#include "dma.cpp"
|
||||
#include "timer.cpp"
|
||||
#include "keypad.cpp"
|
||||
#include "coprocessor.cpp"
|
||||
#include "debugger.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
@@ -45,7 +46,7 @@ auto CPU::main() -> void {
|
||||
if(halted()) {
|
||||
dmaRun();
|
||||
if(!(irq.enable[0] & irq.flag[0])) {
|
||||
return step(4);
|
||||
return step(1);
|
||||
}
|
||||
step(2);
|
||||
context.halted = false;
|
||||
@@ -58,11 +59,18 @@ auto CPU::main() -> void {
|
||||
auto CPU::dmaRun() -> void {
|
||||
if(!context.dmaActive && !context.busLocked) {
|
||||
context.dmaActive = true;
|
||||
while(dma[0].run() | dma[1].run() | dma[2].run() | dma[3].run());
|
||||
while(true) {
|
||||
if(dma[0].run()) continue;
|
||||
if(dma[1].run()) continue;
|
||||
if(dma[2].run()) continue;
|
||||
if(dma[3].run()) continue;
|
||||
break;
|
||||
}
|
||||
if(context.dmaRan) {
|
||||
idle();
|
||||
context.dmaRan = false;
|
||||
context.dmaRomAccess = false;
|
||||
context.dmaActiveChannel = 0; //assign burst to a channel that cannot access ROM
|
||||
}
|
||||
context.dmaActive = false;
|
||||
}
|
||||
@@ -73,14 +81,17 @@ auto CPU::setInterruptFlag(u32 source) -> void {
|
||||
}
|
||||
|
||||
inline auto CPU::stepIRQ() -> void {
|
||||
irq.synchronizer = irq.ime[0] && (irq.enable[0] & irq.flag[0]);
|
||||
irq.enable[0] = irq.enable[1];
|
||||
irq.flag[0] = irq.flag[1];
|
||||
irq.ime[0] = irq.ime[1];
|
||||
if(!context.dmaActive) {
|
||||
irq.synchronizer = irq.ime[0] && (irq.enable[0] & irq.flag[0]);
|
||||
irq.enable[0] = irq.enable[1];
|
||||
irq.flag[0] = irq.flag[1];
|
||||
irq.ime[0] = irq.ime[1];
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::step(u32 clocks) -> void {
|
||||
if(!clocks) return;
|
||||
context.hcounter = (context.hcounter + clocks) % 1232;
|
||||
|
||||
dma[0].waiting = max(0, dma[0].waiting - (s32)clocks);
|
||||
dma[1].waiting = max(0, dma[1].waiting - (s32)clocks);
|
||||
@@ -110,11 +121,11 @@ auto CPU::step(u32 clocks) -> void {
|
||||
Thread::step(clocks);
|
||||
Thread::synchronize(display, player);
|
||||
|
||||
//occasionally synchronize with PPU and APU in case CPU has not recently interacted with them
|
||||
//occasionally perform a full sync in case CPU has not recently interacted with some component
|
||||
static u32 counter = 0;
|
||||
counter += clocks;
|
||||
if(counter >= 1024) {
|
||||
Thread::synchronize(ppu, apu);
|
||||
Thread::synchronize();
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
@@ -123,6 +134,10 @@ auto CPU::power() -> void {
|
||||
ARM7TDMI::power();
|
||||
Thread::create(system.frequency(), {&CPU::main, this});
|
||||
|
||||
bindCDP( 0, [&](n4 cm, n3 op2, n4 cd, n4 cn, n4 op1) { return coprocessor.vcCDP(); });
|
||||
bindMCR(14, [&](n32 data, n4 cm, n3 op2, n4 cn, n3 op1) { return coprocessor.debugMCR(); });
|
||||
bindMRC(14, [&](n4 cm, n3 op2, n4 cn, n3 op1) { return coprocessor.debugMRC(); });
|
||||
|
||||
for(auto& byte : iwram) byte = 0x00;
|
||||
for(auto& byte : ewram) byte = 0x00;
|
||||
|
||||
|
||||
+16
-4
@@ -68,6 +68,7 @@ struct CPU : ARM7TDMI, Thread, IO {
|
||||
auto unlock() -> void override;
|
||||
auto waitEWRAM(u32 mode) -> u32;
|
||||
auto waitCartridge(u32 mode, n32 address) -> u32;
|
||||
auto cartMode(u32 mode, n32 address) -> u32;
|
||||
|
||||
//io.cpp
|
||||
auto readIO(n32 address) -> n8 override;
|
||||
@@ -249,22 +250,33 @@ struct CPU : ARM7TDMI, Thread, IO {
|
||||
auto size() const { return (load - addr) >> 1; }
|
||||
|
||||
n16 slot[8];
|
||||
n32 addr; //read location of slot buffer
|
||||
n32 load; //write location of slot buffer
|
||||
i32 wait = 1; //number of clocks before next slot load
|
||||
n32 addr; //read location of slot buffer
|
||||
n32 load; //write location of slot buffer
|
||||
i32 wait = 1; //wait states for current load
|
||||
i32 cycle; //number of clocks elapsed on current load
|
||||
n1 stopped = 1;
|
||||
} prefetch;
|
||||
|
||||
struct Coprocessor {
|
||||
//coprocessor.cpp
|
||||
auto vcCDP() -> void;
|
||||
auto debugMCR() -> void;
|
||||
auto debugMRC() -> n32;
|
||||
} coprocessor;
|
||||
|
||||
struct Context {
|
||||
n32 clock;
|
||||
n1 halted;
|
||||
n1 stopped;
|
||||
n1 booted; //set to true by the GBA BIOS
|
||||
n1 dmaRan;
|
||||
n1 romAccess;
|
||||
n1 dmaRomAccess;
|
||||
n1 dmaRan;
|
||||
n1 dmaActive;
|
||||
n2 dmaActiveChannel;
|
||||
n1 timerLatched;
|
||||
n1 busLocked;
|
||||
n32 hcounter;
|
||||
} context;
|
||||
};
|
||||
|
||||
|
||||
+6
-11
@@ -10,39 +10,34 @@ inline auto CPU::DMA::run() -> bool {
|
||||
auto CPU::DMA::transfer() -> void {
|
||||
u32 seek = size ? 4 : 2;
|
||||
u32 mode = size ? Word : Half;
|
||||
mode |= latch.length() == length() ? Nonsequential : Sequential;
|
||||
|
||||
if(!cpu.context.dmaRan) {
|
||||
cpu.context.dmaRan = true;
|
||||
cpu.idle();
|
||||
}
|
||||
|
||||
if(cpu.context.dmaActiveChannel != id) {
|
||||
//channel has switched - new burst transfer must be started
|
||||
cpu.context.dmaRomAccess = 0;
|
||||
cpu.context.dmaActiveChannel = id;
|
||||
}
|
||||
|
||||
if(latch.source() < 0x0200'0000) {
|
||||
cpu.idle(); //cannot access BIOS
|
||||
} else {
|
||||
n32 addr = latch.source();
|
||||
if(mode & Word) addr &= ~3;
|
||||
if(mode & Half) addr &= ~1;
|
||||
if(addr & 0x0800'0000) cpu.context.dmaRomAccess = true;
|
||||
latch.data = cpu.get(mode, addr);
|
||||
if(mode & Half) latch.data |= latch.data << 16;
|
||||
}
|
||||
|
||||
if(mode & Nonsequential) {
|
||||
if((source() & 0x0800'0000) && (target() & 0x0800'0000)) {
|
||||
//ROM -> ROM transfer
|
||||
mode |= Sequential;
|
||||
mode ^= Nonsequential;
|
||||
}
|
||||
}
|
||||
|
||||
if(latch.target() < 0x0200'0000) {
|
||||
cpu.idle(); //cannot access BIOS
|
||||
} else {
|
||||
n32 addr = latch.target();
|
||||
if(mode & Word) addr &= ~3;
|
||||
if(mode & Half) addr &= ~1;
|
||||
if(addr & 0x0800'0000) cpu.context.dmaRomAccess = true;
|
||||
cpu.set(mode, addr, latch.data >> (addr & 2) * 8);
|
||||
}
|
||||
|
||||
|
||||
+13
-10
@@ -1,47 +1,50 @@
|
||||
auto CPU::prefetchSync(n32 address) -> void {
|
||||
if(address == prefetch.addr) return;
|
||||
|
||||
if(prefetch.wait == 1) step(1);
|
||||
if(prefetch.wait - prefetch.cycle == 1) step(1);
|
||||
|
||||
prefetch.stopped = false;
|
||||
prefetch.addr = address;
|
||||
prefetch.load = address;
|
||||
prefetch.wait = waitCartridge(Half | Nonsequential, prefetch.load);
|
||||
prefetch.cycle = 0;
|
||||
}
|
||||
|
||||
auto CPU::prefetchStep(u32 clocks) -> void {
|
||||
step(clocks);
|
||||
if(!wait.prefetch || context.dmaRomAccess || prefetch.stopped) return;
|
||||
if(!wait.prefetch || prefetch.stopped) return;
|
||||
|
||||
while(!prefetch.full() && clocks--) {
|
||||
if(--prefetch.wait) continue;
|
||||
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load);
|
||||
prefetch.cycle++;
|
||||
if(prefetch.wait > prefetch.cycle) continue;
|
||||
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.readRom<false>(Half | Nonsequential, prefetch.load); //todo: make access sequentiality consistent with timing used
|
||||
prefetch.load += 2;
|
||||
prefetch.wait = waitCartridge(Half | Sequential, prefetch.load);
|
||||
prefetch.cycle = 0;
|
||||
}
|
||||
|
||||
if(prefetch.full()) prefetch.stopped = true;
|
||||
}
|
||||
|
||||
auto CPU::prefetchReset() -> void {
|
||||
if(prefetch.wait == 1) step(1);
|
||||
if(prefetch.wait - prefetch.cycle == 1) step(1);
|
||||
|
||||
prefetch.stopped = true;
|
||||
prefetch.wait = 0;
|
||||
prefetch.addr = 0;
|
||||
prefetch.load = 0;
|
||||
prefetch.cycle = 0;
|
||||
}
|
||||
|
||||
auto CPU::prefetchRead() -> n16 {
|
||||
if(prefetch.empty()) prefetchStep(prefetch.wait);
|
||||
|
||||
n16 word = prefetch.slot[prefetch.addr >> 1 & 7];
|
||||
prefetch.addr += 2;
|
||||
|
||||
if(prefetch.stopped && prefetch.empty()) {
|
||||
prefetch.stopped = false;
|
||||
prefetch.wait = waitCartridge(Half | Nonsequential, prefetch.load);
|
||||
prefetch.cycle = 0;
|
||||
}
|
||||
if(prefetch.empty()) prefetchStep(prefetch.wait - prefetch.cycle);
|
||||
|
||||
n16 word = prefetch.slot[prefetch.addr >> 1 & 7];
|
||||
prefetch.addr += 2;
|
||||
return word;
|
||||
}
|
||||
@@ -107,15 +107,19 @@ auto CPU::serialize(serializer& s) -> void {
|
||||
s(prefetch.addr);
|
||||
s(prefetch.load);
|
||||
s(prefetch.wait);
|
||||
s(prefetch.cycle);
|
||||
s(prefetch.stopped);
|
||||
|
||||
s(context.clock);
|
||||
s(context.halted);
|
||||
s(context.stopped);
|
||||
s(context.booted);
|
||||
s(context.dmaRan);
|
||||
s(context.romAccess);
|
||||
s(context.dmaRomAccess);
|
||||
s(context.dmaRan);
|
||||
s(context.dmaActive);
|
||||
s(context.dmaActiveChannel);
|
||||
s(context.timerLatched);
|
||||
s(context.busLocked);
|
||||
s(context.hcounter);
|
||||
}
|
||||
@@ -57,7 +57,7 @@ auto CPU::Timer::step() -> void {
|
||||
auto CPU::runFIFO(u32 n) -> void {
|
||||
synchronize(apu);
|
||||
apu.fifo[n].read();
|
||||
if(apu.fifo[n].size > 16) return;
|
||||
if(apu.fifo[n].size() > 3) return;
|
||||
|
||||
auto& dma = this->dma[1 + n];
|
||||
if(dma.enable && dma.timingMode == 3) {
|
||||
|
||||
+6
-5
@@ -4,6 +4,7 @@
|
||||
#include <ares/ares.hpp>
|
||||
|
||||
#include <component/processor/arm7tdmi/arm7tdmi.hpp>
|
||||
#include <component/rtc/s3511a/s3511a.hpp>
|
||||
|
||||
namespace ares::GameBoyAdvance {
|
||||
#include <ares/inline.hpp>
|
||||
@@ -12,15 +13,15 @@ namespace ares::GameBoyAdvance {
|
||||
auto option(string name, string value) -> bool;
|
||||
|
||||
enum : u32 { //mode flags for bus read, write:
|
||||
Nonsequential = 1, //N cycle
|
||||
Sequential = 2, //S cycle
|
||||
Load = 1, //load operation
|
||||
Store = 2, //store operation
|
||||
Prefetch = 4, //instruction fetch (eligible for prefetch)
|
||||
Byte = 8, //8-bit access
|
||||
Half = 16, //16-bit access
|
||||
Word = 32, //32-bit access
|
||||
Load = 64, //load operation
|
||||
Store = 128, //store operation
|
||||
Signed = 256, //sign extended
|
||||
Signed = 64, //sign extended
|
||||
Nonsequential = 128, //N cycle
|
||||
Sequential = 256, //S cycle
|
||||
};
|
||||
|
||||
struct Model {
|
||||
|
||||
Loaded 100 of 4569 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user