mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-10 09:21:41 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
@@ -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
|
||||
|
||||
@@ -21,9 +21,8 @@ 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
|
||||
|
||||
|
||||
+94
-252
@@ -1,10 +1,12 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags: [ 'v*' ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_call:
|
||||
inputs:
|
||||
codesign:
|
||||
description: Enable codesigning
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -12,53 +14,57 @@ 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: mingw-w64-clang-x86_64-clang
|
||||
target-cmake-preset: windows-ci-mingw-native
|
||||
- name: windows-x64-gcc
|
||||
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
|
||||
compiler: g++
|
||||
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
|
||||
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
|
||||
compiler: clang++
|
||||
windres: llvm-rc
|
||||
windres: rc
|
||||
shell: bash
|
||||
msvc-arch: x64
|
||||
target-cmake-preset: windows-ci-msvc-native
|
||||
- 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-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: sh
|
||||
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:
|
||||
@@ -70,247 +76,83 @@ jobs:
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.platform.msystem }}
|
||||
install: make ${{ matrix.platform.install }}
|
||||
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: ${{ secrets.MACOS_CERTIFICATE_NAME == '' }}
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
|
||||
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
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: Linux"
|
||||
if: runner.os == 'Linux'
|
||||
run: .github/scripts/build_ubuntu.sh
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_KEYCHAIN_NAME: ares-macos-keychain
|
||||
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
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' && 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 }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
|
||||
- name: Upload
|
||||
- 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@v4
|
||||
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@v4
|
||||
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@v4
|
||||
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/*
|
||||
@@ -12,6 +12,6 @@ concurrency:
|
||||
jobs:
|
||||
build-project:
|
||||
name: Build
|
||||
uses: ./.github/workflows/build_new.yml
|
||||
uses: ./.github/workflows/build.yml
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -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
|
||||
@@ -11,7 +9,7 @@ permissions:
|
||||
jobs:
|
||||
build:
|
||||
name: Build ares
|
||||
uses: ./.github/workflows/build_new.yml
|
||||
uses: ./.github/workflows/build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
codesign: true
|
||||
|
||||
@@ -19,6 +19,15 @@ jobs:
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: 'bin'
|
||||
- name: "Decompress Build Artifacts"
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
for package in macos-universal windows-x64 windows-clang-cl-x64 windows-clang-cl-arm64; do
|
||||
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 }}
|
||||
|
||||
+4
-4
@@ -26,10 +26,6 @@
|
||||
!CMakeLists.txt
|
||||
!CMakePresets.json
|
||||
|
||||
thirdparty/SDL/SDL
|
||||
thirdparty/SDL/libSDL2-2.0.0.dylib
|
||||
desktop-ui/out
|
||||
desktop-ui/obj
|
||||
ruby/video/metal/shaders.metallib
|
||||
ruby/video/metal/shaders.ir
|
||||
ares/ares/resource/resource.cpp
|
||||
@@ -38,5 +34,9 @@ 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
|
||||
tests/arm7tdmi/tests
|
||||
tests/m68000/tests
|
||||
thirdparty/libchdr/deps/zlib-*/zconf.h
|
||||
thirdparty/libchdr/deps/zlib-*/zconf.h.included
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-1
@@ -81,7 +81,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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
+3
-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(
|
||||
|
||||
@@ -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
|
||||
@@ -9,13 +9,13 @@ namespace ares {
|
||||
Platform* platform = nullptr;
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
build := stable
|
||||
nall.path := ../../../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
all:
|
||||
sourcery resource.bml resource.cpp resource.hpp
|
||||
|
||||
clean:
|
||||
$(call delete,resource.cpp)
|
||||
$(call delete,resource.hpp)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,34 +0,0 @@
|
||||
namespace Resource {
|
||||
namespace Ares {
|
||||
extern const unsigned char Icon1x[6562];
|
||||
extern const unsigned char Icon2x[9662];
|
||||
extern const unsigned char Logo1x[11533];
|
||||
extern const unsigned char Logo2x[18991];
|
||||
}
|
||||
namespace Sprite {
|
||||
namespace SuperFamicom {
|
||||
extern const unsigned char CrosshairBlue[332];
|
||||
extern const unsigned char CrosshairGreen[329];
|
||||
extern const unsigned char CrosshairRed[342];
|
||||
}
|
||||
namespace WonderSwan {
|
||||
extern const unsigned char Auxiliary0[117];
|
||||
extern const unsigned char Auxiliary1[134];
|
||||
extern const unsigned char Auxiliary2[136];
|
||||
extern const unsigned char Headphones[167];
|
||||
extern const unsigned char Initialized[136];
|
||||
extern const unsigned char LowBattery[144];
|
||||
extern const unsigned char Orientation0[148];
|
||||
extern const unsigned char Orientation1[150];
|
||||
extern const unsigned char PoweredOn[155];
|
||||
extern const unsigned char Sleeping[154];
|
||||
extern const unsigned char VolumeA0[129];
|
||||
extern const unsigned char VolumeA1[142];
|
||||
extern const unsigned char VolumeA2[146];
|
||||
extern const unsigned char VolumeB0[125];
|
||||
extern const unsigned char VolumeB1[137];
|
||||
extern const unsigned char VolumeB2[148];
|
||||
extern const unsigned char VolumeB3[153];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,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;
|
||||
|
||||
@@ -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;
|
||||
@@ -221,7 +220,6 @@ struct ARM7TDMI {
|
||||
};
|
||||
|
||||
n1 reload = 1;
|
||||
n1 nonsequential = 1;
|
||||
Instruction fetch;
|
||||
Instruction decode;
|
||||
Instruction execute;
|
||||
@@ -230,6 +228,7 @@ struct ARM7TDMI {
|
||||
n32 opcode;
|
||||
b1 carry;
|
||||
b1 irq;
|
||||
b1 nonsequential;
|
||||
|
||||
function<void (n32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ auto ARM7TDMI::armDisassembleDataRegisterShift
|
||||
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,
|
||||
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte),
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
@@ -150,7 +150,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 +173,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 ? "]" : "",
|
||||
@@ -276,7 +276,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 +308,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 +340,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)};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ auto ARM7TDMI::reload() -> void {
|
||||
u32 size = !cpsr().t ? Word : Half;
|
||||
|
||||
pipeline.reload = false;
|
||||
endBurst();
|
||||
r(15).data &= ~mask;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
|
||||
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
|
||||
@@ -16,18 +17,12 @@ 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.instruction = read(Prefetch | size, pipeline.fetch.address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::instruction() -> void {
|
||||
|
||||
@@ -29,7 +29,7 @@ auto ARM7TDMI::armMoveToStatus(n4 field, n1 mode, n32 data) -> void {
|
||||
|
||||
if(field.bit(0)) {
|
||||
if(mode || privileged()) {
|
||||
psr.m = data.bit(0,4);
|
||||
psr.m = data.bit(0,4) | 0x10;
|
||||
psr.t = data.bit(5);
|
||||
psr.f = data.bit(6);
|
||||
psr.i = data.bit(7);
|
||||
@@ -87,11 +87,12 @@ 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;
|
||||
@@ -108,10 +109,10 @@ auto ARM7TDMI::armInstructionLoadImmediate
|
||||
n32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
rd = load((half ? Half : Byte) | Signed, rn);
|
||||
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);
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
@@ -122,18 +123,19 @@ auto ARM7TDMI::armInstructionLoadRegister
|
||||
n32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
rd = load((half ? Half : Byte) | Signed, rn);
|
||||
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);
|
||||
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 +143,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 +158,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 +175,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,33 +187,44 @@ 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(writeback && mode == 1 && !list.bit(n)) r(n) = rnEnd;
|
||||
|
||||
endBurst();
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(15) + 4);
|
||||
if(mode == 1) r(15) = read(Word, rn);
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(15) + 4);
|
||||
//writeback occurs after first access
|
||||
if(writeback) r(n) = rnEnd;
|
||||
}
|
||||
} else {
|
||||
bool wroteBack = false;
|
||||
for(u32 m : range(16)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(m) + (m == 15 ? 4 : 0));
|
||||
if(mode == 1) r(m) = read(Word, rn);
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m) + (!(n == 15 && writeback) && m == 15 ? 4 : 0));
|
||||
if(!wroteBack && writeback) {
|
||||
//writeback occurs after first access
|
||||
r(n) = rnEnd;
|
||||
wroteBack = true;
|
||||
}
|
||||
}
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,19 +236,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,8 +255,8 @@ 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;
|
||||
@@ -275,7 +283,8 @@ auto ARM7TDMI::armInstructionMoveToStatusFromRegister
|
||||
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 +311,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,22 +105,22 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,58 +128,69 @@ auto ARM7TDMI::thumbInstructionMoveMultiple
|
||||
(n8 list, n3 n, n1 mode) -> void {
|
||||
n32 rn = r(n);
|
||||
n32 bitCount = list ? bit::count(list) : 16;
|
||||
n32 rnEnd = r(n) + bitCount * 4;
|
||||
|
||||
if(mode == 1 && !list.bit(n)) r(n) = r(n) + bitCount * 4;
|
||||
if(mode == 1 && !list.bit(n)) r(n) = rnEnd;
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
endBurst();
|
||||
if(!list) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(15) + 2);
|
||||
if(mode == 1) r(15) = read(Word, rn);
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(15) + 2);
|
||||
//writeback occurs after first access
|
||||
r(n) = rnEnd;
|
||||
}
|
||||
} else {
|
||||
bool wroteBack = false;
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn); //LDMIA
|
||||
if(mode == 0) write(Word | sequential, rn, r(m)); //STMIA
|
||||
if(mode == 1) r(m) = read(Word, rn); //LDMIA
|
||||
if(mode == 0) {
|
||||
write(Word, rn, r(m)); //STMIA
|
||||
//writeback occurs after first access
|
||||
if(!wroteBack) {
|
||||
r(n) = rnEnd;
|
||||
wroteBack = true;
|
||||
}
|
||||
}
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,29 +215,28 @@ auto ARM7TDMI::thumbInstructionStackMultiple
|
||||
if(mode == 1) r(13) = r(13) + bitCount * 4; //POP
|
||||
if(mode == 0) sp = sp - bitCount * 4 + 0; //PUSH
|
||||
|
||||
u32 sequential = Nonsequential;
|
||||
endBurst();
|
||||
if(bitCount == 16) {
|
||||
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(15) + 2); //PUSH
|
||||
if(mode == 1) r(15) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(15) + 2); //PUSH
|
||||
} else {
|
||||
for(u32 m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, sp); //POP
|
||||
if(mode == 0) write(Word | sequential, sp, r(m)); //PUSH
|
||||
if(mode == 1) r(m) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, 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
|
||||
if(mode == 1) r(15) = read(Word, sp); //POP
|
||||
if(mode == 0) write(Word, sp, r(14)); //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);
|
||||
|
||||
@@ -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 {
|
||||
@@ -58,7 +59,6 @@ auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
||||
|
||||
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
||||
s(reload);
|
||||
s(nonsequential);
|
||||
s(fetch.address);
|
||||
s(fetch.instruction);
|
||||
s(fetch.thumb);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
+2
-4
@@ -66,11 +66,8 @@ 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;
|
||||
@@ -79,6 +76,7 @@ struct CPU : SM83, Thread {
|
||||
n22 clock;
|
||||
n8 interruptLatch;
|
||||
n1 hblankPending;
|
||||
n1 timerLine;
|
||||
|
||||
//$ff00 JOYP
|
||||
n4 joyp;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ auto CPU::serialize(serializer& s) -> void {
|
||||
s(status.clock);
|
||||
s(status.interruptLatch);
|
||||
s(status.hblankPending);
|
||||
s(status.timerLine);
|
||||
|
||||
s(status.joyp);
|
||||
s(status.p14);
|
||||
|
||||
+17
-39
@@ -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,15 +50,6 @@ 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();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
static const string SerializerVersion = "v131";
|
||||
static const string SerializerVersion = "v143.1";
|
||||
|
||||
auto System::serialize(bool synchronize) -> serializer {
|
||||
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
||||
|
||||
@@ -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
|
||||
@@ -11,14 +11,12 @@ Cartridge& cartridge = cartridgeSlot.cartridge;
|
||||
#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 +35,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();
|
||||
}
|
||||
|
||||
@@ -80,7 +79,7 @@ auto Cartridge::connect() -> void {
|
||||
|
||||
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);
|
||||
@@ -111,32 +110,4 @@ auto Cartridge::power() -> void {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,8 +17,55 @@ 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();
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+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);
|
||||
}
|
||||
@@ -8,6 +8,8 @@ auto Cartridge::serialize(serializer& s) -> void {
|
||||
auto Cartridge::MROM::serialize(serializer& s) -> void {
|
||||
s(size);
|
||||
s(mask);
|
||||
s(pageAddr);
|
||||
s(burst);
|
||||
}
|
||||
|
||||
auto Cartridge::SRAM::serialize(serializer& s) -> void {
|
||||
|
||||
+48
-10
@@ -43,19 +43,29 @@ 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) {
|
||||
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 +81,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 +94,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 +131,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 +153,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 +182,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;
|
||||
|
||||
@@ -58,11 +58,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;
|
||||
}
|
||||
@@ -81,6 +88,7 @@ inline auto CPU::stepIRQ() -> void {
|
||||
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
@@ -260,11 +261,14 @@ struct CPU : ARM7TDMI, Thread, IO {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ auto CPU::prefetchSync(n32 address) -> void {
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
@@ -113,9 +113,12 @@ auto CPU::serialize(serializer& s) -> void {
|
||||
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);
|
||||
}
|
||||
+5
-5
@@ -12,15 +12,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 {
|
||||
|
||||
+66
-59
@@ -12,6 +12,7 @@ auto PPU::Background::setEnable(n1 status) -> void {
|
||||
auto PPU::Background::scanline(u32 y) -> void {
|
||||
mosaicOffset = 0;
|
||||
for(auto& pixel : output) pixel = {};
|
||||
latch.active = false;
|
||||
}
|
||||
|
||||
auto PPU::Background::outputPixel(u32 x, u32 y) -> void {
|
||||
@@ -23,47 +24,64 @@ auto PPU::Background::outputPixel(u32 x, u32 y) -> void {
|
||||
mosaicOffset--;
|
||||
}
|
||||
|
||||
auto PPU::Background::run(u32 x, u32 y) -> void {
|
||||
auto PPU::Background::run(s32 x, u32 y) -> void {
|
||||
switch(id) {
|
||||
case PPU::BG0:
|
||||
if(io.mode <= 1) { linear(x, y); break; }
|
||||
if(io.mode <= 1) { linearFetchTileMap(x, y); linearRender(x, y); break; }
|
||||
break;
|
||||
|
||||
case PPU::BG1:
|
||||
if(io.mode <= 1) { linear(x, y); break; }
|
||||
if(io.mode <= 1) { linearFetchTileMap(x, y); linearRender(x, y); break; }
|
||||
break;
|
||||
|
||||
case PPU::BG2:
|
||||
if(io.mode == 0) { linear(x, y); break; }
|
||||
if(io.mode == 0) { linearFetchTileMap(x, y); linearRender(x, y); break; }
|
||||
if(io.mode <= 2) { affineFetchTileMap(x, y); affineFetchTileData(x, y); break; }
|
||||
if(io.mode <= 5) { bitmap(x, y); break; }
|
||||
break;
|
||||
|
||||
case PPU::BG3:
|
||||
if(io.mode == 0) { linear(x, y); break; }
|
||||
if(io.mode == 0) { linearFetchTileMap(x, y); linearRender(x, y); break; }
|
||||
if(io.mode == 2) { affineFetchTileMap(x, y); affineFetchTileData(x, y); break; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Background::linearFetchTileMap() -> void {
|
||||
n6 tx = fx >> 3;
|
||||
n6 ty = fy >> 3;
|
||||
auto PPU::Background::linearFetchTileMap(s32 x, u32 y) -> void {
|
||||
if(ppu.blank() || !io.enable[0]) return;
|
||||
|
||||
u32 offset = (ty & 31) << 5 | (tx & 31);
|
||||
if(io.screenSize.bit(0) && (tx & 32)) offset += 32 << 5;
|
||||
if(io.screenSize.bit(1) && (ty & 32)) offset += 32 << 5 + io.screenSize.bit(0);
|
||||
offset = (io.screenBase << 11) + (offset << 1);
|
||||
if(x == -7) {
|
||||
if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) {
|
||||
vmosaic = y;
|
||||
}
|
||||
}
|
||||
|
||||
n16 tilemap = ppu.readVRAM_BG(Half, offset);
|
||||
latch.character = tilemap.bit(0,9);
|
||||
latch.hflip = tilemap.bit(10);
|
||||
latch.vflip = tilemap.bit(11);
|
||||
latch.palette = tilemap.bit(12,15);
|
||||
fx = x + io.hoffset;
|
||||
fy = vmosaic + io.voffset;
|
||||
|
||||
n3 px = fx;
|
||||
if(px == 0) {
|
||||
//fetch tilemap
|
||||
n6 tx = fx >> 3;
|
||||
n6 ty = fy >> 3;
|
||||
|
||||
u32 offset = (ty & 31) << 5 | (tx & 31);
|
||||
if(io.screenSize.bit(0) && (tx & 32)) offset += 32 << 5;
|
||||
if(io.screenSize.bit(1) && (ty & 32)) offset += 32 << 5 + io.screenSize.bit(0);
|
||||
offset = (io.screenBase << 11) + (offset << 1);
|
||||
|
||||
n16 tilemap = ppu.readVRAM_BG(Half, offset);
|
||||
latch.character = tilemap.bit(0,9);
|
||||
latch.hflip = tilemap.bit(10);
|
||||
latch.vflip = tilemap.bit(11);
|
||||
latch.palette = tilemap.bit(12,15);
|
||||
latch.active = true;
|
||||
latch.px = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Background::linearFetchTileData() -> void {
|
||||
n3 px = fx;
|
||||
n3 px = latch.px;
|
||||
n3 py = fy;
|
||||
if(latch.hflip) px = ~px;
|
||||
if(latch.vflip) py = ~py;
|
||||
@@ -75,29 +93,13 @@ auto PPU::Background::linearFetchTileData() -> void {
|
||||
latch.data = ppu.readVRAM_BG(Half, offset);
|
||||
}
|
||||
|
||||
auto PPU::Background::linear(u32 x, u32 y) -> void {
|
||||
if(x > 239) return;
|
||||
auto PPU::Background::linearRender(s32 x, u32 y) -> void {
|
||||
if(ppu.blank() || !io.enable[0]) return;
|
||||
if(!latch.active) return;
|
||||
|
||||
if(x == 0) {
|
||||
if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) {
|
||||
vmosaic = y;
|
||||
}
|
||||
fx = io.hoffset;
|
||||
fy = vmosaic + io.voffset;
|
||||
}
|
||||
n3 px = latch.px;
|
||||
|
||||
n3 px = fx;
|
||||
n3 py = fy;
|
||||
|
||||
if(x == 0 || px == 0) linearFetchTileMap();
|
||||
if(x == 0) {
|
||||
linearFetchTileData();
|
||||
} else if(io.colorMode == 0 && (px & 3) == 0) {
|
||||
linearFetchTileData();
|
||||
} else if(io.colorMode == 1 && (px & 1) == 0) {
|
||||
linearFetchTileData();
|
||||
}
|
||||
if(((px << io.colorMode) & 3) == 0) linearFetchTileData();
|
||||
|
||||
if(latch.hflip) px = ~px;
|
||||
|
||||
@@ -111,17 +113,18 @@ auto PPU::Background::linear(u32 x, u32 y) -> void {
|
||||
}
|
||||
|
||||
if(color) {
|
||||
if(io.colorMode == 0) color |= latch.palette << 4;
|
||||
output[x].enable = true;
|
||||
output[x].priority = io.priority;
|
||||
output[x].color = color;
|
||||
if(x >= 0 && x < 240) {
|
||||
if(io.colorMode == 0) color |= latch.palette << 4;
|
||||
output[x].enable = true;
|
||||
output[x].priority = io.priority;
|
||||
output[x].color = color;
|
||||
}
|
||||
}
|
||||
|
||||
fx++;
|
||||
if(++latch.px == 0) latch.active = false;
|
||||
}
|
||||
|
||||
auto PPU::Background::affineFetchTileMap(u32 x, u32 y) -> void {
|
||||
if(x > 239) return;
|
||||
if(ppu.blank() || !io.enable[0]) return;
|
||||
|
||||
if(x == 0) {
|
||||
@@ -146,16 +149,19 @@ auto PPU::Background::affineFetchTileMap(u32 x, u32 y) -> void {
|
||||
}
|
||||
|
||||
auto PPU::Background::affineFetchTileData(u32 x, u32 y) -> void {
|
||||
if(x > 239) return;
|
||||
if(ppu.blank() || !io.enable[0]) return;
|
||||
|
||||
n3 px = affine.cx;
|
||||
n3 py = affine.cy;
|
||||
n8 color = ppu.readVRAM_BG(Byte, (io.characterBase << 14) + (affine.character << 6) + (py << 3) + px);
|
||||
|
||||
if(affine.tx < affine.screenSize && affine.ty < affine.screenSize) {
|
||||
n3 px = affine.cx;
|
||||
n3 py = affine.cy;
|
||||
if(n8 color = ppu.readVRAM_BG(Byte, (io.characterBase << 14) + (affine.character << 6) + (py << 3) + px)) {
|
||||
output[x].enable = true;
|
||||
output[x].priority = io.priority;
|
||||
output[x].color = color;
|
||||
if(color) {
|
||||
if(x < 240) {
|
||||
output[x].enable = true;
|
||||
output[x].priority = io.priority;
|
||||
output[x].color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +175,6 @@ auto PPU::Background::affineFetchTileData(u32 x, u32 y) -> void {
|
||||
}
|
||||
|
||||
auto PPU::Background::bitmap(u32 x, u32 y) -> void {
|
||||
if(x > 239) return;
|
||||
if(ppu.blank() || !io.enable[0]) return;
|
||||
|
||||
if(x == 0) {
|
||||
@@ -191,15 +196,17 @@ auto PPU::Background::bitmap(u32 x, u32 y) -> void {
|
||||
u32 px = fx >> 8;
|
||||
u32 py = fy >> 8;
|
||||
|
||||
if(px < width && py < height) {
|
||||
u32 offset = py * width + px;
|
||||
n15 color = ppu.readVRAM_BG(mode, baseAddress + (offset << depth));
|
||||
u32 offset = py * width + px;
|
||||
n15 color = ppu.readVRAM_BG(mode, baseAddress + (offset << depth));
|
||||
|
||||
if(px < width && py < height) {
|
||||
if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque
|
||||
if(depth) output[x].directColor = true;
|
||||
output[x].enable = true;
|
||||
output[x].priority = io.priority;
|
||||
output[x].color = color;
|
||||
if(x < 240) {
|
||||
if(depth) output[x].directColor = true;
|
||||
output[x].enable = true;
|
||||
output[x].priority = io.priority;
|
||||
output[x].color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -4,7 +4,16 @@ auto PPU::releaseBus() -> void {
|
||||
}
|
||||
|
||||
auto PPU::pramContention() -> bool {
|
||||
return pramAccessed;
|
||||
if(accurate) return pramAccessed;
|
||||
|
||||
//approximate timings in scanline renderer, assuming no layer blending
|
||||
n3 mode = PPU::Background::IO::mode;
|
||||
if(display.io.vcounter < 160 && !ppu.blank() && mode != 3 && mode != 5) {
|
||||
n32 hcounter = cpu.context.hcounter;
|
||||
if(hcounter < 46 || hcounter > 1005) return false;
|
||||
return (hcounter & 3) == 2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto PPU::vramContention(n32 address) -> bool {
|
||||
|
||||
+54
-20
@@ -75,16 +75,25 @@ auto PPU::step(u32 clocks) -> void {
|
||||
Thread::synchronize(cpu, display);
|
||||
}
|
||||
|
||||
template<u32 Cycle>
|
||||
auto PPU::cycleLinear(u32 x, u32 y) -> void {
|
||||
template<s32 Cycle>
|
||||
auto PPU::cycleLinearMap(s32 x, u32 y) -> void {
|
||||
n3 mode = PPU::Background::IO::mode;
|
||||
if constexpr(Cycle == 0) if(mode <= 1) bg0.linear(x, y);
|
||||
if constexpr(Cycle == 1) if(mode <= 1) bg1.linear(x, y);
|
||||
if constexpr(Cycle == 2) if(mode == 0) bg2.linear(x, y);
|
||||
if constexpr(Cycle == 3) if(mode == 0) bg3.linear(x, y);
|
||||
if constexpr(Cycle == 0) if(mode <= 1) bg0.linearFetchTileMap(x, y);
|
||||
if constexpr(Cycle == 1) if(mode <= 1) bg1.linearFetchTileMap(x, y);
|
||||
if constexpr(Cycle == 2) if(mode == 0) bg2.linearFetchTileMap(x, y);
|
||||
if constexpr(Cycle == 3) if(mode == 0) bg3.linearFetchTileMap(x, y);
|
||||
}
|
||||
|
||||
template<u32 Cycle>
|
||||
template<s32 Cycle>
|
||||
auto PPU::cycleLinearRender(s32 x, u32 y) -> void {
|
||||
n3 mode = PPU::Background::IO::mode;
|
||||
if constexpr(Cycle == 0) if(mode <= 1) bg0.linearRender(x, y);
|
||||
if constexpr(Cycle == 1) if(mode <= 1) bg1.linearRender(x, y);
|
||||
if constexpr(Cycle == 2) if(mode == 0) bg2.linearRender(x, y);
|
||||
if constexpr(Cycle == 3) if(mode == 0) bg3.linearRender(x, y);
|
||||
}
|
||||
|
||||
template<s32 Cycle>
|
||||
auto PPU::cycleAffine(u32 x, u32 y) -> void {
|
||||
n3 mode = PPU::Background::IO::mode;
|
||||
if constexpr(Cycle == 0) if( mode == 2) bg3.affineFetchTileMap(x, y);
|
||||
@@ -111,11 +120,12 @@ auto PPU::cycleUpperLayer(u32 x, u32 y) -> void {
|
||||
dac.upperLayer(x, y);
|
||||
}
|
||||
|
||||
template<u32 Cycle>
|
||||
template<s32 Cycle>
|
||||
auto PPU::cycle(u32 y) -> void {
|
||||
if constexpr(Cycle >= 31 && Cycle <= 1005 ) cycleLinear<(Cycle - 31) & 3>((Cycle - 31) / 4, y);
|
||||
if constexpr(Cycle >= 31 && Cycle <= 1005 ) cycleAffine<(Cycle - 31) & 3>((Cycle - 31) / 4, y);
|
||||
if constexpr(Cycle >= 31 && Cycle <= 1005 && (Cycle - 31) % 4 == 3) cycleBitmap((Cycle - 31) / 4, y);
|
||||
if constexpr(Cycle >= 7 && Cycle <= 1037 ) cycleLinearRender<(Cycle - 7) & 3>((Cycle - 35) >> 2, y);
|
||||
if constexpr(Cycle >= 3 && Cycle <= 1005 ) cycleLinearMap<(Cycle - 3) & 3>((Cycle - 31) >> 2, y);
|
||||
if constexpr(Cycle >= 31 && Cycle <= 1005 ) cycleAffine<(Cycle - 31) & 3>((Cycle - 31) >> 2, y);
|
||||
if constexpr(Cycle >= 31 && Cycle <= 1005 && (Cycle - 31) % 4 == 3) cycleBitmap((Cycle - 31) >> 2, y);
|
||||
if constexpr(Cycle >= 46 && Cycle <= 1005 && (Cycle - 46) % 4 == 0) cycleUpperLayer((Cycle - 46) / 4, y);
|
||||
if constexpr(Cycle >= 46 && Cycle <= 1005 && (Cycle - 46) % 4 == 2) dac.lowerLayer((Cycle - 46) / 4, y);
|
||||
step(1);
|
||||
@@ -133,7 +143,7 @@ auto PPU::main() -> void {
|
||||
bg3.io.ly = bg3.io.y;
|
||||
}
|
||||
|
||||
step(31);
|
||||
step(3);
|
||||
|
||||
u32 y = display.io.vcounter;
|
||||
memory::move(io.forceBlank, io.forceBlank + 1, sizeof(io.forceBlank) - 1);
|
||||
@@ -159,7 +169,13 @@ auto PPU::main() -> void {
|
||||
#define cycles32(index) cycles16(index); cycles16(index + 16)
|
||||
#define cycles64(index) cycles32(index); cycles32(index + 32)
|
||||
|
||||
//cycle 31 - start rendering backgrounds
|
||||
//cycle 3 - earliest possible background render cycle
|
||||
cycles04( 3);
|
||||
cycles08( 7);
|
||||
cycles08( 15);
|
||||
cycles08( 23);
|
||||
|
||||
//cycle 31 - start rendering backgrounds unconditionally
|
||||
cycles01( 31);
|
||||
cycles02( 32);
|
||||
cycles04( 34);
|
||||
@@ -182,6 +198,12 @@ auto PPU::main() -> void {
|
||||
cycles64(878);
|
||||
cycles64(942);
|
||||
|
||||
//cycle 1006 - finish rendering final background tiles
|
||||
cycles08(1006);
|
||||
cycles08(1014);
|
||||
cycles08(1022);
|
||||
cycles08(1030);
|
||||
|
||||
#undef cycles02
|
||||
#undef cycles04
|
||||
#undef cycles08
|
||||
@@ -189,22 +211,25 @@ auto PPU::main() -> void {
|
||||
#undef cycles32
|
||||
#undef cycles64
|
||||
} else {
|
||||
step(renderingCycle);
|
||||
for(s32 x : range(247)) {
|
||||
bg0.run(x - 7, y);
|
||||
bg1.run(x - 7, y);
|
||||
bg2.run(x - 7, y);
|
||||
bg3.run(x - 7, y);
|
||||
}
|
||||
for(u32 x : range(240)) {
|
||||
bg0.run(x, y);
|
||||
bg1.run(x, y);
|
||||
bg2.run(x, y);
|
||||
bg3.run(x, y);
|
||||
cycleUpperLayer(x, y);
|
||||
dac.lowerLayer(x, y);
|
||||
}
|
||||
releaseBus();
|
||||
step(975);
|
||||
step(1035 - renderingCycle);
|
||||
}
|
||||
} else {
|
||||
step(975);
|
||||
step(1035);
|
||||
}
|
||||
|
||||
step(226);
|
||||
step(194);
|
||||
}
|
||||
|
||||
auto PPU::frame() -> void {
|
||||
@@ -237,6 +262,15 @@ auto PPU::power() -> void {
|
||||
window2.power(IN2);
|
||||
window3.power(OUT);
|
||||
dac.power();
|
||||
|
||||
renderingCycle = 43; //by default, render at first cycle of pixel output
|
||||
string gameID;
|
||||
for(u32 index : range(4)) {
|
||||
char byte = cartridge.readRom<true>(Byte, 0xac + index);
|
||||
gameID.append(byte);
|
||||
}
|
||||
if(gameID == "AWRE") renderingCycle = 512; //Advance Wars (USA)
|
||||
if(gameID == "AWRP") renderingCycle = 512; //Advance Wars (Europe) (En,Fr,De,Es)
|
||||
}
|
||||
|
||||
}
|
||||
+11
-6
@@ -37,11 +37,12 @@ struct PPU : Thread, IO {
|
||||
auto blank() -> bool;
|
||||
|
||||
auto step(u32 clocks) -> void;
|
||||
template<u32> auto cycleLinear(u32 x, u32 y) -> void;
|
||||
template<u32> auto cycleAffine(u32 x, u32 y) -> void;
|
||||
template<s32> auto cycleLinearMap(s32 x, u32 y) -> void;
|
||||
template<s32> auto cycleLinearRender(s32 x, u32 y) -> void;
|
||||
template<s32> auto cycleAffine(u32 x, u32 y) -> void;
|
||||
auto cycleBitmap(u32 x, u32 y) -> void;
|
||||
auto cycleUpperLayer(u32 x, u32 y) -> void;
|
||||
template<u32> auto cycle(u32 y) -> void;
|
||||
template<s32> auto cycle(u32 y) -> void;
|
||||
auto main() -> void;
|
||||
|
||||
auto frame() -> void;
|
||||
@@ -106,10 +107,10 @@ private:
|
||||
auto setEnable(n1 status) -> void;
|
||||
auto scanline(u32 y) -> void;
|
||||
auto outputPixel(u32 x, u32 y) -> void;
|
||||
auto run(u32 x, u32 y) -> void;
|
||||
auto linearFetchTileMap() -> void;
|
||||
auto run(s32 x, u32 y) -> void;
|
||||
auto linearFetchTileMap(s32 x, u32 y) -> void;
|
||||
auto linearFetchTileData() -> void;
|
||||
auto linear(u32 x, u32 y) -> void;
|
||||
auto linearRender(s32 x, u32 y) -> void;
|
||||
auto affineFetchTileMap(u32 x, u32 y) -> void;
|
||||
auto affineFetchTileData(u32 x, u32 y) -> void;
|
||||
auto bitmap(u32 x, u32 y) -> void;
|
||||
@@ -160,6 +161,9 @@ private:
|
||||
n4 palette;
|
||||
|
||||
n16 data;
|
||||
|
||||
n1 active;
|
||||
n3 px;
|
||||
} latch;
|
||||
|
||||
struct Affine {
|
||||
@@ -303,6 +307,7 @@ private:
|
||||
|
||||
bool pramAccessed;
|
||||
bool vramAccessedBG;
|
||||
n32 renderingCycle;
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
||||
@@ -1,4 +1,4 @@
|
||||
static const string SerializerVersion = "v141.6";
|
||||
static const string SerializerVersion = "v143.1";
|
||||
|
||||
auto System::serialize(bool synchronize) -> serializer {
|
||||
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
ares.components += m68000
|
||||
ares.components += z80
|
||||
ares.components += sh2
|
||||
ares.components += ssp1601
|
||||
ares.components += sn76489
|
||||
ares.components += ym2612
|
||||
ares.components += m24c
|
||||
|
||||
ares.objects += ares-md-bus
|
||||
ares.objects += ares-md-cpu
|
||||
ares.objects += ares-md-apu
|
||||
ares.objects += ares-md-vdp
|
||||
ares.objects += ares-md-opn2
|
||||
ares.objects += ares-md-m32x
|
||||
ares.objects += ares-md-mcd
|
||||
ares.objects += ares-md-system
|
||||
ares.objects += ares-md-cartridge
|
||||
ares.objects += ares-md-controller
|
||||
|
||||
$(object.path)/ares-md-bus.o: $(ares.path)/md/bus/bus.cpp
|
||||
$(object.path)/ares-md-cpu.o: $(ares.path)/md/cpu/cpu.cpp
|
||||
$(object.path)/ares-md-apu.o: $(ares.path)/md/apu/apu.cpp
|
||||
$(object.path)/ares-md-vdp.o: $(ares.path)/md/vdp/vdp.cpp
|
||||
$(object.path)/ares-md-opn2.o: $(ares.path)/md/opn2/opn2.cpp
|
||||
$(object.path)/ares-md-m32x.o: $(ares.path)/md/m32x/m32x.cpp
|
||||
$(object.path)/ares-md-mcd.o: $(ares.path)/md/mcd/mcd.cpp
|
||||
$(object.path)/ares-md-system.o: $(ares.path)/md/system/system.cpp
|
||||
$(object.path)/ares-md-cartridge.o: $(ares.path)/md/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-md-controller.o: $(ares.path)/md/controller/controller.cpp
|
||||
+5
-3
@@ -65,7 +65,7 @@ auto CPU::step(u32 clocks) -> void {
|
||||
refresh.ram += clocks;
|
||||
refresh.external += clocks;
|
||||
Thread::step(clocks);
|
||||
cyclesUntilSync -= clocks;
|
||||
cyclesUntilFullSync -= clocks;
|
||||
}
|
||||
|
||||
inline auto CPU::idle(u32 clocks) -> void {
|
||||
@@ -74,8 +74,10 @@ inline auto CPU::idle(u32 clocks) -> void {
|
||||
|
||||
auto CPU::wait(u32 clocks) -> void {
|
||||
step(clocks);
|
||||
if (cyclesUntilSync <= 0) {
|
||||
cyclesUntilSync = minCyclesBetweenSyncs;
|
||||
|
||||
Thread::synchronize(apu, cartridge, opn2, vdp);
|
||||
if (cyclesUntilFullSync <= 0) {
|
||||
cyclesUntilFullSync = minCyclesBetweenSyncs;
|
||||
Thread::synchronize();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ struct CPU : M68000, Thread {
|
||||
int stolenMcycles = 0;
|
||||
} state;
|
||||
|
||||
int cyclesUntilSync = 0;
|
||||
int cyclesUntilFullSync = 0;
|
||||
int minCyclesBetweenSyncs = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ auto M32X::readExternal(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
|
||||
}
|
||||
|
||||
if(address >= 0x840000 && address <= 0x87ffff) {
|
||||
if(vdp.framebufferAccess) return data;
|
||||
if(vdp.framebufferEngaged()) { debug(unusual, "[32X FB] 68k read while FEN==1"); return data; } // wait instead?
|
||||
return vdp.bbram[address >> 1 & 0xffff];
|
||||
}
|
||||
|
||||
@@ -40,7 +42,8 @@ auto M32X::writeExternal(n1 upper, n1 lower, n24 address, n16 data) -> void {
|
||||
}
|
||||
|
||||
if(address >= 0x840000 && address <= 0x85ffff) {
|
||||
if (vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferEngaged()) { debug(unusual, "[32X FB] 68k write while FEN==1"); return; } // wait instead?
|
||||
if(!data && (!upper || !lower)) return; //8-bit 0x00 writes do not go through
|
||||
shm.debugger.tracer.instruction->invalidate(0x0400'0000 | address & 0x1fffe);
|
||||
shs.debugger.tracer.instruction->invalidate(0x0400'0000 | address & 0x1fffe);
|
||||
@@ -50,7 +53,8 @@ auto M32X::writeExternal(n1 upper, n1 lower, n24 address, n16 data) -> void {
|
||||
}
|
||||
|
||||
if(address >= 0x860000 && address <= 0x87ffff) {
|
||||
if (vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferEngaged()) { debug(unusual, "[32X FB] 68k overwrite while FEN==1"); return; } // wait instead?
|
||||
shm.debugger.tracer.instruction->invalidate(0x0402'0000 | address & 0x1fffe);
|
||||
shs.debugger.tracer.instruction->invalidate(0x0402'0000 | address & 0x1fffe);
|
||||
if(upper && data.byte(1)) vdp.bbram[address >> 1 & 0xffff].byte(1) = data.byte(1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
auto M32X::readInternal(n1 upper, n1 lower, n32 address, n16 data) -> n16 {
|
||||
if(address >= 0x0000'0000 && address <= 0x0000'3fff) {
|
||||
if(shm.active()) shm.step(1); if(shs.active()) shs.step(1);
|
||||
if(shm.active()) shm.internalStep(1); if(shs.active()) shs.internalStep(1);
|
||||
if(shm.active()) return shm.bootROM[address >> 1];
|
||||
if(shs.active()) return shs.bootROM[address >> 1];
|
||||
}
|
||||
@@ -9,20 +9,22 @@ auto M32X::readInternal(n1 upper, n1 lower, n32 address, n16 data) -> n16 {
|
||||
return readInternalIO(upper, lower, address, data);
|
||||
}
|
||||
|
||||
if(address >= 0x0200'0000 && address <= 0x023f'ffff) {
|
||||
if(address >= 0x0200'0000 && address <= 0x03ff'ffff) {
|
||||
while(dreq.vram) {
|
||||
// SH2 ROM accesses stall while RV is set
|
||||
if(shm.active()) shm.step(1);
|
||||
if(shs.active()) shs.step(1);
|
||||
//SH2 ROM accesses stall while RV is set
|
||||
if(shm.active()) { shm.internalStep(1); shm.syncM68k(true); }
|
||||
if(shs.active()) { shs.internalStep(1); shs.syncM68k(true); }
|
||||
}
|
||||
|
||||
// TODO: SH2 ROM accesses need to stall while the m68k is on the bus
|
||||
if(shm.active()) shm.step(6); if(shs.active()) shs.step(6);
|
||||
//TODO: SH2 ROM accesses need to stall while the m68k is on the bus
|
||||
if(shm.active()) shm.internalStep(6); if(shs.active()) shs.internalStep(6);
|
||||
return cartridge.child->read(upper, lower, address, data);
|
||||
}
|
||||
|
||||
if(address >= 0x0400'0000 && address <= 0x0405'ffff) {
|
||||
if(shm.active()) shm.step(5); if(shs.active()) shs.step(5);
|
||||
if(address >= 0x0400'0000 && address <= 0x05ff'ffff) {
|
||||
if(!vdp.framebufferAccess) return data;
|
||||
if(vdp.framebufferEngaged()) { debug(unusual, "[32X FB] SH2 read while FEN==1"); return data; } // wait instead?
|
||||
if(shm.active()) shm.internalStep(5); if(shs.active()) shs.internalStep(5);
|
||||
return vdp.bbram[address >> 1 & 0xffff];
|
||||
}
|
||||
|
||||
@@ -38,30 +40,27 @@ auto M32X::writeInternal(n1 upper, n1 lower, n32 address, n16 data) -> void {
|
||||
return writeInternalIO(upper, lower, address, data);
|
||||
}
|
||||
|
||||
if(address >= 0x0400'0000 && address <= 0x0401'ffff) {
|
||||
if (!vdp.framebufferAccess) return;
|
||||
if(!data && (!upper || !lower)) return; //8-bit 0x00 writes do not go through
|
||||
if(shm.active()) shm.step(4); if(shs.active()) shs.step(4);
|
||||
if(upper) vdp.bbram[address >> 1 & 0xffff].byte(1) = data.byte(1);
|
||||
if(lower) vdp.bbram[address >> 1 & 0xffff].byte(0) = data.byte(0);
|
||||
return;
|
||||
}
|
||||
if(address >= 0x0400'0000 && address <= 0x05ff'ffff) {
|
||||
address &= 0x0403'ffff;
|
||||
|
||||
if(address >= 0x0402'0000 && address <= 0x0403'ffff) {
|
||||
if (!vdp.framebufferAccess) return;
|
||||
if(shm.active()) shm.step(4); if(shs.active()) shs.step(4);
|
||||
if(upper && data.byte(1)) vdp.bbram[address >> 1 & 0xffff].byte(1) = data.byte(1);
|
||||
if(lower && data.byte(0)) vdp.bbram[address >> 1 & 0xffff].byte(0) = data.byte(0);
|
||||
return;
|
||||
}
|
||||
if(address >= 0x0400'0000 && address <= 0x0401'ffff) {
|
||||
if(!vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferEngaged()) { debug(unusual, "[32X FB] SH2 write while FEN==1"); return; } // wait instead?
|
||||
if(!data && (!upper || !lower)) return; //8-bit 0x00 writes do not go through
|
||||
if(shm.active()) shm.internalStep(4); if(shs.active()) shs.internalStep(4);
|
||||
if(upper) vdp.bbram[address >> 1 & 0xffff].byte(1) = data.byte(1);
|
||||
if(lower) vdp.bbram[address >> 1 & 0xffff].byte(0) = data.byte(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(address >= 0x0404'0000 && address <= 0x0405'ffff) {
|
||||
if (!vdp.framebufferAccess) return;
|
||||
if(!data && (!upper || !lower)) return; //8-bit 0x00 writes do not go through
|
||||
if(shm.active()) shm.step(4); if(shs.active()) shs.step(4);
|
||||
if(upper) vdp.bbram[address >> 1 & 0xffff].byte(1) = data.byte(1);
|
||||
if(lower) vdp.bbram[address >> 1 & 0xffff].byte(0) = data.byte(0);
|
||||
return;
|
||||
if(address >= 0x0402'0000 && address <= 0x0403'ffff) {
|
||||
if(!vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferEngaged()) { debug(unusual, "[32X FB] SH2 overwrite while FEN==1"); return; } // wait instead?
|
||||
if(shm.active()) shm.internalStep(4); if(shs.active()) shs.internalStep(4);
|
||||
if(upper && data.byte(1)) vdp.bbram[address >> 1 & 0xffff].byte(1) = data.byte(1);
|
||||
if(lower && data.byte(0)) vdp.bbram[address >> 1 & 0xffff].byte(0) = data.byte(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(address >= 0x0600'0000 && address <= 0x0603'ffff) {
|
||||
|
||||
@@ -35,7 +35,9 @@ auto M32X::readExternalIO(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
|
||||
data.bit(0) = dreq.vram;
|
||||
data.bit(1) = dreq.dma;
|
||||
data.bit(2) = dreq.active;
|
||||
data.bit(3,6) = 0;
|
||||
data.bit(7) = dreq.fifo.full();
|
||||
data.bit(8,15) = 0;
|
||||
}
|
||||
|
||||
//68K to SH2 DREQ source address
|
||||
@@ -62,9 +64,18 @@ auto M32X::readExternalIO(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
|
||||
data.byte(0) = dreq.length.byte(0);
|
||||
}
|
||||
|
||||
if(address == 0xa15114 ||
|
||||
address == 0xa15116 ||
|
||||
address == 0xa15118 ||
|
||||
address == 0xa1511c ||
|
||||
address == 0xa1511e) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
//TV register
|
||||
if(address == 0xa1511a) {
|
||||
data.bit(0) = io.cartridgeMode;
|
||||
data.bit(1,15) = 0;
|
||||
}
|
||||
|
||||
//communication
|
||||
@@ -139,15 +150,20 @@ auto M32X::readExternalIO(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
|
||||
//frame buffer control
|
||||
if(address == 0xa1518a) {
|
||||
data.bit( 0) = vdp.framebufferActive;
|
||||
data.bit( 1) = MegaDrive::vdp.refreshing(); //framebuffer access
|
||||
data.bit( 1) = MegaDrive::vdp.refreshing()
|
||||
|| vdp.framebufferEngaged(); // FEN: frame buffer engaged
|
||||
data.bit( 2, 12) = 0;
|
||||
data.bit(13) = vdp.vblank || vdp.hblank; //palette access
|
||||
data.bit(13) = !vdp.paletteEngaged(); // PEN: can access palette
|
||||
data.bit(14) = vdp.hblank;
|
||||
data.bit(15) = vdp.vblank;
|
||||
}
|
||||
|
||||
//palette
|
||||
if(address >= 0xa15200 && address <= 0xa153ff) {
|
||||
if(vdp.framebufferAccess) return data;
|
||||
while(vdp.paletteEngaged()) {
|
||||
if(cpu.active()) cpu.wait(1);
|
||||
}
|
||||
data = vdp.cram[address >> 1 & 0xff];
|
||||
}
|
||||
|
||||
@@ -357,7 +373,10 @@ auto M32X::writeExternalIO(n1 upper, n1 lower, n24 address, n16 data) -> void {
|
||||
|
||||
//palette
|
||||
if(address >= 0xa15200 && address <= 0xa153ff) {
|
||||
if (vdp.framebufferAccess) return;
|
||||
if(vdp.framebufferAccess) return;
|
||||
while(vdp.paletteEngaged()) {
|
||||
if(cpu.active()) cpu.wait(1);;
|
||||
}
|
||||
if(upper) vdp.cram[address >> 1 & 0xff].byte(1) = data.byte(1);
|
||||
if(lower) vdp.cram[address >> 1 & 0xff].byte(0) = data.byte(0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
auto M32X::readInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> n16 {
|
||||
if(shm.active()) shm.step(1); if(shs.active()) shs.step(1);
|
||||
if(shm.active()) shm.internalStep(1); if(shs.active()) shs.internalStep(1);
|
||||
|
||||
//interrupt mask
|
||||
if(address == 0x4000) {
|
||||
@@ -63,6 +63,8 @@ auto M32X::readInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> n16 {
|
||||
|
||||
//FIFO
|
||||
if(address == 0x4012) {
|
||||
if(shm.active()) { shm.syncM68k(); }
|
||||
if(shs.active()) { shs.syncM68k(); }
|
||||
data = dreq.fifo.read(data);
|
||||
shm.dmac.dreq[0] = !dreq.fifo.empty();
|
||||
shs.dmac.dreq[0] = !dreq.fifo.empty();
|
||||
@@ -71,8 +73,8 @@ auto M32X::readInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> n16 {
|
||||
//communication
|
||||
if(address >= 0x4020 && address <= 0x402f) {
|
||||
data = communication[address >> 1 & 7];
|
||||
if(shm.active()) { shm.syncOtherSh2(); shm.syncM68k(); }
|
||||
if(shs.active()) { shs.syncOtherSh2(); shs.syncM68k(); }
|
||||
if(shm.active()) { shm.syncAll(); }
|
||||
if(shs.active()) { shs.syncAll(); }
|
||||
}
|
||||
|
||||
//PWM control
|
||||
@@ -144,15 +146,21 @@ auto M32X::readInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> n16 {
|
||||
if(shm.active()) shm.syncM68k();
|
||||
if(shs.active()) shs.syncM68k();
|
||||
data.bit( 0) = vdp.framebufferActive;
|
||||
data.bit( 1) = MegaDrive::vdp.refreshing(); //framebuffer access
|
||||
data.bit(13) = vdp.vblank || vdp.hblank; //palette access
|
||||
data.bit( 1) = MegaDrive::vdp.refreshing()
|
||||
|| vdp.framebufferEngaged(); // FEN: frame buffer engaged
|
||||
data.bit(13) = !vdp.paletteEngaged(); // PEN: can access palette
|
||||
data.bit(14) = vdp.hblank;
|
||||
data.bit(15) = vdp.vblank;
|
||||
}
|
||||
|
||||
//palette
|
||||
if(address >= 0x4200 && address <= 0x43ff) {
|
||||
if(shm.active()) shm.step(4); if(shs.active()) shs.step(4);
|
||||
if(!vdp.framebufferAccess) return data;
|
||||
while(vdp.paletteEngaged()) {
|
||||
if(shm.active()) { shm.internalStep(1); shm.syncAll(true); }
|
||||
if(shs.active()) { shs.internalStep(1); shs.syncAll(true); }
|
||||
}
|
||||
if(shm.active()) shm.internalStep(4); if(shs.active()) shs.internalStep(4);
|
||||
data = vdp.cram[address >> 1 & 0xff];
|
||||
}
|
||||
|
||||
@@ -160,7 +168,7 @@ auto M32X::readInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> n16 {
|
||||
}
|
||||
|
||||
auto M32X::writeInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> void {
|
||||
if(shm.active()) shm.step(1); if(shs.active()) shs.step(1);
|
||||
if(shm.active()) shm.internalStep(1); if(shs.active()) shs.internalStep(1);
|
||||
|
||||
//interrupt mask
|
||||
if(address == 0x4000) {
|
||||
@@ -228,8 +236,8 @@ auto M32X::writeInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> void {
|
||||
|
||||
//communication
|
||||
if(address >= 0x4020 && address <= 0x402f) {
|
||||
if(shm.active()) { shm.syncOtherSh2(); shm.syncM68k(); }
|
||||
if(shs.active()) { shs.syncOtherSh2(); shs.syncM68k(); }
|
||||
if(shm.active()) { shm.syncAll(); }
|
||||
if(shs.active()) { shs.syncAll(); }
|
||||
if(upper) communication[address >> 1 & 7].byte(1) = data.byte(1);
|
||||
if(lower) communication[address >> 1 & 7].byte(0) = data.byte(0);
|
||||
}
|
||||
@@ -337,8 +345,12 @@ auto M32X::writeInternalIO(n1 upper, n1 lower, n29 address, n16 data) -> void {
|
||||
|
||||
//palette
|
||||
if(address >= 0x4200 && address <= 0x43ff) {
|
||||
if (!vdp.framebufferAccess) return;
|
||||
if(shm.active()) shm.step(4); if(shs.active()) shs.step(4);
|
||||
if(!vdp.framebufferAccess) return;
|
||||
while(vdp.paletteEngaged()) {
|
||||
if(shm.active()) { shm.internalStep(1); shm.syncAll(true); }
|
||||
if(shs.active()) { shs.internalStep(1); shs.syncAll(true); }
|
||||
}
|
||||
if(shm.active()) shm.internalStep(4); if(shs.active()) shs.internalStep(4);
|
||||
if(upper) vdp.cram[address >> 1 & 0xff].byte(1) = data.byte(1);
|
||||
if(lower) vdp.cram[address >> 1 & 0xff].byte(0) = data.byte(0);
|
||||
}
|
||||
|
||||
@@ -51,15 +51,12 @@ auto M32X::power(bool reset) -> void {
|
||||
shs.power(reset);
|
||||
vdp.power(reset);
|
||||
pwm.power(reset);
|
||||
n32 vec4 = io.vectorLevel4;
|
||||
io = {};
|
||||
if(reset) io.vectorLevel4 = vec4;
|
||||
dreq = {};
|
||||
for(auto& word : communication) word = 0;
|
||||
|
||||
io.vectorLevel4.byte(3) = vectors[0x70 >> 1].byte(1);
|
||||
io.vectorLevel4.byte(2) = vectors[0x70 >> 1].byte(0);
|
||||
io.vectorLevel4.byte(1) = vectors[0x72 >> 1].byte(1);
|
||||
io.vectorLevel4.byte(0) = vectors[0x72 >> 1].byte(0);
|
||||
|
||||
//connect interfaces
|
||||
shm.sci.link = shs;
|
||||
shs.sci.link = shm;
|
||||
@@ -76,6 +73,13 @@ auto M32X::vblank(bool line) -> void {
|
||||
}
|
||||
|
||||
auto M32X::hblank(bool line) -> void {
|
||||
if(vdp.hblank > line) {
|
||||
// TODO: VDP regs should be latched 192 MClks (~82 cycles) before end of hblank (according to official docs)
|
||||
vdp.latch.mode = vdp.mode;
|
||||
vdp.latch.lines = vdp.lines;
|
||||
vdp.latch.priority = vdp.priority;
|
||||
vdp.latch.dotshift = vdp.dotshift;
|
||||
}
|
||||
vdp.hblank = line;
|
||||
shm.irq.hint.active = 0;
|
||||
shs.irq.hint.active = 0;
|
||||
|
||||
+15
-5
@@ -40,10 +40,12 @@ struct M32X {
|
||||
auto main() -> void;
|
||||
auto instructionPrologue(u16 instruction) -> void override;
|
||||
auto step(u32 clocks) -> void override;
|
||||
auto internalStep(u32 clocks) -> void;
|
||||
auto power(bool reset) -> void;
|
||||
auto restart() -> void;
|
||||
auto syncOtherSh2() -> void;
|
||||
auto syncM68k() -> void;
|
||||
auto syncAll(bool force = false) -> void;
|
||||
auto syncOtherSh2(bool force = false) -> void;
|
||||
auto syncM68k(bool force = false) -> void;
|
||||
|
||||
auto busReadByte(u32 address) -> u32 override;
|
||||
auto busReadWord(u32 address) -> u32 override;
|
||||
@@ -69,10 +71,8 @@ struct M32X {
|
||||
|
||||
s32 cyclesUntilSh2Sync = 0;
|
||||
s32 cyclesUntilM68kSync = 0;
|
||||
s32 cyclesUntilFullSync = 0;
|
||||
s32 minCyclesBetweenSh2Syncs = 0;
|
||||
s32 minCyclesBetweenM68kSyncs = 0;
|
||||
s32 minCyclesBetweenFullSyncs = 0;
|
||||
};
|
||||
|
||||
struct VDP {
|
||||
@@ -104,6 +104,8 @@ struct M32X {
|
||||
auto plot(u32* output, u16 color) -> void;
|
||||
auto fill() -> void;
|
||||
auto selectFramebuffer(n1 active) -> void;
|
||||
auto framebufferEngaged() -> bool;
|
||||
auto paletteEngaged() -> bool;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
@@ -118,8 +120,16 @@ struct M32X {
|
||||
n1 framebufferAccess;
|
||||
n1 framebufferActive;
|
||||
n1 framebufferSelect;
|
||||
int framebufferWait;
|
||||
n1 hblank;
|
||||
n1 vblank;
|
||||
|
||||
struct Latch {
|
||||
n2 mode;
|
||||
n1 lines;
|
||||
n1 priority;
|
||||
n1 dotshift;
|
||||
} latch;
|
||||
};
|
||||
|
||||
struct PWM : Thread {
|
||||
@@ -208,7 +218,7 @@ struct M32X {
|
||||
|
||||
//$a15000
|
||||
n1 adapterEnable;
|
||||
n1 adapterReset;
|
||||
n1 adapterReset = 1;
|
||||
n1 resetEnable = 1;
|
||||
|
||||
//$a15004
|
||||
|
||||
@@ -46,12 +46,17 @@ auto M32X::VDP::serialize(serializer& s) -> void {
|
||||
s(lines);
|
||||
s(priority);
|
||||
s(dotshift);
|
||||
s(latch.mode);
|
||||
s(latch.lines);
|
||||
s(latch.priority);
|
||||
s(latch.dotshift);
|
||||
s(autofillLength);
|
||||
s(autofillAddress);
|
||||
s(autofillData);
|
||||
s(framebufferAccess);
|
||||
s(framebufferActive);
|
||||
s(framebufferSelect);
|
||||
s(framebufferWait);
|
||||
s(hblank);
|
||||
s(vblank);
|
||||
selectFramebuffer(framebufferSelect);
|
||||
@@ -76,4 +81,5 @@ auto M32X::PWM::serialize(serializer& s) -> void {
|
||||
s(lfifoLatch);
|
||||
s(rfifoLatch);
|
||||
s(mfifoLatch);
|
||||
updateFrequency();
|
||||
}
|
||||
+56
-21
@@ -49,28 +49,47 @@ auto M32X::SH7604::instructionPrologue(u16 instruction) -> void {
|
||||
debugger.instruction(instruction);
|
||||
}
|
||||
|
||||
auto M32X::SH7604::internalStep(u32 clocks) -> void {
|
||||
if(SH2::Accuracy::Recompiler && m32x.shm.recompiler.enabled) {
|
||||
regs.CCR += clocks;
|
||||
return;
|
||||
}
|
||||
|
||||
step(clocks);
|
||||
}
|
||||
|
||||
auto M32X::SH7604::step(u32 clocks) -> void {
|
||||
SH2::frt.run(clocks);
|
||||
SH2::wdt.run(clocks);
|
||||
|
||||
Thread::step(clocks);
|
||||
|
||||
cyclesUntilSh2Sync -= clocks;
|
||||
cyclesUntilM68kSync -= clocks;
|
||||
cyclesUntilFullSync -= clocks;
|
||||
|
||||
if(cyclesUntilFullSync <= 0) {
|
||||
cyclesUntilFullSync = minCyclesBetweenFullSyncs;
|
||||
if(m32x.shm.active()) Thread::synchronize(m32x.shs, cpu);
|
||||
if(m32x.shs.active()) Thread::synchronize(m32x.shm, cpu);
|
||||
m32x.vdp.framebufferWait -= min(clocks, m32x.vdp.framebufferWait);
|
||||
|
||||
if(cyclesUntilSh2Sync <= 0) {
|
||||
cyclesUntilSh2Sync = minCyclesBetweenSh2Syncs;
|
||||
if (m32x.shm.active()) Thread::synchronize(m32x.shs);
|
||||
if (m32x.shs.active()) Thread::synchronize(m32x.shm);
|
||||
}
|
||||
|
||||
if(cyclesUntilM68kSync <= 0) {
|
||||
cyclesUntilM68kSync = minCyclesBetweenM68kSyncs;
|
||||
Thread::synchronize(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
auto M32X::SH7604::power(bool reset) -> void {
|
||||
Thread::create((system.frequency() / 7.0) * 3.0, {&M32X::SH7604::main, this});
|
||||
SH2::recompilerStepCycles = 20; // Minimum cycles for recompiler to run for each batch of instructions
|
||||
minCyclesBetweenFullSyncs = 50; // Minimum cycles between full sync with the M68K/MD side
|
||||
minCyclesBetweenSh2Syncs = 5; // Minimum Cycles between sync with the other SH2 (syncOtherSh2)
|
||||
minCyclesBetweenM68kSyncs = 10; // Minimum Cycles between sync with the M68K (syncM68k)
|
||||
|
||||
//When tweaking these values, make sure to test the following problematic games:
|
||||
// Brutal - Check for hang in attract mode
|
||||
// Chaotix - Check for hang on intro screen or level loading transitions
|
||||
|
||||
SH2::recompilerStepCycles = 200; //Recompiler will force an exit after at least N cycles have passed
|
||||
minCyclesBetweenSh2Syncs = 10; //Do not sync SH2s more than once every N cycles
|
||||
minCyclesBetweenM68kSyncs = 50; //Do not sync M68K more than once every N cycles
|
||||
SH2::power(reset);
|
||||
irq = {};
|
||||
irq.vres.enable = 1;
|
||||
@@ -83,19 +102,35 @@ auto M32X::SH7604::restart() -> void {
|
||||
Thread::restart({&M32X::SH7604::main, this});
|
||||
}
|
||||
|
||||
auto M32X::SH7604::syncOtherSh2() -> void {
|
||||
// avoid synchronizing if we recently have
|
||||
if(cyclesUntilSh2Sync > 0) return;
|
||||
if(m32x.shm.active()) Thread::synchronize(m32x.shs);
|
||||
if(m32x.shs.active()) Thread::synchronize(m32x.shm);
|
||||
cyclesUntilSh2Sync = minCyclesBetweenSh2Syncs;
|
||||
auto M32X::SH7604::syncAll(bool force) -> void {
|
||||
SH2::cyclesUntilRecompilerExit = 0;
|
||||
|
||||
if(SH2::Accuracy::Recompiler && m32x.shm.recompiler.enabled && force) {
|
||||
cyclesUntilSh2Sync = 0;
|
||||
cyclesUntilM68kSync = 0;
|
||||
step(regs.CCR);
|
||||
regs.CCR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto M32X::SH7604::syncM68k() -> void {
|
||||
// avoid synchronizing if we recently have
|
||||
if(cyclesUntilM68kSync > 0) return;
|
||||
Thread::synchronize(cpu);
|
||||
cyclesUntilM68kSync = minCyclesBetweenM68kSyncs;
|
||||
auto M32X::SH7604::syncOtherSh2(bool force) -> void {
|
||||
SH2::cyclesUntilRecompilerExit = 0;
|
||||
|
||||
if(SH2::Accuracy::Recompiler && m32x.shm.recompiler.enabled && force) {
|
||||
cyclesUntilSh2Sync = 0;
|
||||
step(regs.CCR);
|
||||
regs.CCR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto M32X::SH7604::syncM68k(bool force) -> void {
|
||||
SH2::cyclesUntilRecompilerExit = 0;
|
||||
|
||||
if(SH2::Accuracy::Recompiler && m32x.shm.recompiler.enabled && force) {
|
||||
cyclesUntilM68kSync = 0;
|
||||
step(regs.CCR);
|
||||
regs.CCR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto M32X::SH7604::busReadByte(u32 address) -> u32 {
|
||||
|
||||
+30
-23
@@ -17,28 +17,30 @@ auto M32X::VDP::power(bool reset) -> void {
|
||||
lines = 0;
|
||||
priority = 0;
|
||||
dotshift = 0;
|
||||
latch = {};
|
||||
autofillLength = 0;
|
||||
autofillAddress = 0;
|
||||
autofillData = 0;
|
||||
framebufferAccess = 0;
|
||||
framebufferActive = 0;
|
||||
framebufferSelect = 0;
|
||||
framebufferWait = 0;
|
||||
hblank = 0;
|
||||
vblank = 1;
|
||||
selectFramebuffer(framebufferSelect);
|
||||
}
|
||||
|
||||
auto M32X::VDP::scanline(u32 pixels[1280], u32 y) -> void {
|
||||
if(!Mega32X() || !pixels || y >= (lines ? 240 : 224)) return;
|
||||
if(mode == 1) return scanlineMode1(pixels, y);
|
||||
if(mode == 2) return scanlineMode2(pixels, y);
|
||||
if(mode == 3) return scanlineMode3(pixels, y);
|
||||
if(!Mega32X() || !pixels || y >= (latch.lines ? 240 : 224)) return;
|
||||
if(latch.mode == 1) return scanlineMode1(pixels, y);
|
||||
if(latch.mode == 2) return scanlineMode2(pixels, y);
|
||||
if(latch.mode == 3) return scanlineMode3(pixels, y);
|
||||
}
|
||||
|
||||
auto M32X::VDP::scanlineMode1(u32 pixels[1280], u32 y) -> void {
|
||||
u16 address = fbram[y];
|
||||
for(u32 x : range(320)) {
|
||||
u8 color = fbram[address + (x + dotshift >> 1) & 0xffff].byte(!(x + dotshift & 1));
|
||||
u8 color = fbram[address + (x + latch.dotshift >> 1) & 0xffff].byte(!(x + latch.dotshift & 1));
|
||||
plot(&pixels[x * 4], cram[color]);
|
||||
}
|
||||
}
|
||||
@@ -66,30 +68,24 @@ auto M32X::VDP::scanlineMode3(u32 pixels[1280], u32 y) -> void {
|
||||
}
|
||||
|
||||
auto M32X::VDP::plot(u32* output, u16 color) -> void {
|
||||
n1 backdrop = output[0] >> 11;
|
||||
n1 throughbit = color >> 15;
|
||||
b1 opaque = color & 0x7fff;
|
||||
|
||||
if(priority == 0) {
|
||||
//Mega Drive has priority
|
||||
if(throughbit || backdrop) {
|
||||
output[0] = color | 1 << 15;
|
||||
output[1] = color | 1 << 15;
|
||||
output[2] = color | 1 << 15;
|
||||
output[3] = color | 1 << 15;
|
||||
}
|
||||
} else {
|
||||
//Mega 32X has priority
|
||||
if(!throughbit || backdrop) {
|
||||
output[0] = color | 1 << 15;
|
||||
output[1] = color | 1 << 15;
|
||||
output[2] = color | 1 << 15;
|
||||
output[3] = color | 1 << 15;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
n1 backdrop = output[i] >> 11;
|
||||
|
||||
if(latch.priority == 0) {
|
||||
//Mega Drive has priority
|
||||
if(throughbit || backdrop) output[i] = color | 1 << 15;
|
||||
} else {
|
||||
//Mega 32X has priority
|
||||
if(!throughbit || backdrop) output[i] = color | 1 << 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto M32X::VDP::fill() -> void {
|
||||
if(framebufferWait > 0) { debug(unusual, "[32X FILL] triggered before last fill finished"); return; }
|
||||
framebufferWait = 7+3*(autofillLength+1); // according to official docs
|
||||
for(u32 repeat : range(1 + autofillLength)) {
|
||||
bbram[autofillAddress] = autofillData;
|
||||
autofillAddress.byte(0)++;
|
||||
@@ -98,9 +94,20 @@ auto M32X::VDP::fill() -> void {
|
||||
|
||||
auto M32X::VDP::selectFramebuffer(n1 select) -> void {
|
||||
framebufferSelect = select;
|
||||
if(!vblank && mode) return;
|
||||
if(!vblank && latch.mode) return;
|
||||
|
||||
framebufferActive = select;
|
||||
fbram = {dram.data() + 0x10000 * (select == 0), 0x10000};
|
||||
bbram = {dram.data() + 0x10000 * (select == 1), 0x10000};
|
||||
}
|
||||
|
||||
// back buffer access
|
||||
auto M32X::VDP::framebufferEngaged() -> bool {
|
||||
// TODO: 40 cycle wait at start of hblank (according to official docs)
|
||||
return (latch.mode != 0 && framebufferSelect != framebufferActive) || framebufferWait > 0;
|
||||
}
|
||||
|
||||
auto M32X::VDP::paletteEngaged() -> bool {
|
||||
// TODO: not available for 24 MClks (~10 cycles) at start of hblank (according to official docs)
|
||||
return !vblank && !hblank && latch.mode.bit(0);
|
||||
}
|
||||
@@ -85,8 +85,8 @@ auto MCD::writeExternalIO(n1 upper, n1 lower, n24 address, n16 data) -> void {
|
||||
} else {
|
||||
if(io.run && !data.bit(0)) resetCpu();
|
||||
io.run = data.bit(0);
|
||||
io.request = data.bit(1);
|
||||
io.halt = !io.run || io.request;
|
||||
io.request = io.run ? data.bit(1) : 1; // asserting reset forces busreq (confirmed by eke)
|
||||
io.halt = io.request;
|
||||
}
|
||||
}
|
||||
if(upper) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
static const string SerializerVersion = "v141.1";
|
||||
static const string SerializerVersion = "v144";
|
||||
|
||||
auto System::serialize(bool synchronize) -> serializer {
|
||||
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
||||
|
||||
@@ -67,7 +67,7 @@ auto VDP::main() -> void {
|
||||
} else if(hcounter() == 0x80) {
|
||||
if(vcounter() < screenHeight() && !runAhead()) {
|
||||
render();
|
||||
m32x.vdp.scanline(pixels(), state.vcounter);
|
||||
if(Mega32X()) m32x.vdp.scanline(pixels() + 18, vcounter()); //approx 3 and 1/4 pixel offset
|
||||
}
|
||||
|
||||
step(768);
|
||||
|
||||
+2
-6
@@ -171,12 +171,6 @@ auto VDP::readControlPort() -> n16 {
|
||||
auto VDP::writeControlPort(n16 data) -> void {
|
||||
//command write (lo)
|
||||
|
||||
// Note: A pending interrupt will be delayed when a register write
|
||||
// is used to enable that interrupt. Further testing is required,
|
||||
// but the current method should be sufficient to handle most cases.
|
||||
// Required for Sesame Street Counting Cafe et al.
|
||||
irq.delay = 2; // 4 pixel delay (4-6 M68k clocks) from this write
|
||||
|
||||
if(command.latch) {
|
||||
command.latch = 0;
|
||||
|
||||
@@ -222,6 +216,7 @@ auto VDP::writeControlPort(n16 data) -> void {
|
||||
io.counterLatch = data.bit(1);
|
||||
io.videoMode4 = data.bit(2);
|
||||
irq.hblank.enable = data.bit(4);
|
||||
irq.delay = h40() ? 3 : 2; // 4-6 pixel delay (~6 M68k cycles)
|
||||
io.leftColumnBlank = data.bit(5);
|
||||
|
||||
if(!io.videoMode4) debug(unimplemented, "[VDP] M4=0");
|
||||
@@ -237,6 +232,7 @@ auto VDP::writeControlPort(n16 data) -> void {
|
||||
}
|
||||
dma.enable = data.bit(4);
|
||||
irq.vblank.enable = data.bit(5);
|
||||
irq.delay = h40() ? 3 : 2; // 4-6 pixel delay (~6 M68k cycles)
|
||||
io.displayEnable = data.bit(6);
|
||||
vram.mode = data.bit(7);
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ auto VDP::IRQ::acknowledge(u8 level) -> void {
|
||||
else
|
||||
hblank.pending = 0;
|
||||
}
|
||||
if(level == 6) vblank.pending = 0;
|
||||
if(level == 6 && vblank.enable) vblank.pending = 0;
|
||||
}
|
||||
|
||||
auto VDP::IRQ::power(bool reset) -> void {
|
||||
|
||||
@@ -110,6 +110,7 @@ auto VDP::vtick() -> void {
|
||||
} else if(irq.hblank.counter-- == 0) {
|
||||
irq.hblank.counter = irq.hblank.frequency;
|
||||
irq.hblank.pending = 1;
|
||||
irq.delay = h40() ? 3 : 2; // 4-6 pixel delay (~6 M68k cycles)
|
||||
debugger.interrupt(CPU::Interrupt::HorizontalBlank);
|
||||
}
|
||||
|
||||
@@ -147,6 +148,7 @@ auto VDP::vedge() -> void {
|
||||
cartridge.vblank(1);
|
||||
apu.setINT(1);
|
||||
irq.vblank.pending = 1;
|
||||
irq.delay = h40() ? 3 : 2; // 4-6 pixel delay (~6 M68k cycles)
|
||||
debugger.interrupt(CPU::Interrupt::VerticalBlank);
|
||||
}
|
||||
}
|
||||
@@ -182,7 +184,7 @@ auto VDP::mainH32() -> void {
|
||||
sprite.begin();
|
||||
if(dac.pixels) {
|
||||
blocks<false, true>();
|
||||
if(Mega32X()) m32x.vdp.scanline(pixels, vcounter());
|
||||
if(Mega32X()) m32x.vdp.scanline(pixels + 18, vcounter()); //approx 3 and 1/4 pixel offset
|
||||
} else {
|
||||
blocks<false, false>();
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
ares.components += z80
|
||||
ares.components += sn76489
|
||||
ares.components += ym2413
|
||||
|
||||
ares.objects += ares-ms-cpu
|
||||
ares.objects += ares-ms-vdp
|
||||
ares.objects += ares-ms-psg
|
||||
ares.objects += ares-ms-opll
|
||||
ares.objects += ares-ms-system
|
||||
ares.objects += ares-ms-cartridge
|
||||
ares.objects += ares-ms-controller
|
||||
ares.objects += ares-ms-expansion
|
||||
|
||||
$(object.path)/ares-ms-cpu.o: $(ares.path)/ms/cpu/cpu.cpp
|
||||
$(object.path)/ares-ms-vdp.o: $(ares.path)/ms/vdp/vdp.cpp
|
||||
$(object.path)/ares-ms-psg.o: $(ares.path)/ms/psg/psg.cpp
|
||||
$(object.path)/ares-ms-opll.o: $(ares.path)/ms/opll/opll.cpp
|
||||
$(object.path)/ares-ms-system.o: $(ares.path)/ms/system/system.cpp
|
||||
$(object.path)/ares-ms-cartridge.o: $(ares.path)/ms/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-ms-controller.o: $(ares.path)/ms/controller/controller.cpp
|
||||
$(object.path)/ares-ms-expansion.o: $(ares.path)/ms/expansion/expansion.cpp
|
||||
@@ -1,25 +0,0 @@
|
||||
ares.components += z80
|
||||
ares.components += tms9918
|
||||
ares.components += v9938
|
||||
ares.components += ay38910
|
||||
ares.components += ym2413
|
||||
|
||||
ares.objects += ares-msx-system
|
||||
ares.objects += ares-msx-keyboard
|
||||
ares.objects += ares-msx-cartridge
|
||||
ares.objects += ares-msx-controller
|
||||
ares.objects += ares-msx-cpu
|
||||
ares.objects += ares-msx-vdp
|
||||
ares.objects += ares-msx-psg
|
||||
ares.objects += ares-msx-tape
|
||||
ares.objects += ares-msx-rtc
|
||||
|
||||
$(object.path)/ares-msx-system.o: $(ares.path)/msx/system/system.cpp
|
||||
$(object.path)/ares-msx-keyboard.o: $(ares.path)/msx/keyboard/keyboard.cpp
|
||||
$(object.path)/ares-msx-cartridge.o: $(ares.path)/msx/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-msx-controller.o: $(ares.path)/msx/controller/controller.cpp
|
||||
$(object.path)/ares-msx-cpu.o: $(ares.path)/msx/cpu/cpu.cpp
|
||||
$(object.path)/ares-msx-vdp.o: $(ares.path)/msx/vdp/vdp.cpp
|
||||
$(object.path)/ares-msx-psg.o: $(ares.path)/msx/psg/psg.cpp
|
||||
$(object.path)/ares-msx-tape.o: $(ares.path)/msx/tape/tape.cpp
|
||||
$(object.path)/ares-msx-rtc.o: $(ares.path)/msx/rtc/rtc.cpp
|
||||
@@ -1,15 +0,0 @@
|
||||
ares.components += z80
|
||||
ares.components += tms9918
|
||||
ares.components += ay38910
|
||||
|
||||
ares.objects += ares-myvision-cpu
|
||||
ares.objects += ares-myvision-vdp
|
||||
ares.objects += ares-myvision-psg
|
||||
ares.objects += ares-myvision-system
|
||||
ares.objects += ares-myvision-cartridge
|
||||
|
||||
$(object.path)/ares-myvision-cpu.o: $(ares.path)/myvision/cpu/cpu.cpp
|
||||
$(object.path)/ares-myvision-vdp.o: $(ares.path)/myvision/vdp/vdp.cpp
|
||||
$(object.path)/ares-myvision-psg.o: $(ares.path)/myvision/psg/psg.cpp
|
||||
$(object.path)/ares-myvision-system.o: $(ares.path)/myvision/system/system.cpp
|
||||
$(object.path)/ares-myvision-cartridge.o: $(ares.path)/myvision/cartridge/cartridge.cpp
|
||||
+421
-421
@@ -1,421 +1,421 @@
|
||||
ares_components(sm5k)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
UNITY #
|
||||
n64.cpp
|
||||
PRIMARY #
|
||||
memory/memory.cpp
|
||||
system/system.cpp
|
||||
cartridge/cartridge.cpp
|
||||
cic/cic.cpp
|
||||
controller/controller.cpp
|
||||
dd/dd.cpp
|
||||
mi/mi.cpp
|
||||
vi/vi.cpp
|
||||
ai/ai.cpp
|
||||
pi/pi.cpp
|
||||
pif/pif.cpp
|
||||
ri/ri.cpp
|
||||
si/si.cpp
|
||||
rdram/rdram.cpp
|
||||
cpu/cpu.cpp
|
||||
rsp/rsp.cpp
|
||||
rdp/rdp.cpp
|
||||
aleck64/aleck64.cpp
|
||||
)
|
||||
|
||||
target_enable_feature(ares "N64 Vulkan rendering with paraLLEl-RDP" VULKAN)
|
||||
target_compile_definitions(ares PUBLIC VULKAN)
|
||||
|
||||
if(OS_WINDOWS)
|
||||
include(cmake/os-windows.cmake)
|
||||
elseif(OS_MACOS)
|
||||
include(cmake/os-macos.cmake)
|
||||
elseif(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD)
|
||||
include(cmake/os-linux.cmake)
|
||||
endif()
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
n64.hpp
|
||||
CMakeLists.txt
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
ai/ai.hpp
|
||||
ai/debugger.cpp
|
||||
ai/io.cpp
|
||||
ai/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
aleck64/aleck64.hpp
|
||||
aleck64/controls.cpp
|
||||
aleck64/debugger.cpp
|
||||
aleck64/serialization.cpp
|
||||
aleck64/io.cpp
|
||||
aleck64/vdp.cpp
|
||||
aleck64/game-config/11beat.hpp
|
||||
aleck64/game-config/doncdoon.hpp
|
||||
aleck64/game-config/kurufev.hpp
|
||||
aleck64/game-config/mayjin3.hpp
|
||||
aleck64/game-config/starsldr.hpp
|
||||
aleck64/game-config/twrshaft.hpp
|
||||
aleck64/game-config/vivdolls.hpp
|
||||
aleck64/game-config/hipai.hpp
|
||||
aleck64/game-config/hipai2.hpp
|
||||
aleck64/game-config/srmvs.hpp
|
||||
aleck64/game-config/mtetrisc.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
cartridge/cartridge.hpp
|
||||
cartridge/debugger.cpp
|
||||
cartridge/flash.cpp
|
||||
cartridge/isviewer.cpp
|
||||
cartridge/joybus.cpp
|
||||
cartridge/rtc.cpp
|
||||
cartridge/serialization.cpp
|
||||
cartridge/slot.cpp
|
||||
cartridge/slot.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
cic/cic.hpp
|
||||
cic/commands.cpp
|
||||
cic/io.cpp
|
||||
cic/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/controller.hpp
|
||||
controller/port.cpp
|
||||
controller/port.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/aleck64/aleck64.cpp
|
||||
controller/aleck64/aleck64.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/gamepad/gamepad.cpp
|
||||
controller/gamepad/gamepad.hpp
|
||||
controller/gamepad/transfer-pak.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/mouse/mouse.cpp
|
||||
controller/mouse/mouse.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
cpu/algorithms.cpp
|
||||
cpu/context.cpp
|
||||
cpu/cpu.hpp
|
||||
cpu/dcache.cpp
|
||||
cpu/debugger.cpp
|
||||
cpu/disassembler.cpp
|
||||
cpu/exceptions.cpp
|
||||
cpu/interpreter-cop2.cpp
|
||||
cpu/interpreter-fpu.cpp
|
||||
cpu/interpreter-ipu.cpp
|
||||
cpu/interpreter-scc.cpp
|
||||
cpu/interpreter.cpp
|
||||
cpu/memory.cpp
|
||||
cpu/recompiler.cpp
|
||||
cpu/serialization.cpp
|
||||
cpu/tlb.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
dd/controller.cpp
|
||||
dd/dd.hpp
|
||||
dd/debugger.cpp
|
||||
dd/drive.cpp
|
||||
dd/io.cpp
|
||||
dd/rtc.cpp
|
||||
dd/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
memory/bus.hpp
|
||||
memory/io.hpp
|
||||
memory/memory.hpp
|
||||
memory/lsb/readable.hpp
|
||||
memory/lsb/writable.hpp
|
||||
memory/msb/readable.hpp
|
||||
memory/msb/writable.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
mi/debugger.cpp
|
||||
mi/io.cpp
|
||||
mi/mi.hpp
|
||||
mi/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
pi/bus.hpp
|
||||
pi/debugger.cpp
|
||||
pi/dma.cpp
|
||||
pi/io.cpp
|
||||
pi/pi.hpp
|
||||
pi/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
pif/debugger.cpp
|
||||
pif/hle.cpp
|
||||
pif/io.cpp
|
||||
pif/pif.hpp
|
||||
pif/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
rdp/debugger.cpp
|
||||
rdp/io.cpp
|
||||
rdp/rdp.hpp
|
||||
rdp/render.cpp
|
||||
rdp/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
rdram/debugger.cpp
|
||||
rdram/io.cpp
|
||||
rdram/rdram.hpp
|
||||
rdram/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
ri/debugger.cpp
|
||||
ri/io.cpp
|
||||
ri/ri.hpp
|
||||
ri/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
rsp/debugger.cpp
|
||||
rsp/decoder.cpp
|
||||
rsp/disassembler.cpp
|
||||
rsp/dma.cpp
|
||||
rsp/interpreter-ipu.cpp
|
||||
rsp/interpreter-scc.cpp
|
||||
rsp/interpreter-vpu.cpp
|
||||
rsp/interpreter.cpp
|
||||
rsp/io.cpp
|
||||
rsp/recompiler.cpp
|
||||
rsp/rsp.hpp
|
||||
rsp/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
si/debugger.cpp
|
||||
si/dma.cpp
|
||||
si/io.cpp
|
||||
si/serialization.cpp
|
||||
si/si.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
system/serialization.cpp
|
||||
system/system.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
vi/debugger.cpp
|
||||
vi/io.cpp
|
||||
vi/serialization.cpp
|
||||
vi/vi.hpp
|
||||
)
|
||||
|
||||
target_compile_definitions(ares PRIVATE VULKAN)
|
||||
|
||||
set(
|
||||
_parallel_rdp_sources
|
||||
vulkan/vulkan.cpp
|
||||
vulkan/vulkan.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/command_ring.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_device.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_dump_write.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_renderer.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/video_interface.cpp
|
||||
vulkan/parallel-rdp/vulkan/buffer.cpp
|
||||
vulkan/parallel-rdp/vulkan/buffer_pool.cpp
|
||||
vulkan/parallel-rdp/vulkan/command_buffer.cpp
|
||||
vulkan/parallel-rdp/vulkan/command_pool.cpp
|
||||
vulkan/parallel-rdp/vulkan/context.cpp
|
||||
vulkan/parallel-rdp/vulkan/cookie.cpp
|
||||
vulkan/parallel-rdp/vulkan/descriptor_set.cpp
|
||||
vulkan/parallel-rdp/vulkan/device.cpp
|
||||
vulkan/parallel-rdp/vulkan/event_manager.cpp
|
||||
vulkan/parallel-rdp/vulkan/fence.cpp
|
||||
vulkan/parallel-rdp/vulkan/fence_manager.cpp
|
||||
vulkan/parallel-rdp/vulkan/image.cpp
|
||||
vulkan/parallel-rdp/vulkan/indirect_layout.cpp
|
||||
vulkan/parallel-rdp/vulkan/memory_allocator.cpp
|
||||
vulkan/parallel-rdp/vulkan/pipeline_event.cpp
|
||||
vulkan/parallel-rdp/vulkan/query_pool.cpp
|
||||
vulkan/parallel-rdp/vulkan/render_pass.cpp
|
||||
vulkan/parallel-rdp/vulkan/sampler.cpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore.cpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore_manager.cpp
|
||||
vulkan/parallel-rdp/vulkan/shader.cpp
|
||||
vulkan/parallel-rdp/vulkan/texture/texture_format.cpp
|
||||
vulkan/parallel-rdp/util/arena_allocator.cpp
|
||||
vulkan/parallel-rdp/util/logging.cpp
|
||||
vulkan/parallel-rdp/util/thread_id.cpp
|
||||
vulkan/parallel-rdp/util/aligned_alloc.cpp
|
||||
vulkan/parallel-rdp/util/timer.cpp
|
||||
vulkan/parallel-rdp/util/timeline_trace_file.cpp
|
||||
vulkan/parallel-rdp/util/thread_name.cpp
|
||||
vulkan/parallel-rdp/util/environment.cpp
|
||||
vulkan/parallel-rdp/volk/volk.c
|
||||
)
|
||||
|
||||
if(ARES_UNITY_CORES)
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
UNITY #
|
||||
${_parallel_rdp_sources}
|
||||
)
|
||||
else()
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
PRIMARY #
|
||||
${_parallel_rdp_sources}
|
||||
)
|
||||
endif()
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
PRIMARY #
|
||||
vulkan/parallel-rdp/parallel-rdp/command_ring.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_device.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_dump_write.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_renderer.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/video_interface.hpp
|
||||
vulkan/parallel-rdp/vulkan/buffer.hpp
|
||||
vulkan/parallel-rdp/vulkan/buffer_pool.hpp
|
||||
vulkan/parallel-rdp/vulkan/command_buffer.hpp
|
||||
vulkan/parallel-rdp/vulkan/command_pool.hpp
|
||||
vulkan/parallel-rdp/vulkan/context.hpp
|
||||
vulkan/parallel-rdp/vulkan/cookie.hpp
|
||||
vulkan/parallel-rdp/vulkan/descriptor_set.hpp
|
||||
vulkan/parallel-rdp/vulkan/device.hpp
|
||||
vulkan/parallel-rdp/vulkan/event_manager.hpp
|
||||
vulkan/parallel-rdp/vulkan/fence.hpp
|
||||
vulkan/parallel-rdp/vulkan/fence_manager.hpp
|
||||
vulkan/parallel-rdp/vulkan/image.hpp
|
||||
vulkan/parallel-rdp/vulkan/indirect_layout.hpp
|
||||
vulkan/parallel-rdp/vulkan/memory_allocator.hpp
|
||||
vulkan/parallel-rdp/vulkan/pipeline_event.hpp
|
||||
vulkan/parallel-rdp/vulkan/query_pool.hpp
|
||||
vulkan/parallel-rdp/vulkan/render_pass.hpp
|
||||
vulkan/parallel-rdp/vulkan/sampler.hpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore.hpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore_manager.hpp
|
||||
vulkan/parallel-rdp/vulkan/shader.hpp
|
||||
vulkan/parallel-rdp/vulkan/texture/texture_format.hpp
|
||||
vulkan/parallel-rdp/util/arena_allocator.hpp
|
||||
vulkan/parallel-rdp/util/logging.hpp
|
||||
vulkan/parallel-rdp/util/thread_id.hpp
|
||||
vulkan/parallel-rdp/util/aligned_alloc.hpp
|
||||
vulkan/parallel-rdp/util/timer.hpp
|
||||
vulkan/parallel-rdp/util/timeline_trace_file.hpp
|
||||
vulkan/parallel-rdp/util/thread_name.hpp
|
||||
vulkan/parallel-rdp/util/environment.hpp
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
ares
|
||||
PRIVATE
|
||||
vulkan/parallel-rdp/parallel-rdp
|
||||
vulkan/parallel-rdp/volk
|
||||
vulkan/parallel-rdp/vulkan
|
||||
vulkan/parallel-rdp/vulkan-headers/include
|
||||
vulkan/parallel-rdp/util
|
||||
)
|
||||
|
||||
target_compile_options(ares PRIVATE $<$<CXX_COMPILER_ID:Clang,AppleClang>:-Wno-newline-eof>)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(ares PUBLIC Threads::Threads)
|
||||
|
||||
if(OS_WINDOWS)
|
||||
target_compile_definitions(ares PRIVATE VK_USE_PLATFORM_WIN32_KHR)
|
||||
target_link_libraries(ares PRIVATE winmm)
|
||||
else()
|
||||
target_link_libraries(ares PRIVATE dl)
|
||||
endif()
|
||||
ares_components(sm5k)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
UNITY #
|
||||
n64.cpp
|
||||
PRIMARY #
|
||||
memory/memory.cpp
|
||||
system/system.cpp
|
||||
cartridge/cartridge.cpp
|
||||
cic/cic.cpp
|
||||
controller/controller.cpp
|
||||
dd/dd.cpp
|
||||
mi/mi.cpp
|
||||
vi/vi.cpp
|
||||
ai/ai.cpp
|
||||
pi/pi.cpp
|
||||
pif/pif.cpp
|
||||
ri/ri.cpp
|
||||
si/si.cpp
|
||||
rdram/rdram.cpp
|
||||
cpu/cpu.cpp
|
||||
rsp/rsp.cpp
|
||||
rdp/rdp.cpp
|
||||
aleck64/aleck64.cpp
|
||||
)
|
||||
|
||||
target_enable_feature(ares "N64 Vulkan rendering with paraLLEl-RDP" VULKAN)
|
||||
target_compile_definitions(ares PUBLIC VULKAN)
|
||||
|
||||
if(OS_WINDOWS)
|
||||
include(cmake/os-windows.cmake)
|
||||
elseif(OS_MACOS)
|
||||
include(cmake/os-macos.cmake)
|
||||
elseif(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD)
|
||||
include(cmake/os-linux.cmake)
|
||||
endif()
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
n64.hpp
|
||||
CMakeLists.txt
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
ai/ai.hpp
|
||||
ai/debugger.cpp
|
||||
ai/io.cpp
|
||||
ai/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
aleck64/aleck64.hpp
|
||||
aleck64/controls.cpp
|
||||
aleck64/debugger.cpp
|
||||
aleck64/serialization.cpp
|
||||
aleck64/io.cpp
|
||||
aleck64/vdp.cpp
|
||||
aleck64/game-config/11beat.hpp
|
||||
aleck64/game-config/doncdoon.hpp
|
||||
aleck64/game-config/kurufev.hpp
|
||||
aleck64/game-config/mayjin3.hpp
|
||||
aleck64/game-config/starsldr.hpp
|
||||
aleck64/game-config/twrshaft.hpp
|
||||
aleck64/game-config/vivdolls.hpp
|
||||
aleck64/game-config/hipai.hpp
|
||||
aleck64/game-config/hipai2.hpp
|
||||
aleck64/game-config/srmvs.hpp
|
||||
aleck64/game-config/mtetrisc.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
cartridge/cartridge.hpp
|
||||
cartridge/debugger.cpp
|
||||
cartridge/flash.cpp
|
||||
cartridge/isviewer.cpp
|
||||
cartridge/joybus.cpp
|
||||
cartridge/rtc.cpp
|
||||
cartridge/serialization.cpp
|
||||
cartridge/slot.cpp
|
||||
cartridge/slot.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
cic/cic.hpp
|
||||
cic/commands.cpp
|
||||
cic/io.cpp
|
||||
cic/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/controller.hpp
|
||||
controller/port.cpp
|
||||
controller/port.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/aleck64/aleck64.cpp
|
||||
controller/aleck64/aleck64.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/gamepad/gamepad.cpp
|
||||
controller/gamepad/gamepad.hpp
|
||||
controller/gamepad/transfer-pak.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
controller/mouse/mouse.cpp
|
||||
controller/mouse/mouse.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
cpu/algorithms.cpp
|
||||
cpu/context.cpp
|
||||
cpu/cpu.hpp
|
||||
cpu/dcache.cpp
|
||||
cpu/debugger.cpp
|
||||
cpu/disassembler.cpp
|
||||
cpu/exceptions.cpp
|
||||
cpu/interpreter-cop2.cpp
|
||||
cpu/interpreter-fpu.cpp
|
||||
cpu/interpreter-ipu.cpp
|
||||
cpu/interpreter-scc.cpp
|
||||
cpu/interpreter.cpp
|
||||
cpu/memory.cpp
|
||||
cpu/recompiler.cpp
|
||||
cpu/serialization.cpp
|
||||
cpu/tlb.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
dd/controller.cpp
|
||||
dd/dd.hpp
|
||||
dd/debugger.cpp
|
||||
dd/drive.cpp
|
||||
dd/io.cpp
|
||||
dd/rtc.cpp
|
||||
dd/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
memory/bus.hpp
|
||||
memory/io.hpp
|
||||
memory/memory.hpp
|
||||
memory/lsb/readable.hpp
|
||||
memory/lsb/writable.hpp
|
||||
memory/msb/readable.hpp
|
||||
memory/msb/writable.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
mi/debugger.cpp
|
||||
mi/io.cpp
|
||||
mi/mi.hpp
|
||||
mi/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
pi/bus.hpp
|
||||
pi/debugger.cpp
|
||||
pi/dma.cpp
|
||||
pi/io.cpp
|
||||
pi/pi.hpp
|
||||
pi/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
pif/debugger.cpp
|
||||
pif/hle.cpp
|
||||
pif/io.cpp
|
||||
pif/pif.hpp
|
||||
pif/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
rdp/debugger.cpp
|
||||
rdp/io.cpp
|
||||
rdp/rdp.hpp
|
||||
rdp/render.cpp
|
||||
rdp/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
rdram/debugger.cpp
|
||||
rdram/io.cpp
|
||||
rdram/rdram.hpp
|
||||
rdram/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
ri/debugger.cpp
|
||||
ri/io.cpp
|
||||
ri/ri.hpp
|
||||
ri/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
rsp/debugger.cpp
|
||||
rsp/decoder.cpp
|
||||
rsp/disassembler.cpp
|
||||
rsp/dma.cpp
|
||||
rsp/interpreter-ipu.cpp
|
||||
rsp/interpreter-scc.cpp
|
||||
rsp/interpreter-vpu.cpp
|
||||
rsp/interpreter.cpp
|
||||
rsp/io.cpp
|
||||
rsp/recompiler.cpp
|
||||
rsp/rsp.hpp
|
||||
rsp/serialization.cpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
si/debugger.cpp
|
||||
si/dma.cpp
|
||||
si/io.cpp
|
||||
si/serialization.cpp
|
||||
si/si.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
system/serialization.cpp
|
||||
system/system.hpp
|
||||
)
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
INCLUDED #
|
||||
vi/debugger.cpp
|
||||
vi/io.cpp
|
||||
vi/serialization.cpp
|
||||
vi/vi.hpp
|
||||
)
|
||||
|
||||
target_compile_definitions(ares PRIVATE VULKAN)
|
||||
|
||||
set(
|
||||
_parallel_rdp_sources
|
||||
vulkan/vulkan.cpp
|
||||
vulkan/vulkan.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/command_ring.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_device.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_dump_write.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_renderer.cpp
|
||||
vulkan/parallel-rdp/parallel-rdp/video_interface.cpp
|
||||
vulkan/parallel-rdp/vulkan/buffer.cpp
|
||||
vulkan/parallel-rdp/vulkan/buffer_pool.cpp
|
||||
vulkan/parallel-rdp/vulkan/command_buffer.cpp
|
||||
vulkan/parallel-rdp/vulkan/command_pool.cpp
|
||||
vulkan/parallel-rdp/vulkan/context.cpp
|
||||
vulkan/parallel-rdp/vulkan/cookie.cpp
|
||||
vulkan/parallel-rdp/vulkan/descriptor_set.cpp
|
||||
vulkan/parallel-rdp/vulkan/device.cpp
|
||||
vulkan/parallel-rdp/vulkan/event_manager.cpp
|
||||
vulkan/parallel-rdp/vulkan/fence.cpp
|
||||
vulkan/parallel-rdp/vulkan/fence_manager.cpp
|
||||
vulkan/parallel-rdp/vulkan/image.cpp
|
||||
vulkan/parallel-rdp/vulkan/indirect_layout.cpp
|
||||
vulkan/parallel-rdp/vulkan/memory_allocator.cpp
|
||||
vulkan/parallel-rdp/vulkan/pipeline_event.cpp
|
||||
vulkan/parallel-rdp/vulkan/query_pool.cpp
|
||||
vulkan/parallel-rdp/vulkan/render_pass.cpp
|
||||
vulkan/parallel-rdp/vulkan/sampler.cpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore.cpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore_manager.cpp
|
||||
vulkan/parallel-rdp/vulkan/shader.cpp
|
||||
vulkan/parallel-rdp/vulkan/texture/texture_format.cpp
|
||||
vulkan/parallel-rdp/util/arena_allocator.cpp
|
||||
vulkan/parallel-rdp/util/logging.cpp
|
||||
vulkan/parallel-rdp/util/thread_id.cpp
|
||||
vulkan/parallel-rdp/util/aligned_alloc.cpp
|
||||
vulkan/parallel-rdp/util/timer.cpp
|
||||
vulkan/parallel-rdp/util/timeline_trace_file.cpp
|
||||
vulkan/parallel-rdp/util/thread_name.cpp
|
||||
vulkan/parallel-rdp/util/environment.cpp
|
||||
vulkan/parallel-rdp/volk/volk.c
|
||||
)
|
||||
|
||||
if(ARES_UNITY_CORES)
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
UNITY #
|
||||
${_parallel_rdp_sources}
|
||||
)
|
||||
else()
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
PRIMARY #
|
||||
${_parallel_rdp_sources}
|
||||
)
|
||||
endif()
|
||||
|
||||
ares_add_sources(
|
||||
CORE #
|
||||
n64
|
||||
PRIMARY #
|
||||
vulkan/parallel-rdp/parallel-rdp/command_ring.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_device.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_dump_write.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/rdp_renderer.hpp
|
||||
vulkan/parallel-rdp/parallel-rdp/video_interface.hpp
|
||||
vulkan/parallel-rdp/vulkan/buffer.hpp
|
||||
vulkan/parallel-rdp/vulkan/buffer_pool.hpp
|
||||
vulkan/parallel-rdp/vulkan/command_buffer.hpp
|
||||
vulkan/parallel-rdp/vulkan/command_pool.hpp
|
||||
vulkan/parallel-rdp/vulkan/context.hpp
|
||||
vulkan/parallel-rdp/vulkan/cookie.hpp
|
||||
vulkan/parallel-rdp/vulkan/descriptor_set.hpp
|
||||
vulkan/parallel-rdp/vulkan/device.hpp
|
||||
vulkan/parallel-rdp/vulkan/event_manager.hpp
|
||||
vulkan/parallel-rdp/vulkan/fence.hpp
|
||||
vulkan/parallel-rdp/vulkan/fence_manager.hpp
|
||||
vulkan/parallel-rdp/vulkan/image.hpp
|
||||
vulkan/parallel-rdp/vulkan/indirect_layout.hpp
|
||||
vulkan/parallel-rdp/vulkan/memory_allocator.hpp
|
||||
vulkan/parallel-rdp/vulkan/pipeline_event.hpp
|
||||
vulkan/parallel-rdp/vulkan/query_pool.hpp
|
||||
vulkan/parallel-rdp/vulkan/render_pass.hpp
|
||||
vulkan/parallel-rdp/vulkan/sampler.hpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore.hpp
|
||||
vulkan/parallel-rdp/vulkan/semaphore_manager.hpp
|
||||
vulkan/parallel-rdp/vulkan/shader.hpp
|
||||
vulkan/parallel-rdp/vulkan/texture/texture_format.hpp
|
||||
vulkan/parallel-rdp/util/arena_allocator.hpp
|
||||
vulkan/parallel-rdp/util/logging.hpp
|
||||
vulkan/parallel-rdp/util/thread_id.hpp
|
||||
vulkan/parallel-rdp/util/aligned_alloc.hpp
|
||||
vulkan/parallel-rdp/util/timer.hpp
|
||||
vulkan/parallel-rdp/util/timeline_trace_file.hpp
|
||||
vulkan/parallel-rdp/util/thread_name.hpp
|
||||
vulkan/parallel-rdp/util/environment.hpp
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
ares
|
||||
PRIVATE
|
||||
vulkan/parallel-rdp/parallel-rdp
|
||||
vulkan/parallel-rdp/volk
|
||||
vulkan/parallel-rdp/vulkan
|
||||
vulkan/parallel-rdp/vulkan-headers/include
|
||||
vulkan/parallel-rdp/util
|
||||
)
|
||||
|
||||
target_compile_options(ares PRIVATE $<$<CXX_COMPILER_ID:Clang,AppleClang>:-Wno-newline-eof>)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(ares PUBLIC Threads::Threads)
|
||||
|
||||
if(OS_WINDOWS)
|
||||
target_compile_definitions(ares PRIVATE VK_USE_PLATFORM_WIN32_KHR)
|
||||
target_link_libraries(ares PRIVATE winmm)
|
||||
else()
|
||||
target_link_libraries(ares PRIVATE dl)
|
||||
endif()
|
||||
@@ -1,99 +0,0 @@
|
||||
ares.components += sm5k
|
||||
|
||||
ares.objects += ares-n64-memory
|
||||
ares.objects += ares-n64-system
|
||||
ares.objects += ares-n64-cartridge
|
||||
ares.objects += ares-n64-cic
|
||||
ares.objects += ares-n64-controller
|
||||
ares.objects += ares-n64-dd
|
||||
ares.objects += ares-n64-mi
|
||||
ares.objects += ares-n64-vi
|
||||
ares.objects += ares-n64-ai
|
||||
ares.objects += ares-n64-pi
|
||||
ares.objects += ares-n64-pif
|
||||
ares.objects += ares-n64-ri
|
||||
ares.objects += ares-n64-si
|
||||
ares.objects += ares-n64-rdram
|
||||
ares.objects += ares-n64-cpu
|
||||
ares.objects += ares-n64-rsp
|
||||
ares.objects += ares-n64-rdp
|
||||
ares.objects += ares-n64-aleck64
|
||||
|
||||
$(object.path)/ares-n64-memory.o: $(ares.path)/n64/memory/memory.cpp
|
||||
$(object.path)/ares-n64-system.o: $(ares.path)/n64/system/system.cpp
|
||||
$(object.path)/ares-n64-cartridge.o: $(ares.path)/n64/cartridge/cartridge.cpp
|
||||
$(object.path)/ares-n64-cic.o: $(ares.path)/n64/cic/cic.cpp
|
||||
$(object.path)/ares-n64-controller.o: $(ares.path)/n64/controller/controller.cpp
|
||||
$(object.path)/ares-n64-dd.o: $(ares.path)/n64/dd/dd.cpp
|
||||
$(object.path)/ares-n64-sp.o: $(ares.path)/n64/sp/sp.cpp
|
||||
$(object.path)/ares-n64-dp.o: $(ares.path)/n64/dp/dp.cpp
|
||||
$(object.path)/ares-n64-mi.o: $(ares.path)/n64/mi/mi.cpp
|
||||
$(object.path)/ares-n64-vi.o: $(ares.path)/n64/vi/vi.cpp
|
||||
$(object.path)/ares-n64-ai.o: $(ares.path)/n64/ai/ai.cpp
|
||||
$(object.path)/ares-n64-pi.o: $(ares.path)/n64/pi/pi.cpp
|
||||
$(object.path)/ares-n64-pif.o: $(ares.path)/n64/pif/pif.cpp
|
||||
$(object.path)/ares-n64-ri.o: $(ares.path)/n64/ri/ri.cpp
|
||||
$(object.path)/ares-n64-si.o: $(ares.path)/n64/si/si.cpp
|
||||
$(object.path)/ares-n64-rdram.o: $(ares.path)/n64/rdram/rdram.cpp
|
||||
$(object.path)/ares-n64-cpu.o: $(ares.path)/n64/cpu/cpu.cpp
|
||||
$(object.path)/ares-n64-rsp.o: $(ares.path)/n64/rsp/rsp.cpp
|
||||
$(object.path)/ares-n64-rdp.o: $(ares.path)/n64/rdp/rdp.cpp
|
||||
$(object.path)/ares-n64-aleck64.o: $(ares.path)/n64/aleck64/aleck64.cpp
|
||||
|
||||
ifeq ($(vulkan),true)
|
||||
ifeq ($(platform),macos)
|
||||
molten = $(ares.path)/../thirdparty/MoltenVK/libMoltenVK.dylib
|
||||
ifeq ($(wildcard $(molten)),)
|
||||
molten = $(shell brew --prefix molten-vk)/lib/libMoltenVK.dylib
|
||||
ifeq ($(wildcard $(molten)),)
|
||||
$(error Compiling Ares N64 Vulkan backend requires MoltenVK. Install it via Homebrew, compile it using thirdparty/MoltenVK/build-moltenvk.sh, or disable with vulkan=false")
|
||||
endif
|
||||
endif
|
||||
ares.dylibs += $(molten)
|
||||
endif
|
||||
ares.objects += ares-n64-vulkan
|
||||
$(object.path)/ares-n64-vulkan.o: $(ares.path)/n64/vulkan/vulkan.cpp
|
||||
PARALLEL_RDP_IMPLEMENTATION := $(ares.path)/n64/vulkan/parallel-rdp
|
||||
include $(PARALLEL_RDP_IMPLEMENTATION)/config.mk
|
||||
ares.objects += $(PARALLEL_RDP_SOURCES_CXX:$(PARALLEL_RDP_IMPLEMENTATION)/%.cpp=ares-n64-parallel-rdp/%)
|
||||
ares.objects += $(PARALLEL_RDP_SOURCES_C:$(PARALLEL_RDP_IMPLEMENTATION)/%.c=ares-n64-parallel-rdp/%)
|
||||
flags += $(PARALLEL_RDP_INCLUDE_DIRS) $(PARALLEL_RDP_CXXFLAGS) $(PARALLEL_RDP_CFLAGS)
|
||||
$(object.path)/ares-n64-parallel-rdp/volk/volk.o: $(PARALLEL_RDP_IMPLEMENTATION)/volk/volk.c
|
||||
$(object.path)/ares-n64-parallel-rdp/parallel-rdp/video_interface.o: $(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp/video_interface.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/parallel-rdp/command_ring.o: $(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp/command_ring.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/parallel-rdp/rdp_device.o: $(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp/rdp_device.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/parallel-rdp/rdp_dump_write.o: $(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp/rdp_dump_write.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/parallel-rdp/rdp_renderer.o: $(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp/rdp_renderer.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/buffer.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/buffer.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/buffer_pool.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/buffer_pool.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/command_buffer.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/command_buffer.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/command_pool.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/command_pool.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/context.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/context.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/cookie.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/cookie.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/descriptor_set.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/descriptor_set.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/device.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/device.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/event_manager.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/event_manager.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/fence.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/fence.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/fence_manager.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/fence_manager.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/image.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/image.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/indirect_layout.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/indirect_layout.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/memory_allocator.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/memory_allocator.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/pipeline_event.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/pipeline_event.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/query_pool.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/query_pool.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/render_pass.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/render_pass.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/sampler.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/sampler.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/semaphore.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/semaphore.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/semaphore_manager.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/semaphore_manager.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/shader.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/shader.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/vulkan/texture/texture_format.o: $(PARALLEL_RDP_IMPLEMENTATION)/vulkan/texture/texture_format.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/arena_allocator.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/arena_allocator.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/logging.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/logging.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/thread_id.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/thread_id.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/aligned_alloc.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/aligned_alloc.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/timer.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/timer.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/timeline_trace_file.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/timeline_trace_file.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/environment.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/environment.cpp
|
||||
$(object.path)/ares-n64-parallel-rdp/util/thread_name.o: $(PARALLEL_RDP_IMPLEMENTATION)/util/thread_name.cpp
|
||||
else
|
||||
$(warning Ares n64 core requires Vulkan for RDP emulation, only titles using Software Rendering will function)
|
||||
endif
|
||||
@@ -26,5 +26,7 @@ struct Accuracy {
|
||||
struct PIF {
|
||||
// Emulate a region-locked console
|
||||
static constexpr bool RegionLock = false;
|
||||
// Emulate the PIF's checksum security check
|
||||
static constexpr bool IPL2Checksum = true;
|
||||
};
|
||||
};
|
||||
@@ -54,7 +54,7 @@ auto Cartridge::joybusComm(n8 send, n8 recv, n8 input[], n8 output[]) -> n2 {
|
||||
if(input[0] == 0x07 && send >= 2 && recv >= 9) {
|
||||
if(cartridge.rtc.present) {
|
||||
rtc.read(input[1], &output[0]);
|
||||
output[8] = 0x00;
|
||||
output[8] = rtc.status;
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ auto Cartridge::joybusComm(n8 send, n8 recv, n8 input[], n8 output[]) -> n2 {
|
||||
if(input[0] == 0x08 && send >= 10 && recv >= 1) {
|
||||
if(cartridge.rtc.present) {
|
||||
rtc.write(input[1], &input[2]);
|
||||
output[0] = 0x00;
|
||||
output[0] = rtc.status;
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ Gamepad::Gamepad(Node::Port parent) {
|
||||
port->setDisconnect([&] { return disconnect(); });
|
||||
port->setSupported({"Controller Pak", "Rumble Pak", "Transfer Pak"});
|
||||
|
||||
bank = 0;
|
||||
|
||||
x = node->append<Node::Input::Axis> ("X-Axis");
|
||||
y = node->append<Node::Input::Axis> ("Y-Axis");
|
||||
up = node->append<Node::Input::Button>("Up");
|
||||
@@ -54,12 +56,56 @@ auto Gamepad::allocate(string name) -> Node::Peripheral {
|
||||
auto Gamepad::connect() -> void {
|
||||
if(!slot) return;
|
||||
if(slot->name() == "Controller Pak") {
|
||||
bool create = true;
|
||||
|
||||
node->setPak(pak = platform->pak(node));
|
||||
ram.allocate(32_KiB);
|
||||
system.controllerPakBankCount = system.configuredControllerPakBankCount; //reset controller bank count
|
||||
ram.allocate(system.controllerPakBankCount * 32_KiB); //allocate N banks * 32KiB, max # of banks allowed is 62
|
||||
bank = 0;
|
||||
formatControllerPak();
|
||||
if(auto fp = pak->read("save.pak")) {
|
||||
if(fp->attribute("loaded").boolean()) {
|
||||
//read the bank count
|
||||
u8 banks;
|
||||
u32 bank_size;
|
||||
|
||||
fp->seek(0x20 + 0x1A);
|
||||
fp->read(array_span<u8>{&banks, sizeof(banks)});
|
||||
fp->seek(0);
|
||||
|
||||
if (banks < 1) {
|
||||
banks = 1;
|
||||
} else if (banks > 62) {
|
||||
banks = 62;
|
||||
}
|
||||
|
||||
bank_size = 32_KiB * banks;
|
||||
|
||||
if (bank_size != ram.size) {
|
||||
ram.allocate(bank_size);
|
||||
|
||||
//update the system controller bank count
|
||||
system.controllerPakBankCount = banks;
|
||||
}
|
||||
ram.load(pak->read("save.pak"));
|
||||
|
||||
if (fp->size() != bank_size) {
|
||||
//reallocate vfs node
|
||||
pak->remove(fp);
|
||||
pak->append("save.pak", bank_size);
|
||||
ram.save(pak->write("save.pak")); //write data back to filesystem
|
||||
}
|
||||
|
||||
create = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (create) {
|
||||
//we need to create a controller pak file, so reallocate the vfs file to configured size
|
||||
if (auto fp = pak->read("save.pak")) {
|
||||
pak->remove(fp);
|
||||
pak->append("save.pak", system.controllerPakBankCount * 32_KiB);
|
||||
ram.save(pak->write("save.pak"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +178,8 @@ auto Gamepad::comm(n8 send, n8 recv, n8 input[], n8 output[]) -> n2 {
|
||||
u16 address = (input[1] << 8 | input[2] << 0) & ~31;
|
||||
if(pif.addressCRC(address) == (n5)input[2]) {
|
||||
for(u32 index : range(recv - 1)) {
|
||||
if(address <= 0x7FFF) output[index] = ram.read<Byte>(address);
|
||||
// read into current bank
|
||||
if(address <= 0x7FFF) output[index] = ram.read<Byte>(bank * 32_KiB + address);
|
||||
else output[index] = 0;
|
||||
address++;
|
||||
}
|
||||
@@ -173,12 +220,46 @@ auto Gamepad::comm(n8 send, n8 recv, n8 input[], n8 output[]) -> n2 {
|
||||
if(ram) {
|
||||
u16 address = (input[1] << 8 | input[2] << 0) & ~31;
|
||||
if(pif.addressCRC(address) == (n5)input[2]) {
|
||||
for(u32 index : range(send - 3)) {
|
||||
if(address <= 0x7FFF) ram.write<Byte>(address, input[3 + index]);
|
||||
address++;
|
||||
//check if address is bank switch command
|
||||
if (address == 0x8000) {
|
||||
if (send >= 4) {
|
||||
u8 reqBank = input[3];
|
||||
if (reqBank < system.controllerPakBankCount) {
|
||||
bank = reqBank;
|
||||
}
|
||||
} else {
|
||||
if (system.homebrewMode) {
|
||||
debug(unusual, "Controller Pak bank switch command with no bank specified");
|
||||
}
|
||||
bank = 0;
|
||||
}
|
||||
|
||||
if (system.homebrewMode) {
|
||||
//Verify we have 32 bytes (1 block) input and each value is the same bank
|
||||
if (send == 35) {
|
||||
u8 bank = input[3];
|
||||
for (u32 i = 4; i < 35; i++) {
|
||||
if (input[i] != bank) {
|
||||
debug(unusual, "Controller Pak bank switch command with mismatched data");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug(unusual, "Controller Pak bank switch command with invalid data length");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output[0] = pif.dataCRC({&input[3], send - 3u});
|
||||
valid = 1;
|
||||
} else {
|
||||
for(u32 index : range(send - 3)) {
|
||||
if(address <= 0x7FFF) ram.write<Byte>(bank * 32_KiB + address, input[3 + index]);
|
||||
address++;
|
||||
}
|
||||
output[0] = pif.dataCRC({&input[3], send - 3u});
|
||||
valid = 1;
|
||||
}
|
||||
output[0] = pif.dataCRC({&input[3], send - 3u});
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,8 +396,24 @@ auto Gamepad::read() -> n32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
//controller paks contain 32KB of SRAM split into 128 pages of 256 bytes each.
|
||||
//the first 5 pages are for storing system data, and the remaining 123 for game data.
|
||||
auto Gamepad::getInodeChecksum(u8 bank) -> u8 {
|
||||
if (bank < 62) {
|
||||
u32 checksum = 0;
|
||||
u32 i = bank == 0 ? 3 + ram.read<Byte>(0x20 + 0x1a) * 2 : 1; //first bank has 3 + bank * 2 system pages, other banks have 127.
|
||||
|
||||
for (i; i < 0x100; i++) {
|
||||
checksum += ram.read<Byte>((1 + bank) * 0x100) + ram.read<Byte>((1 + bank) * 0x100 + 0x01);
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//controller paks contain 32KB * nBanks of SRAM split into 128 pages of 256 bytes each.
|
||||
//the first 3 + nBanks * 2 pages of bank 0 are for storing system data, and the remaining 123 for game data.
|
||||
//the remaining banks page 0 is unused and the remaining 127 are for game data.
|
||||
auto Gamepad::formatControllerPak() -> void {
|
||||
ram.fill(0x00);
|
||||
|
||||
@@ -325,12 +422,12 @@ auto Gamepad::formatControllerPak() -> void {
|
||||
n19 fieldB = random();
|
||||
n27 fieldC = random();
|
||||
for(u32 area : array<u8[4]>{1,3,4,6}) {
|
||||
ram.write<Byte>(area * 0x20 + 0x01, fieldA); //unknown
|
||||
ram.write<Word>(area * 0x20 + 0x04, fieldB); //serial# hi
|
||||
ram.write<Word>(area * 0x20 + 0x08, fieldC); //serial# lo
|
||||
ram.write<Half>(area * 0x20 + 0x18, 0x0001); //device ID
|
||||
ram.write<Byte>(area * 0x20 + 0x1a, 0x01); //banks (0x01 = 32KB)
|
||||
ram.write<Byte>(area * 0x20 + 0x1b, 0x00); //version#
|
||||
ram.write<Byte>(area * 0x20 + 0x01, fieldA); //unknown
|
||||
ram.write<Word>(area * 0x20 + 0x04, fieldB); //serial# hi
|
||||
ram.write<Word>(area * 0x20 + 0x08, fieldC); //serial# lo
|
||||
ram.write<Half>(area * 0x20 + 0x18, 0x0001); //device ID
|
||||
ram.write<Byte>(area * 0x20 + 0x1a, system.controllerPakBankCount); //banks (0x01 = 32KB), (62 = max banks)
|
||||
ram.write<Byte>(area * 0x20 + 0x1b, 0x00); //version#
|
||||
u16 checksum = 0;
|
||||
u16 inverted = 0;
|
||||
for(u32 half : range(14)) {
|
||||
@@ -342,16 +439,25 @@ auto Gamepad::formatControllerPak() -> void {
|
||||
ram.write<Half>(area * 0x20 + 0x1e, inverted);
|
||||
}
|
||||
|
||||
//pages 1+2 (inode table)
|
||||
for(u32 page : array<u8[2]>{1,2}) {
|
||||
ram.write<Byte>(0x100 * page + 0x01, 0x71); //unknown
|
||||
for(u32 slot : range(5,128)) {
|
||||
ram.write<Byte>(0x100 * page + slot * 2 + 0x01, 0x03); //0x01 = stop, 0x03 = empty
|
||||
//pages 1 thru nBanks, nBanks+1 thru (nBanks*2) (inode table, inode table copy)
|
||||
u8 nBanks = ram.read<Byte>(0x20 + 0x1a);
|
||||
u32 inodeTablePage = 1;
|
||||
u32 inodeTableCopyPage = 1 + nBanks * 2;
|
||||
for(u32 bank : range(0,nBanks)) {
|
||||
u32 firstDataPage = bank == 0 ? (3 + nBanks * 2) : 1; //first bank has 3 + bank * 2 system pages, other banks have 127.
|
||||
for(u32 page : array<u32[2]>{inodeTablePage + bank, inodeTableCopyPage + bank}) {
|
||||
for(u32 slot : range(firstDataPage,128)) {
|
||||
ram.write<Byte>(0x100 * page + slot * 2 + 0x01, 0x03); //0x01 = stop, 0x03 = empty
|
||||
}
|
||||
ram.write<Byte>(0x100 * page + 0x01, getInodeChecksum(bank)); //checksum
|
||||
}
|
||||
}
|
||||
|
||||
//pages 3+4 (note table)
|
||||
//pages 5-127 (game saves)
|
||||
//page 1 is pak info and serial
|
||||
//pages 2-nBanks are for the inode table
|
||||
//pages at nBanks+1,2*nBanks are for the inode table backup
|
||||
//pages at 2*nBanks+1, 2*nBanks+2 are for note table
|
||||
//pages 3 + 2*nBanks are for save data
|
||||
}
|
||||
|
||||
auto Gamepad::serialize(serializer& s) -> void {
|
||||
|
||||
Loaded 100 of 4440 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user