mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-09 09:19:42 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f533120df6 | ||
|
|
ec37caccfb | ||
|
|
d0b9669c50 | ||
|
|
dfb355495a | ||
|
|
0f618995f4 | ||
|
|
35ead94515 | ||
|
|
6c8ccc1c7e | ||
|
|
361fb49fd0 | ||
|
|
90139d028d | ||
|
|
d03915bde9 | ||
|
|
8a7549fb21 | ||
|
|
6003e6933b | ||
|
|
35671b2f8d | ||
|
|
43686810d2 | ||
|
|
9bd2afee61 | ||
|
|
7bcb9ae39f | ||
|
|
f39eac9b87 | ||
|
|
f370521a55 | ||
|
|
c763218430 | ||
|
|
2df5b97e5e | ||
|
|
0a7e1c5e4c | ||
|
|
2d80fca221 | ||
|
|
3b8baddfba | ||
|
|
5319fe68f0 | ||
|
|
6b11b281c4 | ||
|
|
c79a73e88c | ||
|
|
53a63d6ae2 | ||
|
|
c95ddfe754 | ||
|
|
bfed5a56f0 | ||
|
|
41275f4a8a | ||
|
|
9fcb4f93e4 | ||
|
|
11a7827eef | ||
|
|
b7de9976a6 | ||
|
|
9671ec7c3d | ||
|
|
cb4aec479f | ||
|
|
44f34f9bb2 | ||
|
|
90b6c0902d | ||
|
|
445cfacb10 | ||
|
|
7989498177 | ||
|
|
b38cacbab8 | ||
|
|
4b121c28d0 | ||
|
|
4e1b4b79ef | ||
|
|
18500e679b | ||
|
|
174eb5bcf2 | ||
|
|
8d32ab3f4f | ||
|
|
5cc3a8118f | ||
|
|
753ba2af6a | ||
|
|
757f326c33 | ||
|
|
fc36600a6a | ||
|
|
038bcb91c2 | ||
|
|
0b1714c8f6 | ||
|
|
76141ba703 | ||
|
|
064b2120e4 | ||
|
|
732d03f3af | ||
|
|
81d0f131c4 | ||
|
|
5d0ff02cb3 | ||
|
|
ba41375179 | ||
|
|
fe7f05fc1e | ||
|
|
cbe2b7be32 | ||
|
|
0d1152de1c | ||
|
|
eaf5e06683 | ||
|
|
0921eb8038 | ||
|
|
64c8354511 | ||
|
|
cd21ca7bf4 | ||
|
|
ded925451b | ||
|
|
b0d5be69d0 | ||
|
|
2f7fa79b07 | ||
|
|
4fd5318e52 | ||
|
|
810c508489 | ||
|
|
383a0870f1 | ||
|
|
9e4a00b968 | ||
|
|
a57cce6b94 | ||
|
|
74a561f62e | ||
|
|
52acac2933 | ||
|
|
9830daef91 | ||
|
|
2f9f7670da | ||
|
|
808aaaf053 | ||
|
|
1044d0ad37 | ||
|
|
0ebd9e3bbe | ||
|
|
57d1a2ef9a | ||
|
|
eeacac8749 | ||
|
|
9e1ff7b479 | ||
|
|
32d2f3d2b2 | ||
|
|
c64aff5992 | ||
|
|
3390d66a7e | ||
|
|
e388299f05 | ||
|
|
f31fa5c99f | ||
|
|
fec8d9029c | ||
|
|
c4bc76b219 | ||
|
|
7d91e5f38a | ||
|
|
907ccf6494 | ||
|
|
c7fabe82d6 | ||
|
|
9f9ff6bf09 | ||
|
|
f60c003826 | ||
|
|
6a30f98145 | ||
|
|
7855c8b469 | ||
|
|
ee85afd30c | ||
|
|
09932f11d5 | ||
|
|
85afab5b36 | ||
|
|
75ef6810e2 | ||
|
|
66db5eb88c | ||
|
|
d5c3a4805b | ||
|
|
82c777e7c2 | ||
|
|
cdbc88f92e | ||
|
|
970a019476 | ||
|
|
9c9ba5d6f4 | ||
|
|
86790da2ec | ||
|
|
7fff423649 | ||
|
|
d258228cc0 | ||
|
|
9bf3ffc3ae | ||
|
|
7168f2e411 | ||
|
|
c75ad74ce0 | ||
|
|
7ed8d6feac | ||
|
|
e2bf15a6ce | ||
|
|
29139b104c | ||
|
|
0b2a85f803 | ||
|
|
a55688a95d | ||
|
|
f39ca5e3a7 | ||
|
|
1a2aedcf00 | ||
|
|
05e9c3a6c9 | ||
|
|
0d9ce81d20 | ||
|
|
eed44e0012 | ||
|
|
93073f2700 | ||
|
|
53a08c9101 | ||
|
|
6540059a28 | ||
|
|
48c816f2f9 | ||
|
|
1edb30d1ea | ||
|
|
797c798787 | ||
|
|
2c3341dfdf | ||
|
|
31357eb4e5 | ||
|
|
3401322e6e | ||
|
|
50ed2ba9bc | ||
|
|
ff8bdbcdc6 | ||
|
|
935802da1a | ||
|
|
1dffa3d974 | ||
|
|
78144f5fab | ||
|
|
47aa5dc1df | ||
|
|
bf7a1a205c | ||
|
|
96bd51471d | ||
|
|
bbd9fcca0c | ||
|
|
f263e89f06 | ||
|
|
698ea74132 | ||
|
|
766fc1ece2 | ||
|
|
247dd180ce | ||
|
|
23ed3de93c | ||
|
|
c0791baa3d | ||
|
|
9ad89d134e | ||
|
|
84ce0e3d9f | ||
|
|
92fe0d2e44 | ||
|
|
864ca3d91e | ||
|
|
8729c5f591 | ||
|
|
89be74aab5 | ||
|
|
24c5e367cc | ||
|
|
5004ca4a33 | ||
|
|
799d0ce726 | ||
|
|
47348d9002 | ||
|
|
3eeecf1cc2 | ||
|
|
31380a1976 | ||
|
|
6974764393 | ||
|
|
0e73ba0cc1 | ||
|
|
5bb5a70b0c | ||
|
|
2830ab92f7 | ||
|
|
2eb0e677a8 | ||
|
|
a5f5eccdbe | ||
|
|
82ff8dbf6b | ||
|
|
c9d8fc525c | ||
|
|
3854a4561d | ||
|
|
cf4afeb7f0 | ||
|
|
755e15c3e1 | ||
|
|
7f0d020466 | ||
|
|
5a2be88f41 | ||
|
|
be570117bb | ||
|
|
640fe5722c | ||
|
|
dff1ad01a6 | ||
|
|
e7a00354dc | ||
|
|
f042f7a51a | ||
|
|
4d92a5b433 | ||
|
|
4aed87bf45 | ||
|
|
a5e76e2e4e | ||
|
|
c7277c964e | ||
|
|
846b622c80 | ||
|
|
abcdff3e60 | ||
|
|
4fcfe3a485 | ||
|
|
76b0204d91 | ||
|
|
cac6f0534a | ||
|
|
f66bb568df | ||
|
|
cc4556824e | ||
|
|
c6f7efb797 | ||
|
|
6a2fcb21dc | ||
|
|
2b347c65de | ||
|
|
f1823630be | ||
|
|
41d1b7e57d | ||
|
|
c28ba81684 | ||
|
|
1561a1d0b4 | ||
|
|
0a302dcf0e | ||
|
|
07051ab738 | ||
|
|
973030ab67 | ||
|
|
67716bcedf | ||
|
|
e06b748516 | ||
|
|
02dac5b4b7 | ||
|
|
a4b8571b61 | ||
|
|
a3fa22b5fc | ||
|
|
9e9b6f8642 | ||
|
|
5f6a0983bd | ||
|
|
2fcab5ca5f | ||
|
|
778a32700d | ||
|
|
a6577318b6 | ||
|
|
badd476d3b | ||
|
|
5a3548402b | ||
|
|
c1f0307a8d | ||
|
|
77c0718df4 | ||
|
|
30bff8dd06 | ||
|
|
b1cf9bf4e5 | ||
|
|
bafc2b6ef4 | ||
|
|
565591568f | ||
|
|
9df891606f | ||
|
|
eea666317b | ||
|
|
ceff1d47a6 | ||
|
|
81dea4cf7e | ||
|
|
17fa3b58a6 | ||
|
|
70fa70fff4 | ||
|
|
137afe5b5b | ||
|
|
545790f048 | ||
|
|
807ef03005 | ||
|
|
ce89a31749 | ||
|
|
3e7675cafb | ||
|
|
4132375f26 | ||
|
|
5e0bd5b3b8 | ||
|
|
d00c84ff1b | ||
|
|
97f3a7a6fb | ||
|
|
8c656cdfd3 | ||
|
|
bea395b24b | ||
|
|
6992197fb8 | ||
|
|
097698ab63 | ||
|
|
46abceebf5 | ||
|
|
06130778b7 | ||
|
|
85b8d6c5a5 | ||
|
|
8436634bc1 | ||
|
|
5972b4e1aa | ||
|
|
426606bd02 | ||
|
|
f9604e29e6 | ||
|
|
7d7b8ea4b2 | ||
|
|
2ed529d564 | ||
|
|
73148db456 | ||
|
|
2fbc9c391c | ||
|
|
12f3d6d89d | ||
|
|
78c13dddef | ||
|
|
be19b58307 | ||
|
|
bca80dc784 | ||
|
|
e6fe07b084 | ||
|
|
c28e47cb93 | ||
|
|
c217662211 | ||
|
|
975a35e7a7 | ||
|
|
2e9233e534 | ||
|
|
4c6d151f7f | ||
|
|
383931bde9 | ||
|
|
1ac8c602c9 | ||
|
|
d5135ca35f | ||
|
|
8265726879 | ||
|
|
5261757f3c | ||
|
|
c099be2b85 | ||
|
|
de8143ef47 | ||
|
|
b80f08956b | ||
|
|
a3088f6d4c | ||
|
|
fdaf0b65a1 | ||
|
|
71e0ad1f5b | ||
|
|
c87be1b4f0 |
No files matched your search
@@ -1,11 +1,8 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/BlankSpruce/gersemi/master/gersemi/configuration.schema.json
|
||||
|
||||
color: false
|
||||
definitions: [ares/CMakeLists.txt]
|
||||
line_length: 120
|
||||
indent: 2
|
||||
list_expansion: favour-inlining
|
||||
quiet: false
|
||||
unsafe: false
|
||||
warn_about_unknown_commands: false
|
||||
workers: 10
|
||||
@@ -0,0 +1,31 @@
|
||||
# dummy GitHub target used to enable editing of GitHub files within generated IDE projects
|
||||
|
||||
add_library(.github INTERFACE)
|
||||
|
||||
set(.github_sources
|
||||
ISSUE_TEMPLATE/bug_report.md
|
||||
ISSUE_TEMPLATE/feature_request.md
|
||||
ISSUE_TEMPLATE/game-issue-report.md
|
||||
scripts/build_macos.sh
|
||||
scripts/build_ubuntu.sh
|
||||
scripts/build_windows.sh
|
||||
scripts/package_artifacts.sh
|
||||
workflows/build-aux.yml
|
||||
workflows/build.yml
|
||||
workflows/pr.yml
|
||||
workflows/push.yml
|
||||
workflows/release.yml
|
||||
)
|
||||
|
||||
target_sources(
|
||||
.github
|
||||
PRIVATE
|
||||
${.github_sources}
|
||||
../.gitignore
|
||||
../.gitattributes
|
||||
../README.md
|
||||
../LICENSE
|
||||
)
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${.github_sources})
|
||||
|
||||
@@ -42,3 +42,8 @@ do
|
||||
zip -r ../ares-${package}.zip ${outdir}
|
||||
cd -
|
||||
done
|
||||
|
||||
# Package the source archive
|
||||
pushd src
|
||||
git archive --format=tar.gz -o ../ares-source.tar.gz HEAD
|
||||
popd
|
||||
@@ -56,6 +56,14 @@ jobs:
|
||||
os: ubuntu-24.04-arm
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-clang
|
||||
- name: ubuntu-gcc-arm64-qt
|
||||
os: ubuntu-24.04-arm
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-qt
|
||||
- name: freebsd
|
||||
os: ubuntu-24.04
|
||||
shell: bash
|
||||
target-cmake-preset: ubuntu-ci-clang
|
||||
name: ${{ matrix.program }}-${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
defaults:
|
||||
@@ -78,12 +86,12 @@ jobs:
|
||||
run: |
|
||||
git config core.autocrlf true
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
if: runner.os == 'Linux' && matrix.platform.name != 'freebsd'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
|
||||
sudo apt-get install cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev qt6-base-dev
|
||||
- name: "Build: Linux"
|
||||
if: runner.os == 'Linux'
|
||||
if: runner.os == 'Linux' && matrix.platform.name != 'freebsd'
|
||||
run: .github/scripts/build_ubuntu.sh
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
@@ -95,6 +103,18 @@ jobs:
|
||||
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
|
||||
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Build: FreeBSD"
|
||||
if: matrix.platform.name == 'freebsd'
|
||||
uses: cross-platform-actions/action@e8a7b572196ff79ded1979dc2bb9ee67d1ddb252
|
||||
env:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: 14.3
|
||||
environment_variables: TARGET_PRESET
|
||||
run: |
|
||||
sudo pkg install -y cmake pkgconf ccache ninja gtk3 libX11 libXext libXrandr libXrender libglvnd alsa-lib libao libudev-devd librashader openal-soft pulseaudio sdl3 vulkan-loader
|
||||
.github/scripts/build_ubuntu.sh
|
||||
- name: "Compress Build Artifacts (Windows)"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
run: |
|
||||
|
||||
@@ -77,6 +77,7 @@ jobs:
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew uninstall --ignore-dependencies cmake
|
||||
brew install ${{ matrix.platform.install }}
|
||||
- name: "Build: Windows"
|
||||
if: runner.os != 'macOS' && runner.os != 'Linux'
|
||||
@@ -89,6 +90,7 @@ jobs:
|
||||
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
|
||||
- name: "Windows: sign"
|
||||
if: runner.os == 'Windows' && inputs.codesign
|
||||
continue-on-error: true
|
||||
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
|
||||
with:
|
||||
certificate: '${{ secrets.WIN_CERTIFICATE }}'
|
||||
|
||||
@@ -73,6 +73,7 @@ jobs:
|
||||
name: ares ${{ steps.check.outputs.versionName }}
|
||||
body: ${{ steps.check.outputs.description }}
|
||||
files: |
|
||||
${{ github.workspace }}/ares-source.tar.gz
|
||||
${{ github.workspace }}/ares-macos-universal.zip
|
||||
${{ github.workspace }}/ares-macos-universal-dSYMs.zip
|
||||
${{ github.workspace }}/ares-windows-x64.zip
|
||||
|
||||
+6
-5
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.28...4.0)
|
||||
cmake_minimum_required(VERSION 3.28...4.1)
|
||||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE)
|
||||
|
||||
@@ -8,8 +8,6 @@ include(compilerconfig)
|
||||
include(defaults)
|
||||
include(helpers)
|
||||
|
||||
add_subdirectory(cmake)
|
||||
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
add_subdirectory(nall/nall)
|
||||
@@ -21,7 +19,7 @@ add_subdirectory(hiro)
|
||||
set(
|
||||
ARES_CORES
|
||||
a26 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
|
||||
CACHE STRING LIST
|
||||
CACHE STRING "List of systems to be built by the project"
|
||||
)
|
||||
# gersemi: on
|
||||
|
||||
@@ -35,7 +33,7 @@ if(ARES_BUILD_OPTIONAL_TARGETS)
|
||||
add_subdirectory(tests/arm7tdmi)
|
||||
add_subdirectory(tests/i8080)
|
||||
add_subdirectory(tests/m68000)
|
||||
if(NOT OS_WINDOWS AND NOT OS_MACOS)
|
||||
if(HIRO_BACKEND STREQUAL "GTK3")
|
||||
add_subdirectory(tools/genius)
|
||||
else()
|
||||
target_disable_subproject(genius "genius (database editor)")
|
||||
@@ -52,4 +50,7 @@ endif()
|
||||
add_subdirectory(tools/sourcery)
|
||||
|
||||
message_configuration()
|
||||
|
||||
add_subdirectory(.github)
|
||||
add_subdirectory(cmake)
|
||||
return()
|
||||
+15
-2
@@ -82,7 +82,7 @@
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_OSX_ARCHITECTURES": {"type": "STRING", "value": "x86_64;arm64"},
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "10.15"},
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "11.0"},
|
||||
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{MACOS_CERTIFICATE_NAME}"},
|
||||
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{MACOS_NOTARIZATION_TEAMID}"},
|
||||
"ENABLE_CCACHE": true,
|
||||
@@ -102,7 +102,9 @@
|
||||
"ARES_BUILD_LOCAL": false,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true,
|
||||
"ARES_UNITY_CORES": true,
|
||||
"ARES_PRECOMPILE_HEADERS": true
|
||||
"ARES_PRECOMPILE_HEADERS": true,
|
||||
"CMAKE_MSVC_RUNTIME_LIBRARY": {"type": "STRING", "value": "MultiThreaded"},
|
||||
"CMAKE_IGNORE_PATH": {"type": "STRING", "value": "C:/Strawberry/c/bin/"}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -159,6 +161,7 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": {"type": "STRING", "value": "RelWithDebInfo"},
|
||||
"ENABLE_CCACHE": true,
|
||||
"ENABLE_IPO": false,
|
||||
"ARES_BUILD_LOCAL": false,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": true,
|
||||
"ARES_PRECOMPILE_HEADERS": false
|
||||
@@ -173,6 +176,16 @@
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ubuntu-ci-qt",
|
||||
"displayName": "Ubuntu CI (arm64, gcc, Qt)",
|
||||
"description": "Single-arch binary for building on Github Actions",
|
||||
"inherits": ["ubuntu-ci"],
|
||||
"cacheVariables": {
|
||||
"USE_QT6": true,
|
||||
"ARES_BUILD_OPTIONAL_TARGETS": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
|
||||
@@ -828,4 +828,32 @@ You may add additional accurate notices of copyright ownership.
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
qoi/qon
|
||||
|
||||
Copyright (c) 2025, Roger Sanders
|
||||
Revised QOI format, achieving higher compression with equivalent performance.
|
||||
|
||||
Based on the "Quite OK Image" format for fast, lossless image compression
|
||||
Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
----------------------------------------------------------------------
|
||||
+1
-1
@@ -21,7 +21,7 @@ if(ARES_PRECOMPILE_HEADERS)
|
||||
target_precompile_headers(ares PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:ares/ares.hpp>")
|
||||
endif()
|
||||
|
||||
target_link_libraries(ares PUBLIC libco sljit nall)
|
||||
target_link_libraries(ares PRIVATE libco ares::nall::headers $<$<BOOL:${ARES_ENABLE_CHD}>:chdr-static> PUBLIC sljit)
|
||||
|
||||
if(ARES_PROFILE_ACCURACY)
|
||||
target_compile_definitions(ares PUBLIC PROFILE_ACCURACY)
|
||||
|
||||
+2
-1
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ares/ares.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include <component/processor/mos6502/mos6502.hpp>
|
||||
|
||||
namespace ares::Atari2600 {
|
||||
#include <ares/inline.hpp>
|
||||
auto enumerate() -> vector<string>;
|
||||
auto enumerate() -> std::vector<string>;
|
||||
auto load(Node::System& node, string name) -> bool;
|
||||
|
||||
struct Region {
|
||||
|
||||
@@ -19,15 +19,15 @@ auto Cartridge::connect() -> void {
|
||||
information.region = pak->attribute("region");
|
||||
information.board = pak->attribute("board");
|
||||
|
||||
if(information.board == "Linear") board = new Board::Linear{*this};
|
||||
if(information.board == "Atari8k") board = new Board::Atari8k{*this};
|
||||
if(information.board == "Atari16k") board = new Board::Atari16k{*this};
|
||||
if(information.board == "Atari32k") board = new Board::Atari32k{*this};
|
||||
if(information.board == "Commavid") board = new Board::Commavid{*this};
|
||||
if(information.board == "ParkerBros8k") board = new Board::ParkerBros{*this};
|
||||
if(information.board == "Tigervision") board = new Board::Tigervision{*this};
|
||||
if(information.board == "Linear") board = std::make_unique<Board::Linear>(*this);
|
||||
if(information.board == "Atari8k") board = std::make_unique<Board::Atari8k>(*this);
|
||||
if(information.board == "Atari16k") board = std::make_unique<Board::Atari16k>(*this);
|
||||
if(information.board == "Atari32k") board = std::make_unique<Board::Atari32k>(*this);
|
||||
if(information.board == "Commavid") board = std::make_unique<Board::Commavid>(*this);
|
||||
if(information.board == "ParkerBros8k") board = std::make_unique<Board::ParkerBros>(*this);
|
||||
if(information.board == "Tigervision") board = std::make_unique<Board::Tigervision>(*this);
|
||||
|
||||
if(!board) board = new Board::Interface{*this};
|
||||
if(!board) board = std::make_unique<Board::Interface>(*this);
|
||||
board->pak = pak;
|
||||
board->load();
|
||||
power();
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Cartridge {
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
unique_pointer<Board::Interface> board;
|
||||
std::unique_ptr<Board::Interface> board;
|
||||
|
||||
//private:
|
||||
struct Information {
|
||||
|
||||
@@ -20,7 +20,7 @@ auto ControllerPort::unload() -> void {
|
||||
}
|
||||
|
||||
auto ControllerPort::allocate(string name) -> Node::Peripheral {
|
||||
if(name == "Gamepad") device = new Gamepad(port);
|
||||
if(name == "Gamepad") device = std::make_unique<Gamepad>(port);
|
||||
if(device) return device->node;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
struct ControllerPort {
|
||||
Node::Port port;
|
||||
unique_pointer<Controller> device;
|
||||
std::unique_ptr<Controller> device;
|
||||
|
||||
//port.cpp
|
||||
ControllerPort(string name);
|
||||
|
||||
@@ -32,7 +32,7 @@ auto CPU::step(u32 clocks) -> void {
|
||||
auto CPU::power(bool reset) -> void {
|
||||
MOS6502::BCD = 1;
|
||||
MOS6502::power();
|
||||
Thread::create(system.frequency() / 3, {&CPU::main, this});
|
||||
Thread::create(system.frequency() / 3, std::bind_front(&CPU::main, this));
|
||||
|
||||
io = {};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ auto RIOT::step(u32 clocks) -> void {
|
||||
}
|
||||
|
||||
auto RIOT::power(bool reset) -> void {
|
||||
Thread::create(system.frequency() / 3, {&RIOT::main, this});
|
||||
Thread::create(system.frequency() / 3, std::bind_front(&RIOT::main, this));
|
||||
timer = {};
|
||||
port[0] = {};
|
||||
port[0].data = 0xff;
|
||||
|
||||
+12
-10
@@ -1,8 +1,9 @@
|
||||
#include <a26/a26.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ares::Atari2600 {
|
||||
|
||||
auto enumerate() -> vector<string> {
|
||||
auto enumerate() -> std::vector<string> {
|
||||
return {
|
||||
"[Atari] Atari 2600 (NTSC)",
|
||||
"[Atari] Atari 2600 (PAL)",
|
||||
@@ -11,7 +12,8 @@ auto enumerate() -> vector<string> {
|
||||
}
|
||||
|
||||
auto load(Node::System& node, string name) -> bool {
|
||||
if(!enumerate().find(name)) return false;
|
||||
auto list = enumerate();
|
||||
if(std::find(list.begin(), list.end(), name) == list.end()) return false;
|
||||
return system.load(node, name);
|
||||
}
|
||||
|
||||
@@ -53,15 +55,15 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
information.frequency = 3546894;
|
||||
}
|
||||
|
||||
node = Node::System::create(information.name);
|
||||
node = std::make_shared<Core::System>(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
node->setSave({&System::save, this});
|
||||
node->setUnload({&System::unload, this});
|
||||
node->setSerialize({&System::serialize, this});
|
||||
node->setUnserialize({&System::unserialize, this});
|
||||
node->setGame(std::bind_front(&System::game, this));
|
||||
node->setRun(std::bind_front(&System::run, this));
|
||||
node->setPower(std::bind_front(&System::power, this));
|
||||
node->setSave(std::bind_front(&System::save, this));
|
||||
node->setUnload(std::bind_front(&System::unload, this));
|
||||
node->setSerialize([this](bool s){ return this->serialize(s); });
|
||||
node->setUnserialize([this](serializer& s){ return this->unserialize(s); });
|
||||
root = node;
|
||||
|
||||
scheduler.reset();
|
||||
|
||||
@@ -18,7 +18,7 @@ auto TIA::load(Node::Object parent) -> void {
|
||||
node = parent->append<Node::Object>("TIA");
|
||||
|
||||
screen = node->append<Node::Video::Screen>("Screen", 180, displayHeight());
|
||||
screen->colors(1 << 7, {&TIA::color, this});
|
||||
screen->colors(1 << 7, std::bind_front(&TIA::color, this));
|
||||
screen->setSize(180, displayHeight());
|
||||
screen->setScale(2.0, 1.0);
|
||||
Region::PAL() ? screen->setAspect(38.0, 45.0) : screen->setAspect(4.0, 5.0);
|
||||
@@ -123,7 +123,7 @@ auto TIA::step(u32 clocks) -> void {
|
||||
}
|
||||
|
||||
auto TIA::power(bool reset) -> void {
|
||||
Thread::create(system.frequency(), {&TIA::main, this});
|
||||
Thread::create(system.frequency(), std::bind_front(&TIA::main, this));
|
||||
screen->power();
|
||||
io = {};
|
||||
playfield = {};
|
||||
|
||||
+8
-5
@@ -3,6 +3,10 @@
|
||||
#include <libco/libco.h>
|
||||
#include <sljit.h>
|
||||
|
||||
#include <vector>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/adaptive-array.hpp>
|
||||
#include <nall/any.hpp>
|
||||
@@ -22,14 +26,13 @@
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/set.hpp>
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/span-helpers.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/terminal.hpp>
|
||||
#include <nall/thread.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
#include <nall/unique-pointer.hpp>
|
||||
#include <memory>
|
||||
#include <nall/variant.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/vfs.hpp>
|
||||
#include <nall/cd.hpp>
|
||||
#include <nall/dsp/iir/one-pole.hpp>
|
||||
@@ -51,8 +54,8 @@ namespace ares {
|
||||
extern const u32 SerializerSignature;
|
||||
|
||||
namespace VFS {
|
||||
using Pak = shared_pointer<vfs::directory>;
|
||||
using File = shared_pointer<vfs::file>;
|
||||
using Pak = std::shared_ptr<vfs::directory>;
|
||||
using File = std::shared_ptr<vfs::file>;
|
||||
}
|
||||
|
||||
namespace Video {
|
||||
|
||||
+12
-12
@@ -4,40 +4,40 @@ Debug _debug;
|
||||
|
||||
auto Debug::reset() -> void {
|
||||
_totalNotices = 0;
|
||||
_unhandledNotices.reset();
|
||||
_unimplementedNotices.reset();
|
||||
_unusualNotices.reset();
|
||||
_unverifiedNotices.reset();
|
||||
_unhandledNotices.clear();
|
||||
_unimplementedNotices.clear();
|
||||
_unusualNotices.clear();
|
||||
_unverifiedNotices.clear();
|
||||
}
|
||||
|
||||
auto Debug::_unhandled(const string& text) -> void {
|
||||
if(_unhandledNotices.find(text)) return;
|
||||
if(std::ranges::find(_unhandledNotices, text) != _unhandledNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unhandledNotices.append(text);
|
||||
_unhandledNotices.push_back(text);
|
||||
|
||||
print(terminal::color::yellow("[unhandled] "), text, "\n");
|
||||
}
|
||||
|
||||
auto Debug::_unimplemented(const string& text) -> void {
|
||||
if(_unimplementedNotices.find(text)) return;
|
||||
if(std::ranges::find(_unimplementedNotices, text) != _unimplementedNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unimplementedNotices.append(text);
|
||||
_unimplementedNotices.push_back(text);
|
||||
|
||||
print(terminal::color::magenta("[unimplemented] "), text, "\n");
|
||||
}
|
||||
|
||||
auto Debug::_unusual(const string& text) -> void {
|
||||
if(_unusualNotices.find(text)) return;
|
||||
if(std::ranges::find(_unusualNotices, text) != _unusualNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unusualNotices.append(text);
|
||||
_unusualNotices.push_back(text);
|
||||
|
||||
print(terminal::color::cyan("[unusual] "), text, "\n");
|
||||
}
|
||||
|
||||
auto Debug::_unverified(const string& text) -> void {
|
||||
if(_unverifiedNotices.find(text)) return;
|
||||
if(std::ranges::find(_unverifiedNotices, text) != _unverifiedNotices.end()) return;
|
||||
if(_totalNotices++ > 256) return;
|
||||
_unverifiedNotices.append(text);
|
||||
_unverifiedNotices.push_back(text);
|
||||
|
||||
print(terminal::color::gray("[unverified] "), text, "\n");
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ private:
|
||||
auto _unverified(const string&) -> void;
|
||||
|
||||
u64 _totalNotices = 0;
|
||||
vector<string> _unhandledNotices;
|
||||
vector<string> _unimplementedNotices;
|
||||
vector<string> _unusualNotices;
|
||||
vector<string> _unverifiedNotices;
|
||||
std::vector<string> _unhandledNotices;
|
||||
std::vector<string> _unimplementedNotices;
|
||||
std::vector<string> _unusualNotices;
|
||||
std::vector<string> _unverifiedNotices;
|
||||
};
|
||||
|
||||
extern Debug _debug;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ares/memory/memory.hpp>
|
||||
#include <span>
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
@@ -32,7 +33,7 @@ struct Readable {
|
||||
|
||||
auto load(VFS::File fp) -> void {
|
||||
if(!self.size) allocate(fp->size());
|
||||
fp->read({self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
fp->read({(u8*)self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
for(u32 address = self.size; address <= self.mask; address++) {
|
||||
self.data[address] = self.data[mirror(address, self.size)];
|
||||
}
|
||||
@@ -59,7 +60,7 @@ struct Readable {
|
||||
auto end() const -> const T* { return &self.data[self.size]; }
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s(array_span<T>{self.data, self.size});
|
||||
s(std::span<T>{self.data, self.size});
|
||||
}
|
||||
|
||||
//private:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ares/memory/memory.hpp>
|
||||
#include <span>
|
||||
|
||||
namespace ares::Memory {
|
||||
|
||||
@@ -32,14 +33,14 @@ struct Writable {
|
||||
|
||||
auto load(VFS::File fp) -> void {
|
||||
if(!self.size) allocate(fp->size());
|
||||
fp->read({self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
fp->read({(u8*)self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
for(u32 address = self.size; address <= self.mask; address++) {
|
||||
self.data[address] = self.data[mirror(address, self.size)];
|
||||
}
|
||||
}
|
||||
|
||||
auto save(VFS::File fp) -> void {
|
||||
fp->write({self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
fp->write({(const u8*)self.data, min(fp->size(), self.size * sizeof(T))});
|
||||
}
|
||||
|
||||
explicit operator bool() const { return (bool)self.data; }
|
||||
@@ -61,7 +62,7 @@ struct Writable {
|
||||
auto end() const -> const T* { return &self.data[self.size]; }
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s(array_span<T>{self.data, self.size});
|
||||
s(std::span<T>{self.data, self.size});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
auto Stream::setChannels(u32 channels) -> void {
|
||||
_channels.reset();
|
||||
_channels.clear();
|
||||
_channels.resize(channels);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ auto Stream::setResamplerFrequency(f64 resamplerFrequency) -> void {
|
||||
_resamplerFrequency = resamplerFrequency;
|
||||
|
||||
for(auto& channel : _channels) {
|
||||
channel.nyquist.reset();
|
||||
channel.nyquist.clear();
|
||||
channel.resampler.reset(_frequency, _resamplerFrequency);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ auto Stream::setResamplerFrequency(f64 resamplerFrequency) -> void {
|
||||
DSP::IIR::Biquad filter;
|
||||
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, _frequency, q);
|
||||
channel.nyquist.append(filter);
|
||||
channel.nyquist.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ auto Stream::setMuted(bool muted) -> void {
|
||||
|
||||
auto Stream::resetFilters() -> void {
|
||||
for(auto& channel : _channels) {
|
||||
channel.filters.reset();
|
||||
channel.filters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,13 +47,13 @@ auto Stream::addLowPassFilter(f64 cutoffFrequency, u32 order, u32 passes) -> voi
|
||||
if(order == 1) {
|
||||
Filter filter{Filter::Mode::OnePole, Filter::Type::LowPass, Filter::Order::First};
|
||||
filter.onePole.reset(DSP::IIR::OnePole::Type::LowPass, cutoffFrequency, _frequency);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
if(order == 2) {
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::LowPass, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,13 +65,13 @@ auto Stream::addHighPassFilter(f64 cutoffFrequency, u32 order, u32 passes) -> vo
|
||||
if(order == 1) {
|
||||
Filter filter{Filter::Mode::OnePole, Filter::Type::HighPass, Filter::Order::First};
|
||||
filter.onePole.reset(DSP::IIR::OnePole::Type::HighPass, cutoffFrequency, _frequency);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
if(order == 2) {
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::HighPass, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::HighPass, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ auto Stream::addLowShelfFilter(f64 cutoffFrequency, u32 order, f64 gain, f64 slo
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::LowShelf, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::shelf(gain, slope);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::LowShelf, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,13 +94,13 @@ auto Stream::addHighShelfFilter(f64 cutoffFrequency, u32 order, f64 gain, f64 sl
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::HighShelf, Filter::Order::Second};
|
||||
f64 q = DSP::IIR::Biquad::shelf(gain, slope);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::HighShelf, cutoffFrequency, _frequency, q);
|
||||
channel.filters.append(filter);
|
||||
channel.filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::pending() const -> bool {
|
||||
return _channels && _channels[0].resampler.pending();
|
||||
return !_channels.empty() && _channels[0].resampler.pending();
|
||||
}
|
||||
|
||||
auto Stream::read(f64 samples[]) -> u32 {
|
||||
@@ -127,5 +127,5 @@ auto Stream::write(const f64 samples[]) -> void {
|
||||
|
||||
//if there are samples pending, then alert the frontend to possibly process them.
|
||||
//this will generally happen when every audio stream has pending samples to be mixed.
|
||||
if(pending()) platform->audio(shared());
|
||||
if(pending()) platform->audio(std::static_pointer_cast<Core::Audio::Stream>(shared_from_this()));
|
||||
}
|
||||
@@ -38,11 +38,11 @@ protected:
|
||||
DSP::IIR::Biquad biquad;
|
||||
};
|
||||
struct Channel {
|
||||
vector<Filter> filters;
|
||||
vector<DSP::IIR::Biquad> nyquist;
|
||||
std::vector<Filter> filters;
|
||||
std::vector<DSP::IIR::Biquad> nyquist;
|
||||
DSP::Resampler::Cubic resampler;
|
||||
};
|
||||
vector<Channel> _channels;
|
||||
std::vector<Channel> _channels;
|
||||
f64 _frequency = 48000.0;
|
||||
f64 _resamplerFrequency = 48000.0;
|
||||
bool _muted = false;
|
||||
|
||||
@@ -4,26 +4,28 @@
|
||||
struct Class {
|
||||
struct Instance {
|
||||
const string identifier;
|
||||
const function<Node::Object ()> create;
|
||||
const std::function<Node::Object ()> create;
|
||||
};
|
||||
|
||||
static auto classes() -> vector<Instance>& {
|
||||
static vector<Instance> classes;
|
||||
static auto classes() -> std::vector<Instance>& {
|
||||
static std::vector<Instance> classes;
|
||||
return classes;
|
||||
}
|
||||
|
||||
template<typename T> static auto register() -> void {
|
||||
if(!classes().find([&](auto instance) { return instance.identifier == T::identifier(); })) {
|
||||
classes().append({T::identifier(), &T::create});
|
||||
auto& cls = classes();
|
||||
auto it = std::ranges::find_if(cls, [&](const Instance& instance) { return instance.identifier == T::identifier(); });
|
||||
if(it == cls.end()) {
|
||||
cls.push_back({T::identifier(), &T::create});
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
static auto create(string identifier) -> Node::Object {
|
||||
if(auto index = classes().find([&](auto instance) { return instance.identifier == identifier; })) {
|
||||
return classes()[*index].create();
|
||||
}
|
||||
auto& cls = classes();
|
||||
auto it = std::ranges::find_if(cls, [&](const Instance& instance) { return instance.identifier == identifier; });
|
||||
if(it != cls.end()) return it->create();
|
||||
if(identifier == "Object") throw; //should never occur: detects unregistered classes
|
||||
return create("Object");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ struct RealTimeClock : Component {
|
||||
auto update() -> void { if(_update) return _update(); }
|
||||
auto timestamp() const -> u64 { return _timestamp; }
|
||||
|
||||
auto setUpdate(function<void ()> update) -> void { _update = update; }
|
||||
auto setUpdate(std::function<void ()> update) -> void { _update = update; }
|
||||
auto setTimestamp(u64 timestamp) -> void { _timestamp = timestamp; }
|
||||
|
||||
auto synchronize(u64 timestamp = 0) -> void {
|
||||
@@ -25,6 +25,6 @@ struct RealTimeClock : Component {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<void ()> _update;
|
||||
std::function<void ()> _update;
|
||||
u64 _timestamp;
|
||||
};
|
||||
@@ -6,10 +6,10 @@ struct Graphics : Debugger {
|
||||
|
||||
auto width() const -> u32 { return _width; }
|
||||
auto height() const -> u32 { return _height; }
|
||||
auto capture() const -> vector<u32> { if(_capture) return _capture(); return {}; }
|
||||
auto capture() const -> std::vector<u32> { if(_capture) return _capture(); return {}; }
|
||||
|
||||
auto setSize(u32 width, u32 height) -> void { _width = width, _height = height; }
|
||||
auto setCapture(function<vector<u32> ()> capture) -> void { _capture = capture; }
|
||||
auto setCapture(std::function<std::vector<u32> ()> capture) -> void { _capture = capture; }
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
Debugger::serialize(output, depth);
|
||||
@@ -22,5 +22,5 @@ struct Graphics : Debugger {
|
||||
protected:
|
||||
u32 _width = 0;
|
||||
u32 _height = 0;
|
||||
function<vector<u32> ()> _capture;
|
||||
std::function<std::vector<u32> ()> _capture;
|
||||
};
|
||||
@@ -9,8 +9,8 @@ struct Memory : Debugger {
|
||||
auto write(u32 address, u8 data) const -> void { if(_write) return _write(address, data); }
|
||||
|
||||
auto setSize(u32 size) -> void { _size = size; }
|
||||
auto setRead(function<u8 (u32)> read) -> void { _read = read; }
|
||||
auto setWrite(function<void (u32, u8)> write) -> void { _write = write; }
|
||||
auto setRead(std::function<u8 (u32)> read) -> void { _read = read; }
|
||||
auto setWrite(std::function<void (u32, u8)> write) -> void { _write = write; }
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
Debugger::serialize(output, depth);
|
||||
@@ -22,6 +22,6 @@ struct Memory : Debugger {
|
||||
|
||||
protected:
|
||||
u32 _size = 0;
|
||||
function<u8 (u32)> _read;
|
||||
function<void (u32, u8)> _write;
|
||||
std::function<u8 (u32)> _read;
|
||||
std::function<void (u32, u8)> _write;
|
||||
};
|
||||
@@ -6,7 +6,7 @@ struct Properties : Debugger {
|
||||
|
||||
auto query() const -> string { if(_query) return _query(); return {}; }
|
||||
|
||||
auto setQuery(function<string ()> query) -> void { _query = query; }
|
||||
auto setQuery(std::function<string ()> query) -> void { _query = query; }
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
Debugger::serialize(output, depth);
|
||||
@@ -17,5 +17,5 @@ struct Properties : Debugger {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<string ()> _query;
|
||||
std::function<string ()> _query;
|
||||
};
|
||||
@@ -23,7 +23,7 @@ struct Instruction : Tracer {
|
||||
|
||||
auto setDepth(u32 depth) -> void {
|
||||
_depth = depth;
|
||||
_history.reset();
|
||||
_history.clear();
|
||||
_history.resize(depth);
|
||||
for(auto& history : _history) history = ~0ull;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ struct Instruction : Tracer {
|
||||
for(auto index : range(_depth - 1)) {
|
||||
_history[index] = _history[index + 1];
|
||||
}
|
||||
_history.last() = _address;
|
||||
_history.back() = _address;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -71,7 +71,8 @@ struct Instruction : Tracer {
|
||||
if(!enabled()) return;
|
||||
|
||||
if(_omitted) {
|
||||
PlatformLog(shared(), {"[Omitted: ", _omitted, "]"});
|
||||
auto message = string{ "[Omitted: ", _omitted, "]" };
|
||||
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), message);
|
||||
_omitted = 0;
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ struct Instruction : Tracer {
|
||||
context, " ",
|
||||
extra
|
||||
};
|
||||
PlatformLog(shared(), {output.strip()});
|
||||
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), {output.strip()});
|
||||
}
|
||||
|
||||
auto serialize(string& output, string depth) -> void override {
|
||||
@@ -135,6 +136,6 @@ protected:
|
||||
//unserialized:
|
||||
n64 _address = 0;
|
||||
n64 _omitted = 0;
|
||||
vector<u64> _history;
|
||||
std::vector<u64> _history;
|
||||
hashset<VisitMask> _masks;
|
||||
};
|
||||
@@ -6,7 +6,7 @@ struct Notification : Tracer {
|
||||
|
||||
auto notify(const string& message = {}) -> void {
|
||||
if(!enabled()) return;
|
||||
PlatformLog(shared(), message);
|
||||
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), message);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -12,7 +12,7 @@ struct Tracer : Debugger {
|
||||
auto file() const -> bool { return _file; }
|
||||
auto autoLineBreak() const -> bool { return _autoLineBreak; }
|
||||
|
||||
auto setToggle(function<void ()> toggle) -> void { _toggle = toggle; }
|
||||
auto setToggle(std::function<void ()> toggle) -> void { _toggle = toggle; }
|
||||
auto setComponent(string component) -> void { _component = component; }
|
||||
auto setPrefix(bool prefix) -> void { _prefix = prefix; }
|
||||
auto setTerminal(bool terminal) -> void { _terminal = terminal; if(_toggle) _toggle(); }
|
||||
@@ -36,7 +36,7 @@ struct Tracer : Debugger {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<void ()> _toggle;
|
||||
std::function<void ()> _toggle;
|
||||
string _component;
|
||||
bool _prefix = false;
|
||||
bool _terminal = false;
|
||||
|
||||
@@ -5,6 +5,57 @@ struct Axis : Input {
|
||||
auto value() const -> s64 { return _value; }
|
||||
auto setValue(s64 value) -> void { _value = value; }
|
||||
|
||||
auto setOperatingRange(s16 position, double saturationRadius, double offset) -> double {
|
||||
return position * saturationRadius / 32767.0 + offset;
|
||||
}
|
||||
|
||||
auto processDeadzoneAndResponseCurve(double position, double innerDeadzone, double cardinalMax, double offset) -> double {
|
||||
auto lengthAbsolute = abs(position - offset);
|
||||
if(lengthAbsolute <= innerDeadzone) {
|
||||
position = offset;
|
||||
} else {
|
||||
lengthAbsolute = (lengthAbsolute - innerDeadzone) * (cardinalMax) / (cardinalMax - innerDeadzone) / lengthAbsolute;
|
||||
position = (position - offset) * lengthAbsolute + offset;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
auto revisePosition(double position, double length, double saturationRadius, double offset) -> double {
|
||||
if(length > saturationRadius) {
|
||||
length = saturationRadius / length;
|
||||
position = (position - offset) * length + offset;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
auto applyGateBoundaries(double innerDeadzone, double cardinalMax, double diagonalMax, double positionX, double positionY, double offset, double& boundedPositionX, double& boundedPositionY) -> void {
|
||||
if(positionX != offset && positionY != offset) {
|
||||
auto slope = (positionY - offset) / (positionX - offset);
|
||||
auto edgex = copysign(cardinalMax / (abs(slope) + (cardinalMax - diagonalMax) / diagonalMax), positionX);
|
||||
auto edgey = copysign(min(abs(edgex * slope), cardinalMax / (1.0 / abs(slope) + (cardinalMax - diagonalMax) / diagonalMax)), positionY);
|
||||
edgex = edgey / slope;
|
||||
|
||||
auto distanceToEdge = hypot(edgex, edgey);
|
||||
|
||||
auto length = hypot(positionX - offset, positionY - offset);
|
||||
if(length > distanceToEdge) {
|
||||
positionX = edgex + offset;
|
||||
positionY = edgey + offset;
|
||||
}
|
||||
}
|
||||
boundedPositionX = positionX;
|
||||
boundedPositionY = positionY;
|
||||
}
|
||||
|
||||
auto clampAxisToNearestBoundary(double position, double offset, double cardinalMax) -> double {
|
||||
if(abs(position - offset) > cardinalMax) position = copysign(cardinalMax, position - offset) + offset;
|
||||
return position;
|
||||
}
|
||||
|
||||
auto counteractPrecisionError(double position) -> double {
|
||||
return copysign(abs(position) + 1e-09, position);
|
||||
}
|
||||
|
||||
protected:
|
||||
s64 _value = 0;
|
||||
s64 _minimum = -32768;
|
||||
|
||||
+35
-34
@@ -45,47 +45,47 @@ namespace ares::Core {
|
||||
}
|
||||
|
||||
namespace ares::Node {
|
||||
using Object = shared_pointer<Core::Object>;
|
||||
using System = shared_pointer<Core::System>;
|
||||
using Peripheral = shared_pointer<Core::Peripheral>;
|
||||
using Port = shared_pointer<Core::Port>;
|
||||
using Object = std::shared_ptr<Core::Object>;
|
||||
using System = std::shared_ptr<Core::System>;
|
||||
using Peripheral = std::shared_ptr<Core::Peripheral>;
|
||||
using Port = std::shared_ptr<Core::Port>;
|
||||
namespace Component {
|
||||
using Component = shared_pointer<Core::Component::Component>;
|
||||
using RealTimeClock = shared_pointer<Core::Component::RealTimeClock>;
|
||||
using Component = std::shared_ptr<Core::Component::Component>;
|
||||
using RealTimeClock = std::shared_ptr<Core::Component::RealTimeClock>;
|
||||
}
|
||||
namespace Video {
|
||||
using Video = shared_pointer<Core::Video::Video>;
|
||||
using Sprite = shared_pointer<Core::Video::Sprite>;
|
||||
using Screen = shared_pointer<Core::Video::Screen>;
|
||||
using Video = std::shared_ptr<Core::Video::Video>;
|
||||
using Sprite = std::shared_ptr<Core::Video::Sprite>;
|
||||
using Screen = std::shared_ptr<Core::Video::Screen>;
|
||||
}
|
||||
namespace Audio {
|
||||
using Audio = shared_pointer<Core::Audio::Audio>;
|
||||
using Stream = shared_pointer<Core::Audio::Stream>;
|
||||
using Audio = std::shared_ptr<Core::Audio::Audio>;
|
||||
using Stream = std::shared_ptr<Core::Audio::Stream>;
|
||||
}
|
||||
namespace Input {
|
||||
using Input = shared_pointer<Core::Input::Input>;
|
||||
using Button = shared_pointer<Core::Input::Button>;
|
||||
using Axis = shared_pointer<Core::Input::Axis>;
|
||||
using Trigger = shared_pointer<Core::Input::Trigger>;
|
||||
using Rumble = shared_pointer<Core::Input::Rumble>;
|
||||
using Input = std::shared_ptr<Core::Input::Input>;
|
||||
using Button = std::shared_ptr<Core::Input::Button>;
|
||||
using Axis = std::shared_ptr<Core::Input::Axis>;
|
||||
using Trigger = std::shared_ptr<Core::Input::Trigger>;
|
||||
using Rumble = std::shared_ptr<Core::Input::Rumble>;
|
||||
}
|
||||
namespace Setting {
|
||||
using Setting = shared_pointer<Core::Setting::Setting>;
|
||||
using Boolean = shared_pointer<Core::Setting::Boolean>;
|
||||
using Natural = shared_pointer<Core::Setting::Natural>;
|
||||
using Integer = shared_pointer<Core::Setting::Integer>;
|
||||
using Real = shared_pointer<Core::Setting::Real>;
|
||||
using String = shared_pointer<Core::Setting::String>;
|
||||
using Setting = std::shared_ptr<Core::Setting::Setting>;
|
||||
using Boolean = std::shared_ptr<Core::Setting::Boolean>;
|
||||
using Natural = std::shared_ptr<Core::Setting::Natural>;
|
||||
using Integer = std::shared_ptr<Core::Setting::Integer>;
|
||||
using Real = std::shared_ptr<Core::Setting::Real>;
|
||||
using String = std::shared_ptr<Core::Setting::String>;
|
||||
}
|
||||
namespace Debugger {
|
||||
using Debugger = shared_pointer<Core::Debugger::Debugger>;
|
||||
using Memory = shared_pointer<Core::Debugger::Memory>;
|
||||
using Graphics = shared_pointer<Core::Debugger::Graphics>;
|
||||
using Properties = shared_pointer<Core::Debugger::Properties>;
|
||||
using Debugger = std::shared_ptr<Core::Debugger::Debugger>;
|
||||
using Memory = std::shared_ptr<Core::Debugger::Memory>;
|
||||
using Graphics = std::shared_ptr<Core::Debugger::Graphics>;
|
||||
using Properties = std::shared_ptr<Core::Debugger::Properties>;
|
||||
namespace Tracer {
|
||||
using Tracer = shared_pointer<Core::Debugger::Tracer::Tracer>;
|
||||
using Notification = shared_pointer<Core::Debugger::Tracer::Notification>;
|
||||
using Instruction = shared_pointer<Core::Debugger::Tracer::Instruction>;
|
||||
using Tracer = std::shared_ptr<Core::Debugger::Tracer::Tracer>;
|
||||
using Notification = std::shared_ptr<Core::Debugger::Tracer::Notification>;
|
||||
using Instruction = std::shared_ptr<Core::Debugger::Tracer::Instruction>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,9 +164,10 @@ namespace ares::Node {
|
||||
}
|
||||
|
||||
static inline auto parent(Object child) -> Object {
|
||||
if(!child || !child->parent()) return {};
|
||||
if(auto parent = child->parent().acquire()) return parent;
|
||||
return {};
|
||||
if(!child) return {};
|
||||
auto wp = child->parent();
|
||||
if(wp.expired()) return {};
|
||||
return wp.lock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -177,8 +178,8 @@ namespace ares::Node {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline auto enumerate(Object from) -> vector<T> {
|
||||
vector<T> objects;
|
||||
static inline auto enumerate(Object from) -> std::vector<T> {
|
||||
std::vector<T> objects;
|
||||
if(from) from->enumerate<T>(objects);
|
||||
return objects;
|
||||
}
|
||||
|
||||
+45
-38
@@ -3,13 +3,13 @@
|
||||
|
||||
#define DeclareClass(Type, Name) \
|
||||
static auto identifier() -> string { return Name; } \
|
||||
static auto create() -> Node::Object { return new Type; } \
|
||||
static auto create() -> Node::Object { return std::make_shared<Type>(); } \
|
||||
auto identity() const -> string override { return Name; } \
|
||||
private: static inline Class::Register<Type> register; public: \
|
||||
|
||||
struct Object : shared_pointer_this<Object> {
|
||||
struct Object : std::enable_shared_from_this<Object> {
|
||||
static auto identifier() -> string { return "Object"; }
|
||||
static auto create() -> Node::Object { return new Object; }
|
||||
static auto create() -> Node::Object { return std::make_shared<Object>(); }
|
||||
virtual auto identity() const -> string { return "Object"; }
|
||||
private: static inline Class::Register<Object> register; public:
|
||||
//DeclareClass(Object, "object")
|
||||
@@ -18,44 +18,47 @@ struct Object : shared_pointer_this<Object> {
|
||||
virtual ~Object() = default;
|
||||
|
||||
auto name() const -> string { return _name; }
|
||||
auto parent() const -> shared_pointer_weak<Object> { return _parent; }
|
||||
auto parent() const -> std::weak_ptr<Object> { return _parent; }
|
||||
|
||||
auto setName(string_view name) -> void { _name = name; }
|
||||
|
||||
auto prepend(Node::Object node) -> Node::Object {
|
||||
if(auto found = find(node)) return found;
|
||||
_nodes.prepend(node);
|
||||
node->_parent = shared();
|
||||
_nodes.insert(_nodes.begin(), node);
|
||||
node->_parent = shared_from_this();
|
||||
PlatformAttach(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T, typename... P>
|
||||
auto prepend(P&&... p) -> Node::Object {
|
||||
using Type = typename T::type;
|
||||
return prepend(shared_pointer<Type>::create(std::forward<P>(p)...));
|
||||
auto prepend(P&&... p) -> std::shared_ptr<typename T::element_type> {
|
||||
using Type = typename T::element_type;
|
||||
auto node = std::make_shared<Type>(std::forward<P>(p)...);
|
||||
prepend(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
auto append(Node::Object node) -> Node::Object {
|
||||
if(auto found = find(node)) return found;
|
||||
_nodes.append(node);
|
||||
node->_parent = shared();
|
||||
_nodes.push_back(node);
|
||||
node->_parent = shared_from_this();
|
||||
PlatformAttach(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T, typename... P>
|
||||
auto append(P&&... p) -> Node::Object {
|
||||
using Type = typename T::type;
|
||||
return append(shared_pointer<Type>::create(std::forward<P>(p)...));
|
||||
auto append(P&&... p) -> std::shared_ptr<typename T::element_type> {
|
||||
using Type = typename T::element_type;
|
||||
auto node = std::make_shared<Type>(std::forward<P>(p)...);
|
||||
append(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
auto remove(Node::Object node) -> void {
|
||||
if(auto index = _nodes.find(node)) {
|
||||
if(std::erase(_nodes, node)) {
|
||||
PlatformDetach(node);
|
||||
node->reset();
|
||||
node->_parent.reset();
|
||||
_nodes.remove(*index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,13 +68,12 @@ struct Object : shared_pointer_this<Object> {
|
||||
node->reset();
|
||||
node->_parent.reset();
|
||||
}
|
||||
_nodes.reset();
|
||||
_nodes.clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto cast() -> shared_pointer<typename T::type> {
|
||||
if(dynamic_cast<typename T::type*>(this)) return shared();
|
||||
return {};
|
||||
auto cast() -> std::shared_ptr<typename T::element_type> {
|
||||
return std::dynamic_pointer_cast<typename T::element_type>(shared_from_this());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -80,17 +82,20 @@ struct Object : shared_pointer_this<Object> {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto find() -> vector<shared_pointer<typename T::type>> {
|
||||
vector<shared_pointer<typename T::type>> result;
|
||||
if(dynamic_cast<typename T::type*>(this)) {
|
||||
if(auto instance = shared()) result.append(instance);
|
||||
auto find() -> std::vector<std::shared_ptr<typename T::element_type>> {
|
||||
std::vector<std::shared_ptr<typename T::element_type>> result;
|
||||
if(dynamic_cast<typename T::element_type*>(this)) {
|
||||
if(auto instance = cast<T>()) result.push_back(instance);
|
||||
}
|
||||
for(auto& node : _nodes) {
|
||||
auto sub = node->find<T>();
|
||||
std::ranges::copy(sub, std::back_inserter(result));
|
||||
}
|
||||
for(auto& node : _nodes) result.append(node->find<T>());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto find(u32 index) -> shared_pointer<typename T::type> {
|
||||
auto find(u32 index) -> std::shared_ptr<typename T::element_type> {
|
||||
auto result = find<T>();
|
||||
if(index < result.size()) return result[index];
|
||||
return {};
|
||||
@@ -106,31 +111,33 @@ struct Object : shared_pointer_this<Object> {
|
||||
|
||||
template<typename T = Node::Object>
|
||||
auto find(string name) -> T {
|
||||
using Type = typename T::type;
|
||||
auto path = name.split("/");
|
||||
name = path.takeFirst();
|
||||
using Type = typename T::element_type;
|
||||
auto path = nall::split(name, "/");
|
||||
if(path.empty()) return {};
|
||||
name = path.front();
|
||||
path.erase(path.begin());
|
||||
for(auto& node : _nodes) {
|
||||
if(node->_name != name) continue;
|
||||
if(path) return node->find<T>(path.merge("/"));
|
||||
if(node->identity() == Type::identifier()) return node;
|
||||
if(!path.empty()) return node->find<T>(nall::merge(path, "/"));
|
||||
if(node->identity() == Type::identifier()) return node->template cast<T>();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T = Node::Object>
|
||||
auto scan(string name) -> T {
|
||||
using Type = typename T::type;
|
||||
using Type = typename T::element_type;
|
||||
for(auto& node : _nodes) {
|
||||
if(node->identity() == Type::identifier() && node->_name == name) return node;
|
||||
if(node->identity() == Type::identifier() && node->_name == name) return node->template cast<T>();
|
||||
if(auto result = node->scan<T>(name)) return result;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto enumerate(vector<T>& objects) -> void {
|
||||
using Type = typename T::type;
|
||||
if(auto instance = cast<T>()) objects.append(instance);
|
||||
auto enumerate(std::vector<T>& objects) -> void {
|
||||
using Type = typename T::element_type;
|
||||
if(auto instance = cast<T>()) objects.push_back(instance);
|
||||
for(auto& node : _nodes) node->enumerate<T>(objects);
|
||||
}
|
||||
|
||||
@@ -230,6 +237,6 @@ protected:
|
||||
string _name;
|
||||
VFS::Pak _pak;
|
||||
set<Attribute> _attributes;
|
||||
shared_pointer_weak<Object> _parent;
|
||||
vector<Node::Object> _nodes;
|
||||
std::weak_ptr<Object> _parent;
|
||||
std::vector<Node::Object> _nodes;
|
||||
};
|
||||
@@ -5,15 +5,15 @@ struct Port : Object {
|
||||
auto type() const -> string { return _type; }
|
||||
auto family() const -> string { return _family; }
|
||||
auto hotSwappable() const -> bool { return _hotSwappable; }
|
||||
auto supported() const -> vector<string> { return _supported; }
|
||||
auto supported() const -> std::vector<string> { return _supported; }
|
||||
|
||||
auto setAllocate(function<Node::Peripheral (string)> allocate) -> void { _allocate = allocate; }
|
||||
auto setConnect(function<void ()> connect) -> void { _connect = connect; }
|
||||
auto setDisconnect(function<void ()> disconnect) -> void { _disconnect = disconnect; }
|
||||
auto setAllocate(std::function<Node::Peripheral (string)> allocate) -> void { _allocate = allocate; }
|
||||
auto setConnect(std::function<void ()> connect) -> void { _connect = connect; }
|
||||
auto setDisconnect(std::function<void ()> disconnect) -> void { _disconnect = disconnect; }
|
||||
auto setType(string type) -> void { _type = type; }
|
||||
auto setFamily(string family) -> void { _family = family; }
|
||||
auto setHotSwappable(bool hotSwappable) -> void { _hotSwappable = hotSwappable; }
|
||||
auto setSupported(vector<string> supported) -> void { _supported = supported; }
|
||||
auto setSupported(std::vector<string> supported) -> void { _supported = supported; }
|
||||
|
||||
auto connected() -> Node::Peripheral {
|
||||
return find<Node::Peripheral>(0);
|
||||
@@ -64,11 +64,11 @@ struct Port : Object {
|
||||
}
|
||||
|
||||
protected:
|
||||
function<Node::Peripheral (string)> _allocate;
|
||||
function<void ()> _connect;
|
||||
function<void ()> _disconnect;
|
||||
std::function<Node::Peripheral (string)> _allocate;
|
||||
std::function<void ()> _connect;
|
||||
std::function<void ()> _disconnect;
|
||||
string _type;
|
||||
string _family;
|
||||
bool _hotSwappable = false;
|
||||
vector<string> _supported;
|
||||
std::vector<string> _supported;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Boolean : Setting {
|
||||
DeclareClass(Boolean, "setting.boolean")
|
||||
|
||||
Boolean(string name = {}, bool value = {}, function<void (bool)> modify = {}) : Setting(name) {
|
||||
Boolean(string name = {}, bool value = {}, std::function<void (bool)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,7 +11,7 @@ struct Boolean : Setting {
|
||||
auto value() const -> bool { return _currentValue; }
|
||||
auto latch() const -> bool { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (bool)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (bool)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(bool value) -> void {
|
||||
_currentValue = value;
|
||||
@@ -26,11 +26,11 @@ struct Boolean : Setting {
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override { return {"false", "true"}; }
|
||||
auto readAllowedValues() const -> std::vector<string> override { return {"false", "true"}; }
|
||||
auto writeValue(string value) -> void override { setValue(value.boolean()); }
|
||||
|
||||
protected:
|
||||
function<void (bool)> _modify;
|
||||
std::function<void (bool)> _modify;
|
||||
bool _currentValue = {};
|
||||
bool _latchedValue = {};
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Integer : Setting {
|
||||
DeclareClass(Integer, "setting.integer")
|
||||
|
||||
Integer(string name = {}, s64 value = {}, function<void (s64)> modify = {}) : Setting(name) {
|
||||
Integer(string name = {}, s64 value = {}, std::function<void (s64)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct Integer : Setting {
|
||||
auto value() const -> s64 { return _currentValue; }
|
||||
auto latch() const -> s64 { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (s64)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (s64)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(s64 value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,23 +25,23 @@ struct Integer : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<s64> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<s64> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override {
|
||||
vector<string> values;
|
||||
for(auto value : _allowedValues) values.append(value);
|
||||
auto readAllowedValues() const -> std::vector<string> override {
|
||||
std::vector<string> values;
|
||||
for(auto value : _allowedValues) values.push_back(value);
|
||||
return values;
|
||||
}
|
||||
auto writeValue(string value) -> void override { setValue(value.integer()); }
|
||||
|
||||
protected:
|
||||
function<void (s64)> _modify;
|
||||
std::function<void (s64)> _modify;
|
||||
s64 _currentValue = {};
|
||||
s64 _latchedValue = {};
|
||||
vector<s64> _allowedValues;
|
||||
std::vector<s64> _allowedValues;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Natural : Setting {
|
||||
DeclareClass(Natural, "setting.natural")
|
||||
|
||||
Natural(string name = {}, u64 value = {}, function<void (u64)> modify = {}) : Setting(name) {
|
||||
Natural(string name = {}, u64 value = {}, std::function<void (u64)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct Natural : Setting {
|
||||
auto value() const -> u64 { return _currentValue; }
|
||||
auto latch() const -> u64 { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (u64)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (u64)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(u64 value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,23 +25,23 @@ struct Natural : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<u64> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<u64> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override {
|
||||
vector<string> values;
|
||||
for(auto value : _allowedValues) values.append(value);
|
||||
auto readAllowedValues() const -> std::vector<string> override {
|
||||
std::vector<string> values;
|
||||
for(auto value : _allowedValues) values.push_back(value);
|
||||
return values;
|
||||
}
|
||||
auto writeValue(string value) -> void override { setValue(value.natural()); }
|
||||
|
||||
protected:
|
||||
function<void (u64)> _modify;
|
||||
std::function<void (u64)> _modify;
|
||||
u64 _currentValue = {};
|
||||
u64 _latchedValue = {};
|
||||
vector<u64> _allowedValues;
|
||||
std::vector<u64> _allowedValues;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
struct Real : Setting {
|
||||
DeclareClass(Real, "setting.real")
|
||||
|
||||
Real(string name = {}, f64 value = {}, function<void (f64)> modify = {}) : Setting(name) {
|
||||
Real(string name = {}, f64 value = {}, std::function<void (f64)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct Real : Setting {
|
||||
auto value() const -> f64 { return _currentValue; }
|
||||
auto latch() const -> f64 { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (f64)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (f64)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(f64 value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,23 +25,23 @@ struct Real : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<f64> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<f64> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override {
|
||||
vector<string> values;
|
||||
for(auto value : _allowedValues) values.append(value);
|
||||
auto readAllowedValues() const -> std::vector<string> override {
|
||||
std::vector<string> values;
|
||||
for(auto value : _allowedValues) values.push_back(value);
|
||||
return values;
|
||||
}
|
||||
auto writeValue(string value) -> void override { setValue(value.real()); }
|
||||
|
||||
protected:
|
||||
function<void (f64)> _modify;
|
||||
std::function<void (f64)> _modify;
|
||||
f64 _currentValue = {};
|
||||
f64 _latchedValue = {};
|
||||
vector<f64> _allowedValues;
|
||||
std::vector<f64> _allowedValues;
|
||||
};
|
||||
@@ -12,12 +12,12 @@ struct Setting : Object {
|
||||
|
||||
virtual auto readValue() const -> string { return {}; }
|
||||
virtual auto readLatch() const -> string { return {}; }
|
||||
virtual auto readAllowedValues() const -> vector<string> { return {}; }
|
||||
virtual auto readAllowedValues() const -> std::vector<string> { return {}; }
|
||||
virtual auto writeValue(string value) -> void {}
|
||||
|
||||
auto load(Node::Object source) -> bool override {
|
||||
if(!Object::load(source)) return false;
|
||||
if(auto setting = source->cast<shared_pointer<Setting>>()) writeValue(setting->readValue());
|
||||
if(auto setting = source->cast<Node::Setting::Setting>()) writeValue(setting->readValue());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
struct String : Setting {
|
||||
DeclareClass(String, "setting.string")
|
||||
|
||||
String(string name = {}, string value = {}, function<void (string)> modify = {}) : Setting(name) {
|
||||
String(string name = {}, string value = {}, std::function<void (string)> modify = {}) : Setting(name) {
|
||||
_currentValue = value;
|
||||
_latchedValue = value;
|
||||
_modify = modify;
|
||||
@@ -11,10 +11,10 @@ struct String : Setting {
|
||||
auto value() const -> string { return _currentValue; }
|
||||
auto latch() const -> string { return _latchedValue; }
|
||||
|
||||
auto setModify(function<void (string)> modify) { _modify = modify; }
|
||||
auto setModify(std::function<void (string)> modify) { _modify = modify; }
|
||||
|
||||
auto setValue(string value) -> void {
|
||||
if(_allowedValues && !_allowedValues.find(value)) return;
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
|
||||
_currentValue = value;
|
||||
if(_dynamic) setLatch();
|
||||
}
|
||||
@@ -25,19 +25,19 @@ struct String : Setting {
|
||||
modify(_latchedValue);
|
||||
}
|
||||
|
||||
auto setAllowedValues(vector<string> allowedValues) -> void {
|
||||
auto setAllowedValues(std::vector<string> allowedValues) -> void {
|
||||
_allowedValues = allowedValues;
|
||||
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
|
||||
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
|
||||
}
|
||||
|
||||
auto readValue() const -> string override { return value(); }
|
||||
auto readLatch() const -> string override { return latch(); }
|
||||
auto readAllowedValues() const -> vector<string> override { return _allowedValues; }
|
||||
auto readAllowedValues() const -> std::vector<string> override { return _allowedValues; }
|
||||
auto writeValue(string value) -> void override { setValue(value); }
|
||||
|
||||
protected:
|
||||
function<void (string)> _modify;
|
||||
std::function<void (string)> _modify;
|
||||
string _currentValue = {};
|
||||
string _latchedValue = {};
|
||||
vector<string> _allowedValues;
|
||||
std::vector<string> _allowedValues;
|
||||
};
|
||||
+14
-14
@@ -10,20 +10,20 @@ struct System : Object {
|
||||
auto serialize(bool synchronize = true) -> serializer { if(_serialize) return _serialize(synchronize); return {}; }
|
||||
auto unserialize(serializer& s) -> bool { if(_unserialize) return _unserialize(s); return false; }
|
||||
|
||||
auto setGame(function<string ()> game) -> void { _game = game; }
|
||||
auto setRun(function<void ()> run) -> void { _run = run; }
|
||||
auto setPower(function<void (bool)> power) -> void { _power = power; }
|
||||
auto setSave(function<void ()> save) -> void { _save = save; }
|
||||
auto setUnload(function<void ()> unload) -> void { _unload = unload; }
|
||||
auto setSerialize(function<serializer (bool)> serialize) -> void { _serialize = serialize; }
|
||||
auto setUnserialize(function<bool (serializer&)> unserialize) -> void { _unserialize = unserialize; }
|
||||
auto setGame(std::function<string ()> game) -> void { _game = game; }
|
||||
auto setRun(std::function<void ()> run) -> void { _run = run; }
|
||||
auto setPower(std::function<void (bool)> power) -> void { _power = power; }
|
||||
auto setSave(std::function<void ()> save) -> void { _save = save; }
|
||||
auto setUnload(std::function<void ()> unload) -> void { _unload = unload; }
|
||||
auto setSerialize(std::function<serializer (bool)> serialize) -> void { _serialize = serialize; }
|
||||
auto setUnserialize(std::function<bool (serializer&)> unserialize) -> void { _unserialize = unserialize; }
|
||||
|
||||
protected:
|
||||
function<string ()> _game;
|
||||
function<void ()> _run;
|
||||
function<void (bool)> _power;
|
||||
function<void ()> _save;
|
||||
function<void ()> _unload;
|
||||
function<serializer (bool)> _serialize;
|
||||
function<bool (serializer&)> _unserialize;
|
||||
std::function<string ()> _game;
|
||||
std::function<void ()> _run;
|
||||
std::function<void (bool)> _power;
|
||||
std::function<void ()> _save;
|
||||
std::function<void ()> _unload;
|
||||
std::function<serializer (bool)> _serialize;
|
||||
std::function<bool (serializer&)> _unserialize;
|
||||
};
|
||||
@@ -1,15 +1,18 @@
|
||||
#include <memory>
|
||||
Screen::Screen(string name, u32 width, u32 height) : Video(name) {
|
||||
_canvasWidth = width;
|
||||
_canvasHeight = height;
|
||||
|
||||
if(width && height) {
|
||||
_inputA = new u32[width * height]();
|
||||
_inputB = new u32[width * height]();
|
||||
_output = new u32[width * height]();
|
||||
_rotate = new u32[width * height]();
|
||||
_inputA = std::make_unique<u32[]>(width * height);
|
||||
_inputB = std::make_unique<u32[]>(width * height);
|
||||
_output = std::make_unique<u32[]>(width * height);
|
||||
_rotate = std::make_unique<u32[]>(width * height);
|
||||
_lineOverrideActive.resize(width * height, false);
|
||||
_lineOverride.resize(width * height, nullptr);
|
||||
|
||||
if constexpr(ares::Video::Threaded) {
|
||||
_thread = nall::thread::create({&Screen::main, this});
|
||||
_thread = nall::thread::create(std::bind_front(&Screen::main, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,34 +44,37 @@ auto Screen::main(uintptr_t) -> void {
|
||||
auto Screen::quit() -> void {
|
||||
_kill = true;
|
||||
_thread.join();
|
||||
_sprites.reset();
|
||||
_sprites.clear();
|
||||
}
|
||||
|
||||
auto Screen::power() -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
memory::fill<u32>(_inputA.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_inputB.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_output.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_rotate.data(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_inputA.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_inputB.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_output.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<u32>(_rotate.get(), _canvasWidth * _canvasHeight, _fillColor);
|
||||
memory::fill<n1>(_lineOverrideActive.data(), _canvasWidth * _canvasHeight, false);
|
||||
memory::fill<const u32*>(_lineOverride.data(), _canvasWidth * _canvasHeight, nullptr);
|
||||
}
|
||||
|
||||
auto Screen::pixels(bool frame) -> array_span<u32> {
|
||||
if(frame == 0) return {_inputA.data(), _canvasWidth * _canvasHeight};
|
||||
if(frame == 1) return {_inputB.data(), _canvasWidth * _canvasHeight};
|
||||
auto Screen::pixels(bool frame) -> std::span<u32> {
|
||||
if(frame == 0) return {_inputA.get(), _canvasWidth * _canvasHeight};
|
||||
if(frame == 1) return {_inputB.get(), _canvasWidth * _canvasHeight};
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Screen::resetPalette() -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::resetSprites() -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_sprites.reset();
|
||||
_sprites.clear();
|
||||
}
|
||||
|
||||
auto Screen::setRefresh(function<void ()> refresh) -> void {
|
||||
auto Screen::setRefresh(std::function<void ()> refresh) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_refresh = refresh;
|
||||
}
|
||||
@@ -117,18 +123,21 @@ auto Screen::setSaturation(f64 saturation) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_saturation = saturation;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::setGamma(f64 gamma) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_gamma = gamma;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::setLuminance(f64 luminance) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_luminance = luminance;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::setFillColor(u32 fillColor) -> void {
|
||||
@@ -172,21 +181,22 @@ auto Screen::setInterlace(bool interlaceField) -> void {
|
||||
|
||||
auto Screen::attach(Node::Video::Sprite sprite) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
if(_sprites.find(sprite)) return;
|
||||
_sprites.append(sprite);
|
||||
if(std::ranges::find(_sprites, sprite) != _sprites.end()) return;
|
||||
_sprites.push_back(sprite);
|
||||
}
|
||||
|
||||
auto Screen::detach(Node::Video::Sprite sprite) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
if(!_sprites.find(sprite)) return;
|
||||
_sprites.removeByValue(sprite);
|
||||
if(std::ranges::find(_sprites, sprite) == _sprites.end()) return;
|
||||
std::erase(_sprites, sprite);
|
||||
}
|
||||
|
||||
auto Screen::colors(u32 colors, function<n64 (n32)> color) -> void {
|
||||
auto Screen::colors(u32 colors, std::function<n64 (n32)> color) -> void {
|
||||
lock_guard<recursive_mutex> lock(_mutex);
|
||||
_colors = colors;
|
||||
_color = color;
|
||||
_palette.reset();
|
||||
refreshPalette();
|
||||
}
|
||||
|
||||
auto Screen::frame() -> void {
|
||||
@@ -219,14 +229,20 @@ auto Screen::refresh() -> void {
|
||||
auto pitch = _canvasWidth;
|
||||
auto width = _canvasWidth;
|
||||
auto height = _canvasHeight;
|
||||
auto input = _inputB.data();
|
||||
auto output = _output.data();
|
||||
auto input = _inputB.get();
|
||||
auto output = _output.get();
|
||||
|
||||
for(u32 y : range(height)) {
|
||||
auto source = input + y * pitch;
|
||||
auto target = output + y * width;
|
||||
|
||||
if(_interlace) {
|
||||
if (_lineOverrideActive[y]) {
|
||||
auto source = _lineOverride[y];
|
||||
for(u32 x : range(width)) {
|
||||
auto color = *source++;
|
||||
*target++ = color;
|
||||
}
|
||||
} else if(_interlace) {
|
||||
if((_interlaceField & 1) == (y & 1)) {
|
||||
for(u32 x : range(width)) {
|
||||
auto color = _palette[*source++];
|
||||
@@ -295,11 +311,11 @@ auto Screen::refresh() -> void {
|
||||
for(u32 y : range(height)) {
|
||||
auto source = output + y * width;
|
||||
for(u32 x : range(width)) {
|
||||
auto target = _rotate.data() + (width - 1 - x) * height + y;
|
||||
auto target = _rotate.get() + (width - 1 - x) * height + y;
|
||||
*target = *source++;
|
||||
}
|
||||
}
|
||||
output = _rotate.data();
|
||||
output = _rotate.get();
|
||||
swap(width, height);
|
||||
swap(viewWidth, viewHeight);
|
||||
}
|
||||
@@ -309,11 +325,11 @@ auto Screen::refresh() -> void {
|
||||
for(u32 y : range(height)) {
|
||||
auto source = output + y * width;
|
||||
for(u32 x : range(width)) {
|
||||
auto target = _rotate.data() + (height - 1 - y) * width + (width - 1 - x);
|
||||
auto target = _rotate.get() + (height - 1 - y) * width + (width - 1 - x);
|
||||
*target = *source++;
|
||||
}
|
||||
}
|
||||
output = _rotate.data();
|
||||
output = _rotate.get();
|
||||
}
|
||||
|
||||
if(_rotation == 270) {
|
||||
@@ -321,17 +337,31 @@ auto Screen::refresh() -> void {
|
||||
for(u32 y : range(height)) {
|
||||
auto source = output + y * width;
|
||||
for(u32 x : range(width)) {
|
||||
auto target = _rotate.data() + x * height + (height - 1 - y);
|
||||
auto target = _rotate.get() + x * height + (height - 1 - y);
|
||||
*target = *source++;
|
||||
}
|
||||
}
|
||||
output = _rotate.data();
|
||||
output = _rotate.get();
|
||||
swap(width, height);
|
||||
swap(viewWidth, viewHeight);
|
||||
}
|
||||
|
||||
platform->video(shared(), output + viewX + viewY * width, width * sizeof(u32), viewWidth, viewHeight);
|
||||
memory::fill<u32>(_inputB.data(), width * height, _fillColor);
|
||||
platform->video(std::static_pointer_cast<Core::Video::Screen>(shared_from_this()), output + viewX + viewY * width, width * sizeof(u32), viewWidth, viewHeight);
|
||||
memory::fill<u32>(_inputB.get(), width * height, _fillColor);
|
||||
}
|
||||
|
||||
auto Screen::lookupPalette(u32 index) -> u32 {
|
||||
return _palette[index];
|
||||
}
|
||||
|
||||
auto Screen::overrideLineDraw(u32 y, const u32* source) -> void {
|
||||
_lineOverride[y] = source;
|
||||
_lineOverrideActive[y] = true;
|
||||
}
|
||||
|
||||
auto Screen::clearOverrideLineDraw(u32 y) -> void {
|
||||
_lineOverrideActive[y] = false;
|
||||
_lineOverride[y] = nullptr;
|
||||
}
|
||||
|
||||
auto Screen::refreshPalette() -> void {
|
||||
@@ -339,7 +369,7 @@ auto Screen::refreshPalette() -> void {
|
||||
if(_palette) return;
|
||||
|
||||
//generate the color lookup palettes to convert native colors to ARGB8888
|
||||
_palette = new u32[_colors];
|
||||
_palette = std::make_unique<u32[]>(_colors);
|
||||
for(u32 index : range(_colors)) {
|
||||
n64 color = _color(index);
|
||||
n16 b = color.bit( 0,15);
|
||||
@@ -349,10 +379,9 @@ auto Screen::refreshPalette() -> void {
|
||||
|
||||
if(_saturation != 1.0) {
|
||||
n16 grayscale = uclamp<16>((r + g + b) / 3);
|
||||
f64 inverse = max(0.0, 1.0 - _saturation);
|
||||
r = uclamp<16>(r * _saturation + grayscale * inverse);
|
||||
g = uclamp<16>(g * _saturation + grayscale * inverse);
|
||||
b = uclamp<16>(b * _saturation + grayscale * inverse);
|
||||
r = uclamp<16>(grayscale + (r - grayscale) * _saturation);
|
||||
g = uclamp<16>(grayscale + (g - grayscale) * _saturation);
|
||||
b = uclamp<16>(grayscale + (b - grayscale) * _saturation);
|
||||
}
|
||||
|
||||
if(_gamma != 1.0) {
|
||||
|
||||
@@ -18,7 +18,7 @@ struct Screen : Video {
|
||||
auto aspectY() const -> f64 { return _aspectY; }
|
||||
auto overscan() const -> bool { return _overscan; }
|
||||
auto colors() const -> u32 { return _colors; }
|
||||
auto pixels(bool frame = 0) -> array_span<u32>;
|
||||
auto pixels(bool frame = 0) -> std::span<u32>;
|
||||
|
||||
auto saturation() const -> double { return _saturation; }
|
||||
auto gamma() const -> double { return _gamma; }
|
||||
@@ -32,7 +32,7 @@ struct Screen : Video {
|
||||
auto resetPalette() -> void;
|
||||
auto resetSprites() -> void;
|
||||
|
||||
auto setRefresh(function<void ()> refresh) -> void;
|
||||
auto setRefresh(std::function<void ()> refresh) -> void;
|
||||
auto setViewport(u32 x, u32 y, u32 width, u32 height) -> void;
|
||||
auto refreshRateHint(double refreshRate) -> void;
|
||||
auto refreshRateHint(double pixelFrequency, int dotsPerLine, int linesPerFrame) -> void;
|
||||
@@ -58,9 +58,12 @@ struct Screen : Video {
|
||||
auto attach(Node::Video::Sprite) -> void;
|
||||
auto detach(Node::Video::Sprite) -> void;
|
||||
|
||||
auto colors(u32 colors, function<n64 (n32)> color) -> void;
|
||||
auto colors(u32 colors, std::function<n64 (n32)> color) -> void;
|
||||
auto frame() -> void;
|
||||
auto refresh() -> void;
|
||||
auto lookupPalette(u32 index) -> u32;
|
||||
auto overrideLineDraw(u32 y, const u32* source) -> void;
|
||||
auto clearOverrideLineDraw(u32 y) -> void;
|
||||
|
||||
auto serialize(string& output, string depth) -> void override;
|
||||
auto unserialize(Markup::Node node) -> void override;
|
||||
@@ -88,13 +91,15 @@ protected:
|
||||
bool _overscan = true;
|
||||
u32 _rotation = 0; //counter-clockwise (90 = left, 270 = right)
|
||||
|
||||
function<n64 (n32)> _color;
|
||||
unique_pointer<u32[]> _inputA;
|
||||
unique_pointer<u32[]> _inputB;
|
||||
unique_pointer<u32[]> _output;
|
||||
unique_pointer<u32[]> _rotate;
|
||||
unique_pointer<u32[]> _palette;
|
||||
vector<Node::Video::Sprite> _sprites;
|
||||
std::function<n64 (n32)> _color;
|
||||
std::unique_ptr<u32[]> _inputA;
|
||||
std::unique_ptr<u32[]> _inputB;
|
||||
std::unique_ptr<u32[]> _output;
|
||||
std::unique_ptr<u32[]> _rotate;
|
||||
std::unique_ptr<u32[]> _palette;
|
||||
std::vector<n1> _lineOverrideActive;
|
||||
std::vector<const u32*> _lineOverride;
|
||||
std::vector<Node::Video::Sprite> _sprites;
|
||||
|
||||
//unserialized:
|
||||
nall::thread _thread;
|
||||
@@ -103,7 +108,7 @@ protected:
|
||||
condition_variable _frameCondition;
|
||||
atomic<bool> _kill = false;
|
||||
atomic<bool> _frame = false;
|
||||
function<void ()> _refresh;
|
||||
std::function<void ()> _refresh;
|
||||
bool _progressive = false;
|
||||
bool _progressiveDouble = false;
|
||||
bool _interlace = false;
|
||||
|
||||
@@ -10,13 +10,13 @@ auto Sprite::setPosition(u32 x, u32 y) -> void {
|
||||
auto Sprite::setImage(nall::image image, bool invert) -> void {
|
||||
_width = image.width();
|
||||
_height = image.height();
|
||||
_pixels = new u32[_width * _height];
|
||||
_pixels = std::make_unique<u32[]>(_width * _height);
|
||||
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
|
||||
memory::copy(_pixels.data(), _width * _height * sizeof(u32), image.data(), image.size());
|
||||
memory::copy(_pixels.get(), _width * _height * sizeof(u32), image.data(), image.size());
|
||||
if(!invert) return;
|
||||
|
||||
for(u32 y : range(_height)) {
|
||||
auto data = _pixels.data() + y * _width;
|
||||
auto data = _pixels.get() + y * _width;
|
||||
for(u32 x : range(_width)) {
|
||||
auto pixel = data[x];
|
||||
pixel ^= 0xffffff;
|
||||
|
||||
@@ -7,7 +7,7 @@ struct Sprite : Video {
|
||||
auto y() const -> u32 { return _y; }
|
||||
auto width() const -> u32 { return _width; }
|
||||
auto height() const -> u32 { return _height; }
|
||||
auto image() const -> array_view<u32> { return {_pixels.data(), _width * _height}; }
|
||||
auto image() const -> std::span<const u32> { return {_pixels.get(), _width * _height}; }
|
||||
|
||||
auto setVisible(bool visible) -> void;
|
||||
auto setPosition(u32 x, u32 y) -> void;
|
||||
@@ -19,5 +19,5 @@ protected:
|
||||
u32 _y = 0;
|
||||
u32 _width = 0;
|
||||
u32 _height = 0;
|
||||
unique_pointer<u32[]> _pixels;
|
||||
std::unique_ptr<u32[]> _pixels;
|
||||
};
|
||||
@@ -13,7 +13,7 @@ enum class Event : u32 {
|
||||
struct Platform {
|
||||
virtual auto attach(Node::Object) -> void {}
|
||||
virtual auto detach(Node::Object) -> void {}
|
||||
virtual auto pak(Node::Object) -> shared_pointer<vfs::directory> { return {}; }
|
||||
virtual auto pak(Node::Object) -> std::shared_ptr<vfs::directory> { return {}; }
|
||||
virtual auto event(Event) -> void {}
|
||||
virtual auto log(Node::Debugger::Tracer::Tracer, string_view message) -> void {}
|
||||
virtual auto status(string_view message) -> void {}
|
||||
|
||||
+13
-5
@@ -4,6 +4,9 @@ namespace ares {
|
||||
|
||||
struct Random {
|
||||
enum class Entropy : u32 { None, Low, High };
|
||||
struct Init { u64 seed, sequence; };
|
||||
|
||||
static constexpr Init Default { 0x853c49e6748fea9b, 0xda3e39cb94b95bdb };
|
||||
|
||||
auto operator()() -> n64 {
|
||||
return random();
|
||||
@@ -14,8 +17,8 @@ struct Random {
|
||||
seed();
|
||||
}
|
||||
|
||||
auto seed(maybe<n32> seed = nothing, maybe<n32> sequence = nothing) -> void {
|
||||
if(!seed) seed = (n32)clock();
|
||||
auto seed(maybe<n64> seed = nothing, maybe<n64> sequence = nothing) -> void {
|
||||
if(!seed) seed = (n64)clock();
|
||||
if(!sequence) sequence = 0;
|
||||
|
||||
_state = 0;
|
||||
@@ -25,6 +28,10 @@ struct Random {
|
||||
step();
|
||||
}
|
||||
|
||||
auto seed(Init init) -> void {
|
||||
seed((n64)init.seed, (n64)init.sequence);
|
||||
}
|
||||
|
||||
auto random() -> n64 {
|
||||
if(_entropy == Entropy::None) return 0;
|
||||
return (n64)step() << 32 | (n64)step() << 0;
|
||||
@@ -43,15 +50,16 @@ struct Random {
|
||||
}
|
||||
}
|
||||
|
||||
auto array(array_span<n8> buffer) -> void {
|
||||
auto array(std::span<u8> buffer) -> void {
|
||||
if(_entropy == Entropy::None) {
|
||||
memory::fill(buffer.data(), buffer.size());
|
||||
return;
|
||||
}
|
||||
|
||||
if(_entropy == Entropy::High) {
|
||||
for(n32 address : range(buffer.size())) {
|
||||
buffer[address] = random();
|
||||
while(buffer.size()) {
|
||||
u64 value = random();
|
||||
nall::writel(buffer, value, min((u32)sizeof(value), (u32)buffer.size()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
inline auto Scheduler::reset() -> void {
|
||||
_threads.reset();
|
||||
_threads.clear();
|
||||
}
|
||||
|
||||
inline auto Scheduler::threads() const -> u32 {
|
||||
@@ -41,15 +41,15 @@ inline auto Scheduler::maximum() const -> u64 {
|
||||
}
|
||||
|
||||
inline auto Scheduler::append(Thread& thread) -> bool {
|
||||
if(_threads.find(&thread)) return false;
|
||||
if(std::ranges::find(_threads, &thread) != _threads.end()) return false;
|
||||
thread._uniqueID = uniqueID();
|
||||
thread._clock = maximum() + thread._uniqueID;
|
||||
_threads.append(&thread);
|
||||
_threads.push_back(&thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline auto Scheduler::remove(Thread& thread) -> void {
|
||||
_threads.removeByValue(&thread);
|
||||
std::erase(_threads, &thread);
|
||||
}
|
||||
|
||||
//power cycle and soft reset events: assigns the primary thread and resets all thread clocks.
|
||||
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
cothread_t _primary = nullptr; //primary thread (used to synchronize components)
|
||||
Mode _mode = Mode::Run;
|
||||
Event _event = Event::Step;
|
||||
vector<Thread*> _threads;
|
||||
std::vector<Thread*> _threads;
|
||||
bool _synchronize = false;
|
||||
|
||||
friend struct Thread;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
inline auto Thread::EntryPoints() -> vector<EntryPoint>& {
|
||||
static vector<EntryPoint> entryPoints;
|
||||
inline auto Thread::EntryPoints() -> std::vector<EntryPoint>& {
|
||||
static std::vector<EntryPoint> entryPoints;
|
||||
return entryPoints;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ inline auto Thread::Enter() -> void {
|
||||
for(u32 index : range(EntryPoints().size())) {
|
||||
if(co_active() == EntryPoints()[index].handle) {
|
||||
auto entryPoint = EntryPoints()[index].entryPoint;
|
||||
EntryPoints().remove(index);
|
||||
EntryPoints().erase(EntryPoints().begin() + index);
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
entryPoint();
|
||||
@@ -45,22 +45,22 @@ inline auto Thread::setClock(u64 clock) -> void {
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
inline auto Thread::create(double frequency, function<void ()> entryPoint) -> void {
|
||||
inline auto Thread::create(double frequency, std::function<void ()> entryPoint) -> void {
|
||||
if(!_handle) {
|
||||
_handle = co_create(Thread::Size, &Thread::Enter);
|
||||
} else {
|
||||
co_derive(_handle, Thread::Size, &Thread::Enter);
|
||||
}
|
||||
EntryPoints().append({_handle, entryPoint});
|
||||
EntryPoints().push_back({_handle, entryPoint});
|
||||
setFrequency(frequency);
|
||||
setClock(0);
|
||||
scheduler.append(*this);
|
||||
}
|
||||
|
||||
//returns a thread to its entry point (eg for a reset), without resetting the clock value
|
||||
inline auto Thread::restart(function<void()> entryPoint) -> void {
|
||||
inline auto Thread::restart(std::function<void()> entryPoint) -> void {
|
||||
co_derive(_handle, Thread::Size, &Thread::Enter);
|
||||
EntryPoints().append({_handle, entryPoint});
|
||||
EntryPoints().push_back({_handle, entryPoint});
|
||||
}
|
||||
|
||||
inline auto Thread::destroy() -> void {
|
||||
|
||||
@@ -6,10 +6,10 @@ struct Thread {
|
||||
|
||||
struct EntryPoint {
|
||||
cothread_t handle = nullptr;
|
||||
function<void ()> entryPoint;
|
||||
std::function<void ()> entryPoint;
|
||||
};
|
||||
|
||||
static auto EntryPoints() -> vector<EntryPoint>&;
|
||||
static auto EntryPoints() -> std::vector<EntryPoint>&;
|
||||
static auto Enter() -> void;
|
||||
|
||||
Thread() = default;
|
||||
@@ -29,8 +29,8 @@ struct Thread {
|
||||
auto setScalar(u64 scalar) -> void;
|
||||
auto setClock(u64 clock) -> void;
|
||||
|
||||
auto create(double frequency, function<void ()> entryPoint) -> void;
|
||||
auto restart(function<void ()> entryPoint) -> void;
|
||||
auto create(double frequency, std::function<void ()> entryPoint) -> void;
|
||||
auto restart(std::function<void ()> entryPoint) -> void;
|
||||
auto destroy() -> void;
|
||||
|
||||
auto step(u32 clocks) -> void;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
list(REMOVE_DUPLICATES ares.components)
|
||||
|
||||
set(ARES_COMPONENTS_LIST "${ares.components}" CACHE STRING "Enabled shared hardware components" FORCE)
|
||||
|
||||
mark_as_advanced(ARES_COMPONENTS_LIST)
|
||||
|
||||
ares_add_sources(INCLUDED CMakeLists.txt)
|
||||
|
||||
macro(component_sources)
|
||||
@@ -134,6 +138,7 @@ component_sources(
|
||||
INCLUDED
|
||||
processor/arm7tdmi/algorithms.cpp
|
||||
processor/arm7tdmi/arm7tdmi.hpp
|
||||
processor/arm7tdmi/coprocessor.cpp
|
||||
processor/arm7tdmi/disassembler.cpp
|
||||
processor/arm7tdmi/instruction.cpp
|
||||
processor/arm7tdmi/instructions-arm.cpp
|
||||
|
||||
@@ -135,10 +135,10 @@ auto YM2149::read() -> n8 {
|
||||
data.bit(4,7) = envelope.unused;
|
||||
break;
|
||||
case 14:
|
||||
data.bit(0,7) = portA.data;
|
||||
data.bit(0,7) = readIO(0);
|
||||
break;
|
||||
case 15:
|
||||
data.bit(0,7) = portB.data;
|
||||
data.bit(0,7) = readIO(1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -215,9 +215,11 @@ auto YM2149::write(n8 data) -> void {
|
||||
break;
|
||||
case 14:
|
||||
portA.data = data;
|
||||
writeIO(0, data);
|
||||
break;
|
||||
case 15:
|
||||
portB.data = data;
|
||||
writeIO(1, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace ares {
|
||||
//Yamaha YM2149 (General Instrument AY-3-8910 derivative)
|
||||
|
||||
struct YM2149 {
|
||||
virtual auto readIO(n1 port) -> n8 { return 0xff; }
|
||||
virtual auto writeIO(n1 port, n8 data) -> void {}
|
||||
|
||||
//ym2149.cpp
|
||||
auto clock() -> array<n5[3]>;
|
||||
auto read() -> n8;
|
||||
|
||||
@@ -15,7 +15,7 @@ auto M24C::serialize(serializer& s) -> void {
|
||||
s(output);
|
||||
s(response);
|
||||
s(writable);
|
||||
s(array_span<u8>{memory, size()});
|
||||
s(std::span<n8>{memory, size()});
|
||||
if(type >= Type::M24C32) s(idpage);
|
||||
s(locked);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ struct ARM7TDMI {
|
||||
}
|
||||
|
||||
n32 data;
|
||||
function<auto () -> void> modify;
|
||||
std::function<auto () -> void> modify;
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
@@ -248,17 +248,17 @@ struct ARM7TDMI {
|
||||
b1 irq;
|
||||
b1 nonsequential;
|
||||
|
||||
function<void (n32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
std::function<void (n32 opcode)> armInstruction[4096];
|
||||
std::function<void ()> thumbInstruction[65536];
|
||||
|
||||
//coprocessor.cpp
|
||||
auto bindCDP(n4 id, function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void;
|
||||
auto bindMCR(n4 id, function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
auto bindMRC(n4 id, function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
auto bindCDP(n4 id, std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void;
|
||||
auto bindMCR(n4 id, std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
auto bindMRC(n4 id, std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
|
||||
|
||||
function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> CDP[16];
|
||||
function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> MCR[16];
|
||||
function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> MRC[16];
|
||||
std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> CDP[16];
|
||||
std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> MCR[16];
|
||||
std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> MRC[16];
|
||||
|
||||
//disassembler.cpp
|
||||
auto armDisassembleBranch(i24, n1) -> string;
|
||||
@@ -310,8 +310,8 @@ struct ARM7TDMI {
|
||||
auto thumbDisassembleStackMultiple(n8, n1, n1) -> string;
|
||||
auto thumbDisassembleUndefined() -> string;
|
||||
|
||||
function<string (n32 opcode)> armDisassemble[4096];
|
||||
function<string ()> thumbDisassemble[65536];
|
||||
std::function<string (n32 opcode)> armDisassemble[4096];
|
||||
std::function<string ()> thumbDisassemble[65536];
|
||||
|
||||
n32 _pc;
|
||||
string _c;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
auto ARM7TDMI::bindCDP(n4 id, function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void {
|
||||
auto ARM7TDMI::bindCDP(n4 id, std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void {
|
||||
CDP[id] = handler;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::bindMCR(n4 id, function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
auto ARM7TDMI::bindMCR(n4 id, std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
MCR[id] = handler;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::bindMRC(n4 id, function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
auto ARM7TDMI::bindMRC(n4 id, std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
|
||||
MRC[id] = handler;
|
||||
}
|
||||
@@ -442,8 +442,8 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||
auto ARM7TDMI::thumbInitialize() -> void {
|
||||
#define bind(id, name, ...) { \
|
||||
assert(!thumbInstruction[id]); \
|
||||
thumbInstruction[id] = [=] { return thumbInstruction##name(__VA_ARGS__); }; \
|
||||
thumbDisassemble[id] = [=] { return thumbDisassemble##name(__VA_ARGS__); }; \
|
||||
thumbInstruction[id] = [=, this] { return thumbInstruction##name(__VA_ARGS__); }; \
|
||||
thumbDisassemble[id] = [=, this] { return thumbDisassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
|
||||
@@ -104,12 +104,12 @@ auto ARM7TDMI::armInstructionDataRegisterShift
|
||||
|
||||
auto ARM7TDMI::armInstructionMemorySwap
|
||||
(n4 m, n4 d, n4 n, n1 byte) -> void {
|
||||
n32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||
lock();
|
||||
n32 word = load((byte ? Byte : Word), r(n));
|
||||
store((byte ? Byte : Word), r(n), rm);
|
||||
r(d) = word;
|
||||
store((byte ? Byte : Word), r(n), r(m) + (m == 15 ? 4 : 0));
|
||||
unlock();
|
||||
idle();
|
||||
r(d) = word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
@@ -123,7 +123,10 @@ auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
@@ -138,7 +141,10 @@ auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
@@ -152,7 +158,10 @@ auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveMultiple
|
||||
@@ -219,7 +228,10 @@ auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveSignedImmediate
|
||||
@@ -233,7 +245,10 @@ auto ARM7TDMI::armInstructionMoveSignedImmediate
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveSignedRegister
|
||||
@@ -248,7 +263,10 @@ auto ARM7TDMI::armInstructionMoveSignedRegister
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
|
||||
if(mode == 1) r(d) = rd;
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(d) = rd;
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToCoprocessorFromRegister
|
||||
|
||||
@@ -106,13 +106,14 @@ auto ARM7TDMI::thumbInstructionLoadLiteral
|
||||
(n8 displacement, n3 d) -> void {
|
||||
n32 address = (r(15) & ~3) + (displacement << 2);
|
||||
r(d) = load(Word, address);
|
||||
idle();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveByteImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Byte, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte, r(n) + offset); break; //LDRB
|
||||
case 1: r(d) = load(Byte, r(n) + offset); idle(); break; //LDRB
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@ auto ARM7TDMI::thumbInstructionMoveHalfImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Half, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half, r(n) + offset * 2); break; //LDRH
|
||||
case 1: r(d) = load(Half, r(n) + offset * 2); idle(); break; //LDRH
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,11 +159,11 @@ auto ARM7TDMI::thumbInstructionMoveRegisterOffset
|
||||
case 0: store(Word, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Signed, r(n) + r(m)); break; //LDSB
|
||||
case 4: r(d) = load(Word, r(n) + r(m)); break; //LDR
|
||||
case 5: r(d) = load(Half, r(n) + r(m)); break; //LDRH
|
||||
case 6: r(d) = load(Byte, r(n) + r(m)); break; //LDRB
|
||||
case 7: r(d) = load(Half | Signed, r(n) + r(m)); break; //LDSH
|
||||
case 3: r(d) = load(Byte | Signed, r(n) + r(m)); idle(); break; //LDSB
|
||||
case 4: r(d) = load(Word, r(n) + r(m)); idle(); break; //LDR
|
||||
case 5: r(d) = load(Half, r(n) + r(m)); idle(); break; //LDRH
|
||||
case 6: r(d) = load(Byte, r(n) + r(m)); idle(); break; //LDRB
|
||||
case 7: r(d) = load(Half | Signed, r(n) + r(m)); idle(); break; //LDSH
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +171,7 @@ auto ARM7TDMI::thumbInstructionMoveStack
|
||||
(n8 immediate, n3 d, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(13) + immediate * 4); break; //LDR
|
||||
case 1: r(d) = load(Word, r(13) + immediate * 4); idle(); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +179,7 @@ auto ARM7TDMI::thumbInstructionMoveWordImmediate
|
||||
(n3 d, n3 n, n5 offset, n1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word, r(n) + offset * 4); break; //LDR
|
||||
case 1: r(d) = load(Word, r(n) + offset * 4); idle(); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
|
||||
} else {
|
||||
word = ROR(word, address.bit(0,1) << 3);
|
||||
}
|
||||
idle();
|
||||
return word;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,8 +180,8 @@ protected:
|
||||
} io;
|
||||
|
||||
n23 stack[8];
|
||||
function<void ()> instructionTable[65536];
|
||||
function<string ()> disassembleTable[65536];
|
||||
std::function<void ()> instructionTable[65536];
|
||||
std::function<string ()> disassembleTable[65536];
|
||||
|
||||
auto disassembleADD(n7 reg, n5 shift) -> string;
|
||||
auto disassembleADD(n8 imm, n5 shift) -> string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
HG51B::HG51B() {
|
||||
#define bind(id, name, ...) { \
|
||||
if(instructionTable[id]) throw; \
|
||||
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
||||
instructionTable[id] = [=, this] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=, this] { return disassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
|
||||
@@ -163,7 +163,7 @@ auto HuC6280::disassembleInstruction() -> string {
|
||||
|
||||
n8 opcode = readByte();
|
||||
|
||||
#define op(id, name, ...) case id: o = {name, " ", vector<string>{__VA_ARGS__}.merge(",")}; break;
|
||||
#define op(id, name, ...) case id: o = {name, " ", nall::merge({__VA_ARGS__}, ",")}; break;
|
||||
string o;
|
||||
|
||||
#define U
|
||||
|
||||
@@ -41,7 +41,7 @@ auto I8080::disassembleContext() -> string {
|
||||
return s;
|
||||
}
|
||||
|
||||
#define op(id, name, ...) case id: return {name, " ", vector<string>{__VA_ARGS__}.merge(",")};
|
||||
#define op(id, name, ...) case id: return {name, " ", nall::merge({__VA_ARGS__}, ",")};
|
||||
|
||||
#define N string{"$", hex(byte(), 2L)}
|
||||
#define IN string{"(", N, ")"}
|
||||
|
||||
@@ -10,13 +10,13 @@ auto M68000::instruction() -> void {
|
||||
M68000::M68000() {
|
||||
#define bind(id, name, ...) { \
|
||||
assert(!instructionTable[id]); \
|
||||
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
||||
instructionTable[id] = [=, this] { return instruction##name(__VA_ARGS__); }; \
|
||||
disassembleTable[id] = [=, this] { return disassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define unbind(id) { \
|
||||
instructionTable[id].reset(); \
|
||||
disassembleTable[id].reset(); \
|
||||
instructionTable[id] = {}; \
|
||||
disassembleTable[id] = {}; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
|
||||
@@ -752,7 +752,12 @@ template<u32 Size> auto M68000::instructionMOVEM_TO_MEM(EffectiveAddress to) ->
|
||||
|
||||
if(to.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes<Size>();
|
||||
auto data = index < 8 ? read<Size>(DataRegister{index}) : read<Size>(AddressRegister{index});
|
||||
write<Size>(addr, data);
|
||||
if(to.mode == AddressRegisterIndirectWithPreDecrement) {
|
||||
//pre-decrement mode writes longwords in reverse-word order (low word before high)
|
||||
write<Size, Reverse>(addr, data);
|
||||
} else {
|
||||
write<Size>(addr, data);
|
||||
}
|
||||
if(to.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes<Size>();
|
||||
}
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ struct M68000 {
|
||||
bool reset;
|
||||
} r;
|
||||
|
||||
function<void ()> instructionTable[65536];
|
||||
std::function<void ()> instructionTable[65536];
|
||||
|
||||
private:
|
||||
//disassembler.cpp
|
||||
@@ -434,7 +434,7 @@ private:
|
||||
auto _condition(n4 condition) -> string;
|
||||
|
||||
n32 _pc;
|
||||
function<string ()> disassembleTable[65536];
|
||||
std::function<string ()> disassembleTable[65536];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,8 +6,8 @@ auto MOS6502::addressAbsolute() -> n16 {
|
||||
|
||||
auto MOS6502::addressAbsoluteJMP() -> n16 {
|
||||
n16 absolute = operand();
|
||||
// JMP Indirect last_cycle
|
||||
L absolute |= operand() << 8;
|
||||
// JMP Indirect last cycle
|
||||
L absolute |= operand() << 8;
|
||||
return absolute;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,6 @@ auto MOS6502::addressAbsoluteYWrite() -> n16 {
|
||||
return absolute + Y;
|
||||
}
|
||||
|
||||
auto MOS6502::addressAccumulator() -> n16 {
|
||||
return PC;
|
||||
}
|
||||
|
||||
auto MOS6502::addressImmediate() -> n16 {
|
||||
return PC++;
|
||||
}
|
||||
@@ -56,8 +52,8 @@ auto MOS6502::addressIndirect() -> n16 {
|
||||
absolute |= operand() << 8;
|
||||
n16 indirect = read(absolute);
|
||||
absolute.byte(0)++;
|
||||
// JMP Indirect last_cycle
|
||||
L indirect |= read(absolute) << 8;
|
||||
// JMP Indirect last cycle
|
||||
L indirect |= read(absolute) << 8;
|
||||
return indirect;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,10 +210,12 @@ auto MOS6502::algorithmJMP() -> void {
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmJSR() -> void {
|
||||
PC--;
|
||||
n16 target = operand();
|
||||
MDR = read(0x0100 | S); // dummy stack read
|
||||
push(PCH);
|
||||
L push(PCL);
|
||||
PC = MAR;
|
||||
push(PCL);
|
||||
L target |= operand() << 8;
|
||||
PC = target;
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmLDA() -> void {
|
||||
@@ -257,8 +259,8 @@ auto MOS6502::algorithmORA() -> void {
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmPHA() -> void {
|
||||
read(MAR); // dummy implied read
|
||||
L push(A);
|
||||
read(MAR); // dummy implied read
|
||||
L push(A);
|
||||
}
|
||||
|
||||
auto MOS6502::algorithmPHP() -> void {
|
||||
|
||||
@@ -24,7 +24,7 @@ auto MOS6502::reset() -> void {
|
||||
read(0x0100 | S--); // Dummy push (P)
|
||||
I = 1;
|
||||
PCL = read(vector++);
|
||||
L PCH = read(vector++);
|
||||
L PCH = read(vector++);
|
||||
resetting = 0;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x07, Modify, addr(ZeroPage), fp(SLO))
|
||||
op(0x08, None, addr(Implied), fp(PHP))
|
||||
op(0x09, Load, addr(Immediate), fp(ORA))
|
||||
op(0x0a, Load, addr(Accumulator), fp(ASLA))
|
||||
op(0x0a, Load, addr(Implied), fp(ASLA))
|
||||
op(0x0b, Load, addr(Immediate), fp(AAC))
|
||||
op(0x0c, Load, addr(Absolute), fp(NOP))
|
||||
op(0x0d, Load, addr(Absolute), fp(ORA))
|
||||
@@ -64,7 +64,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x1d, Load, addr(AbsoluteXRead), fp(ORA))
|
||||
op(0x1e, Modify, addr(AbsoluteXWrite), fp(ASLM))
|
||||
op(0x1f, Modify, addr(AbsoluteXWrite), fp(SLO))
|
||||
op(0x20, Load, addr(Absolute), fp(JSR))
|
||||
op(0x20, None, addr(Implied), fp(JSR))
|
||||
op(0x21, Load, addr(IndirectX), fp(AND))
|
||||
op(0x22, None, addr(Implied), fp(JAM))
|
||||
op(0x23, Modify, addr(IndirectX), fp(RLA))
|
||||
|
||||
@@ -40,7 +40,6 @@ struct MOS6502 {
|
||||
auto addressAbsoluteXWrite() -> n16;
|
||||
auto addressAbsoluteYRead() -> n16;
|
||||
auto addressAbsoluteYWrite() -> n16;
|
||||
auto addressAccumulator() -> n16;
|
||||
auto addressImmediate() -> n16;
|
||||
auto addressImplied() -> n16;
|
||||
auto addressIndirect() -> n16;
|
||||
|
||||
@@ -6,7 +6,7 @@ auto SH2::hint(P&&... p) const -> string {
|
||||
}
|
||||
|
||||
auto SH2::disassembleInstruction(u16 opcode) -> string {
|
||||
vector<string> s;
|
||||
std::vector<string> s;
|
||||
|
||||
auto registerName = [&](u32 r) -> string {
|
||||
return {"r", r};
|
||||
@@ -512,10 +512,10 @@ auto SH2::disassembleInstruction(u16 opcode) -> string {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!s) s = {"illegal", {"0x", hex(opcode, 4L)}};
|
||||
auto name = s.takeFirst();
|
||||
if(s.empty()) s = {"illegal", {"0x", hex(opcode, 4L)}};
|
||||
auto name = s.front(); s.erase(s.begin());
|
||||
while(name.size() < 8) name.append(" ");
|
||||
string r = {name, s.merge(",")};
|
||||
string r = {name, nall::merge(s, ",")};
|
||||
while(r.size() < 30) r.append(" ");
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BRA disp
|
||||
case range16(0xa0, 0xaf): {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(PPC, PC, imm(4 + (i12)d12 * 2));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
});
|
||||
@@ -714,7 +714,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BSR disp
|
||||
case range16(0xb0, 0xbf): {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(reg(0), PC);
|
||||
mov32(PR, reg(0));
|
||||
add32(reg(0), reg(0), imm(4 + (i12)d12 * 2));
|
||||
@@ -807,7 +807,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BT disp
|
||||
case 0x89: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_eq);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Take));
|
||||
@@ -818,7 +818,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BF disp
|
||||
case 0x8b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_ne);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Take));
|
||||
@@ -829,7 +829,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BT/S disp
|
||||
case 0x8d: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_eq);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
@@ -840,7 +840,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BF/S disp
|
||||
case 0x8f: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
auto skip = cmp32_jump(T, imm(0), flag_ne);
|
||||
add32(PPC, PC, imm(4 + (s8)d8 * 2));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
@@ -875,7 +875,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//TRAPA #imm
|
||||
case 0xc3: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
getSR(reg(2));
|
||||
sub32(reg(1), R15, imm(4));
|
||||
mov32(R15, reg(1));
|
||||
@@ -1022,7 +1022,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BSRF Rm
|
||||
case 0x003: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(reg(0), PC);
|
||||
mov32(PR, reg(0));
|
||||
add32(reg(0), reg(0), Rm);
|
||||
@@ -1059,7 +1059,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//BRAF Rm
|
||||
case 0x023: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(reg(0), PC, Rm);
|
||||
add32(reg(0), reg(0), imm(4));
|
||||
mov32(PPC, reg(0));
|
||||
@@ -1168,7 +1168,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//JSR @Rm
|
||||
case 0x40b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(PR, PC);
|
||||
add32(PPC, Rm, imm(4));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
@@ -1370,7 +1370,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//JMP @Rm
|
||||
case 0x42b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(PPC, Rm, imm(4));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
});
|
||||
@@ -1405,7 +1405,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//RTS
|
||||
case 0x000b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
add32(PPC, PR, imm(4));
|
||||
mov32(PPM, imm(Branch::Slot));
|
||||
});
|
||||
@@ -1447,7 +1447,7 @@ auto SH2::Recompiler::emitInstruction(u16 opcode) -> u32 {
|
||||
|
||||
//RTE
|
||||
case 0x002b: {
|
||||
checkDelaySlot([=] {
|
||||
checkDelaySlot([=, this] {
|
||||
mov32(reg(1), R15);
|
||||
add32(R15, reg(1), imm(4));
|
||||
call(readL);
|
||||
|
||||
@@ -283,8 +283,8 @@ struct SH2 {
|
||||
auto reset() -> void {
|
||||
generation = 0;
|
||||
blocks.reset();
|
||||
pools.reallocate(1 << 24);
|
||||
pools.fill();
|
||||
pools.resize(1 << 24);
|
||||
std::ranges::fill(pools, nullptr);
|
||||
}
|
||||
|
||||
auto invalidateCached() -> void {
|
||||
@@ -312,7 +312,7 @@ struct SH2 {
|
||||
bump_allocator allocator;
|
||||
hashset<BlockHashPair> blocks;
|
||||
u16 instructions[1 << 7];
|
||||
vector<Pool*> pools;
|
||||
std::vector<Pool*> pools;
|
||||
} recompiler{*this};
|
||||
|
||||
#include "sh7604/sh7604.hpp"
|
||||
|
||||
@@ -17,7 +17,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
return offset;
|
||||
};
|
||||
|
||||
auto instruction = [&](string_view name) -> string {
|
||||
auto instruction = [&](string name) -> string {
|
||||
if(name.size() >= 7) return name;
|
||||
return pad(name, -7);
|
||||
};
|
||||
@@ -150,7 +150,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
|
||||
};
|
||||
|
||||
#define op(id, name, ...) case id: \
|
||||
output.append(instruction(name), vector<string>{__VA_ARGS__}.merge(",")); \
|
||||
output.append(instruction(name), nall::merge({__VA_ARGS__}, ",")); \
|
||||
break
|
||||
|
||||
auto opcode = read(0);
|
||||
|
||||
@@ -56,7 +56,7 @@ auto Z80::disassembleContext() -> string {
|
||||
return s;
|
||||
}
|
||||
|
||||
#define op(id, name, ...) case id: return {name, " ", vector<string>{__VA_ARGS__}.merge(",")};
|
||||
#define op(id, name, ...) case id: return {name, " ", nall::merge({__VA_ARGS__}, ",")};
|
||||
|
||||
#define N string{"$", hex(byte(), 2L)}
|
||||
#define IN string{"(", N, ")"}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
auto S3511A::serialize(serializer& s) -> void {
|
||||
s(array_span<u8>{data, size});
|
||||
s(std::span<n8>{data, size});
|
||||
|
||||
s(cs);
|
||||
s(sio);
|
||||
|
||||
@@ -27,11 +27,11 @@ auto TMS9918::main() -> void {
|
||||
background.run(x, y);
|
||||
sprite.run(x, y);
|
||||
dac.run(x, y);
|
||||
step(1);
|
||||
step(2);
|
||||
}
|
||||
step(200);
|
||||
step(172);
|
||||
} else {
|
||||
step(456);
|
||||
step(684);
|
||||
}
|
||||
|
||||
io.vcounter++;
|
||||
|
||||
@@ -34,9 +34,9 @@ auto V9938::main() -> void {
|
||||
tick(1);
|
||||
}
|
||||
|
||||
tick(200);
|
||||
tick(86);
|
||||
} else {
|
||||
tick(456);
|
||||
tick(342);
|
||||
}
|
||||
|
||||
io.hcounter = 0;
|
||||
@@ -71,7 +71,7 @@ auto V9938::tick(u32 clocks) -> void {
|
||||
io.hcounter += clocks;
|
||||
while(clocks--) {
|
||||
command();
|
||||
step(1);
|
||||
step(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ auto Cartridge::connect() -> void {
|
||||
information.region = pak->attribute("region");
|
||||
information.board = pak->attribute("board");
|
||||
|
||||
if(information.board == "xin1") board = new Board::xin1{*this};
|
||||
if(information.board == "coleco") board = new Board::coleco{*this};
|
||||
if(information.board == "megacart") board = new Board::megacart{*this};
|
||||
if(information.board == "xin1") board = std::make_unique<Board::xin1>(*this);
|
||||
if(information.board == "coleco") board = std::make_unique<Board::coleco>(*this);
|
||||
if(information.board == "megacart") board = std::make_unique<Board::megacart>(*this);
|
||||
|
||||
|
||||
if(!board) board = new Board::Interface{*this};
|
||||
if(!board) board = std::make_unique<Board::Interface>(*this);
|
||||
board->pak = pak;
|
||||
board->load();
|
||||
power();
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Cartridge {
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
unique_pointer<Board::Interface> board;
|
||||
std::unique_ptr<Board::Interface> board;
|
||||
|
||||
//private:
|
||||
struct Information {
|
||||
|
||||
@@ -20,7 +20,7 @@ auto ControllerPort::unload() -> void {
|
||||
}
|
||||
|
||||
auto ControllerPort::allocate(string name) -> Node::Peripheral {
|
||||
if(name == "Gamepad") device = new Gamepad(port);
|
||||
if(name == "Gamepad") device = std::make_unique<Gamepad>(port);
|
||||
if(device) return device->node;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
struct ControllerPort {
|
||||
Node::Port port;
|
||||
unique_pointer<Controller> device;
|
||||
std::unique_ptr<Controller> device;
|
||||
|
||||
//port.cpp
|
||||
ControllerPort(string name);
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ auto CPU::setIRQ(bool value) -> void {
|
||||
auto CPU::power() -> void {
|
||||
Z80::bus = this;
|
||||
Z80::power();
|
||||
Thread::create(system.colorburst(), {&CPU::main, this});
|
||||
Thread::create(system.colorburst(), std::bind_front(&CPU::main, this));
|
||||
|
||||
PC = 0x0000; //reset vector address
|
||||
state = {};
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@
|
||||
//started: 2019-02-19
|
||||
|
||||
#include <ares/ares.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include <component/processor/z80/z80.hpp>
|
||||
#include <component/video/tms9918/tms9918.hpp>
|
||||
@@ -9,7 +10,7 @@
|
||||
|
||||
namespace ares::ColecoVision {
|
||||
#include <ares/inline.hpp>
|
||||
auto enumerate() -> vector<string>;
|
||||
auto enumerate() -> std::vector<string>;
|
||||
auto load(Node::System& node, string name) -> bool;
|
||||
|
||||
struct Model {
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ auto PSG::step(u32 clocks) -> void {
|
||||
|
||||
auto PSG::power() -> void {
|
||||
SN76489::power();
|
||||
Thread::create(system.colorburst() / 16.0, {&PSG::main, this});
|
||||
Thread::create(system.colorburst() / 16.0, std::bind_front(&PSG::main, this));
|
||||
|
||||
for(u32 level : range(15)) {
|
||||
volume[level] = pow(2, level * -2.0 / 6.0);
|
||||
|
||||
+13
-11
@@ -1,8 +1,9 @@
|
||||
#include <cv/cv.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ares::ColecoVision {
|
||||
|
||||
auto enumerate() -> vector<string> {
|
||||
auto enumerate() -> std::vector<string> {
|
||||
return {
|
||||
"[Coleco] ColecoVision (NTSC)",
|
||||
"[Coleco] ColecoVision (PAL)",
|
||||
@@ -12,7 +13,8 @@ auto enumerate() -> vector<string> {
|
||||
}
|
||||
|
||||
auto load(Node::System& node, string name) -> bool {
|
||||
if(!enumerate().find(name)) return false;
|
||||
auto list = enumerate();
|
||||
if(std::find(list.begin(), list.end(), name) == list.end()) return false;
|
||||
return system.load(node, name);
|
||||
}
|
||||
|
||||
@@ -55,20 +57,20 @@ auto System::load(Node::System& root, string name) -> bool {
|
||||
information.colorburst = Constants::Colorburst::PAL * 4.0 / 5.0;
|
||||
}
|
||||
|
||||
node = Node::System::create(information.name);
|
||||
node = std::make_shared<Core::System>(information.name);
|
||||
node->setAttribute("configuration", name);
|
||||
node->setGame({&System::game, this});
|
||||
node->setRun({&System::run, this});
|
||||
node->setPower({&System::power, this});
|
||||
node->setSave({&System::save, this});
|
||||
node->setUnload({&System::unload, this});
|
||||
node->setSerialize({&System::serialize, this});
|
||||
node->setUnserialize({&System::unserialize, this});
|
||||
node->setGame(std::bind_front(&System::game, this));
|
||||
node->setRun(std::bind_front(&System::run, this));
|
||||
node->setPower(std::bind_front(&System::power, this));
|
||||
node->setSave(std::bind_front(&System::save, this));
|
||||
node->setUnload(std::bind_front(&System::unload, this));
|
||||
node->setSerialize([this](bool save) -> serializer { return serialize(save); });
|
||||
node->setUnserialize(std::bind_front(&System::unserialize, this));
|
||||
root = node;
|
||||
if(!node->setPak(pak = platform->pak(node))) return false;
|
||||
|
||||
if(auto fp = pak->read("bios.rom")) {
|
||||
fp->read({bios, 0x2000});
|
||||
fp->read(bios, 0x2000);
|
||||
}
|
||||
|
||||
scheduler.reset();
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ auto VDP::load(Node::Object parent) -> void {
|
||||
node = parent->append<Node::Object>("VDP");
|
||||
|
||||
screen = node->append<Node::Video::Screen>("Screen", 284, 243);
|
||||
screen->colors(1 << 4, {&VDP::color, this});
|
||||
screen->colors(1 << 4, std::bind_front(&VDP::color, this));
|
||||
screen->setSize(284, 243);
|
||||
screen->setScale(1.0, 1.0);
|
||||
screen->setAspect(8.0, 7.0);
|
||||
@@ -59,7 +59,7 @@ auto VDP::frame() -> void {
|
||||
|
||||
auto VDP::power() -> void {
|
||||
TMS9918::power();
|
||||
Thread::create(system.colorburst() * 2, [&] { main(); });
|
||||
Thread::create(system.colorburst() * 3, [&] { main(); });
|
||||
screen->power();
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -73,11 +73,11 @@ auto APU::tick() -> void {
|
||||
}
|
||||
|
||||
auto APU::setIRQ() -> void {
|
||||
cpu.apuLine(frame.irqPending | dmc.irqPending);
|
||||
cpu.apuLine((frame.irqPending & ~frame.irqInhibit) | dmc.irqPending);
|
||||
}
|
||||
|
||||
auto APU::power(bool reset) -> void {
|
||||
Thread::create(system.frequency(), {&APU::main, this});
|
||||
Thread::create(system.frequency(), std::bind_front(&APU::main, this));
|
||||
|
||||
pulse1.power(reset);
|
||||
pulse2.power(reset);
|
||||
@@ -100,11 +100,10 @@ auto APU::readIO(n16 address) -> n8 {
|
||||
data.bit(2) = (bool)triangle.length.counter;
|
||||
data.bit(3) = (bool)noise.length.counter;
|
||||
data.bit(4) = (bool)dmc.lengthCounter;
|
||||
data.bit(5) = 0;
|
||||
//bit 5 is open bus
|
||||
data.bit(6) = frame.irqPending;
|
||||
data.bit(7) = dmc.irqPending;
|
||||
frame.irqPending = false;
|
||||
setIRQ();
|
||||
frame.delayIRQ = true;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -199,8 +199,8 @@ struct APU : Thread {
|
||||
n16 counter;
|
||||
|
||||
bool odd;
|
||||
bool delay;
|
||||
n3 delayCounter;
|
||||
bool delayIRQ;
|
||||
bool delayCounter[2];
|
||||
|
||||
constexpr static u16 periodNTSC[2][6] = {
|
||||
{ 7457, 7456, 7458, 7457, 1, 1, },
|
||||
|
||||
@@ -2,17 +2,25 @@ auto APU::FrameCounter::main() -> void {
|
||||
--counter;
|
||||
odd = !odd;
|
||||
|
||||
if (delay && --delayCounter == 0) {
|
||||
delay = false;
|
||||
step = 0;
|
||||
counter = getPeriod() + 2;
|
||||
if (mode == Freq48Hz) {
|
||||
apu.clockHalfFrame();
|
||||
if(!odd) {
|
||||
//IRQ is reset on next GET cycle
|
||||
if(delayIRQ) {
|
||||
delayIRQ = false;
|
||||
irqPending = 0;
|
||||
apu.setIRQ();
|
||||
}
|
||||
|
||||
//counter is reloaded on GET cycle after next
|
||||
if(delayCounter[0]) {
|
||||
step = 0;
|
||||
counter = getPeriod();
|
||||
if(mode == Freq48Hz) apu.clockHalfFrame();
|
||||
}
|
||||
delayCounter[0] = delayCounter[1];
|
||||
delayCounter[1] = false;
|
||||
}
|
||||
|
||||
if (counter != 0)
|
||||
return;
|
||||
if(counter != 0) return;
|
||||
|
||||
switch(step) {
|
||||
case 0:
|
||||
@@ -29,21 +37,22 @@ auto APU::FrameCounter::main() -> void {
|
||||
break;
|
||||
case 3:
|
||||
step = 4;
|
||||
if (mode == Freq60Hz && irqInhibit == 0)
|
||||
irqPending = 1;
|
||||
if(mode == Freq60Hz) irqPending = 1;
|
||||
break;
|
||||
case 4:
|
||||
step = 5;
|
||||
apu.clockHalfFrame();
|
||||
if (mode == Freq60Hz && irqInhibit == 0) {
|
||||
if(mode == Freq60Hz) {
|
||||
irqPending = 1;
|
||||
apu.setIRQ();
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
step = 0;
|
||||
if (mode == Freq60Hz && irqInhibit == 0)
|
||||
irqPending = 1;
|
||||
if(mode == Freq60Hz) {
|
||||
irqPending = ~irqInhibit;
|
||||
apu.setIRQ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -52,30 +61,24 @@ auto APU::FrameCounter::main() -> void {
|
||||
|
||||
auto APU::FrameCounter::power(bool reset) -> void {
|
||||
irqInhibit = 0;
|
||||
if (!reset) mode = Freq60Hz;
|
||||
if(!reset) mode = Freq60Hz;
|
||||
|
||||
irqPending = 0;
|
||||
step = 0;
|
||||
counter = getPeriod();
|
||||
|
||||
odd = true;
|
||||
delay = false;
|
||||
delayCounter = 0;
|
||||
delayIRQ = false;
|
||||
delayCounter[0] = false;
|
||||
delayCounter[1] = false;
|
||||
}
|
||||
|
||||
auto APU::FrameCounter::write(n8 data) -> void {
|
||||
mode = data.bit(7);
|
||||
delay = true;
|
||||
|
||||
// If the write occurs during an APU cycle,
|
||||
// the effects occur 3 CPU cycles after the
|
||||
// $4017 write cycle, and if the write occurs
|
||||
// between APU cycles, the effects occurs 4 CPU
|
||||
// cycles after the write cycle.
|
||||
delayCounter = odd ? 1 : 2;
|
||||
delayCounter[1] = true;
|
||||
|
||||
irqInhibit = data.bit(6);
|
||||
if (irqInhibit) {
|
||||
if(irqInhibit) {
|
||||
irqPending = 0;
|
||||
apu.setIRQ();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ auto APU::serialize(serializer& s) -> void {
|
||||
s(pulse1);
|
||||
s(pulse2);
|
||||
s(triangle);
|
||||
s(noise);
|
||||
s(dmc);
|
||||
s(frame);
|
||||
}
|
||||
@@ -95,6 +96,6 @@ auto APU::FrameCounter::serialize(serializer& s) -> void {
|
||||
s(counter);
|
||||
|
||||
s(odd);
|
||||
s(delay);
|
||||
s(delayCounter);
|
||||
s(delayIRQ);
|
||||
for(auto& delay : delayCounter) s(delay);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ struct BandaiLZ93D50 : Interface {
|
||||
if(auto fp = pak->read("save.eeprom")) {
|
||||
if(fp->size() == 128) eeprom.load(M24C::Type::X24C01);
|
||||
if(fp->size() == 256) eeprom.load(M24C::Type::M24C02);
|
||||
if(eeprom) fp->read({eeprom.memory, eeprom.size()});
|
||||
if(eeprom) fp->read(eeprom.memory, eeprom.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ struct BandaiLZ93D50 : Interface {
|
||||
Interface::save(programRAM, "save.ram");
|
||||
Interface::save(characterRAM, "character.ram");
|
||||
if(auto fp = pak->write("save.eeprom")) {
|
||||
if(eeprom) fp->write({eeprom.memory, eeprom.size()});
|
||||
if(eeprom) fp->write(eeprom.memory, eeprom.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ auto Cartridge::connect() -> void {
|
||||
information.title = pak->attribute("title");
|
||||
information.region = pak->attribute("region");
|
||||
|
||||
board = Board::Interface::create(pak->attribute("board"));
|
||||
board.reset(Board::Interface::create(pak->attribute("board")));
|
||||
board->pak = pak;
|
||||
board->load();
|
||||
|
||||
@@ -47,7 +47,7 @@ auto Cartridge::save() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::power() -> void {
|
||||
Thread::create(system.frequency(), {&Cartridge::main, this});
|
||||
Thread::create(system.frequency(), std::bind_front(&Cartridge::main, this));
|
||||
board->power();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ struct Cartridge : Thread {
|
||||
} information;
|
||||
|
||||
//privileged:
|
||||
unique_pointer<Board::Interface> board;
|
||||
std::unique_ptr<Board::Interface> board;
|
||||
|
||||
auto readPRG(n32 address, n8 data) -> n8;
|
||||
auto writePRG(n32 address, n8 data) -> void;
|
||||
|
||||
Loaded 100 of 1011 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user