Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 466788c006 | |||
| 19e2dba35a | |||
| 0634b4a278 | |||
| ee428deb1e | |||
| 07bc77c7e7 | |||
| 72973fe582 | |||
| c263b6af6f | |||
| e46576b4c3 | |||
| 89bcb73d47 | |||
| 7d81a724ef | |||
| 634686d59b | |||
| d0af14632e | |||
| c87986b276 | |||
| b600b90d53 | |||
| 2b979024cb | |||
| 5f676a6a55 | |||
| 2ab5b37137 | |||
| f6547fac8c | |||
| 9c685c1449 | |||
| aaf1a597ef | |||
| 850fc372b7 | |||
| bad9d8043b | |||
| 8e8e66f880 | |||
| fec5ac2298 |
@@ -84,7 +84,11 @@ function(SystemPackageViable JSON_NAME)
|
|||||||
parse_object(${object})
|
parse_object(${object})
|
||||||
|
|
||||||
string(REPLACE " " ";" find_args "${find_args}")
|
string(REPLACE " " ";" find_args "${find_args}")
|
||||||
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
|
if (${package}_FORCE_BUNDLED)
|
||||||
|
set(${package}_FOUND OFF)
|
||||||
|
else()
|
||||||
|
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
|
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
|
||||||
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
|
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
|
||||||
|
|||||||
@@ -6,225 +6,206 @@
|
|||||||
viewBox="0 0 512 512"
|
viewBox="0 0 512 512"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg7"
|
id="svg7"
|
||||||
sodipodi:docname="base.svg.2026_01_12_14_43_47.0.svg"
|
sodipodi:docname="EdenLogoLoveWhiteV3.svg"
|
||||||
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
|
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
|
||||||
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
|
xml:space="preserve"
|
||||||
|
inkscape:export-filename="dev.eden_emu.eden.png"
|
||||||
inkscape:export-xdpi="96"
|
inkscape:export-xdpi="96"
|
||||||
inkscape:export-ydpi="96"
|
inkscape:export-ydpi="96"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<metadata
|
||||||
|
id="metadata1">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>Madeline_Dev</dc:title>
|
||||||
|
<dc:identifier>mailto:madelvidel@gmail.com</dc:identifier>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
<dc:date>2025</dc:date>
|
||||||
|
<dc:license
|
||||||
|
rdf:resource="https://www.gnu.org/licenses/gpl-3.0.html" />
|
||||||
|
<dc:rights>2025 Eden Emulator Project</dc:rights>
|
||||||
|
<dc:source>https://git.eden-emu.dev</dc:source>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
<defs
|
<defs
|
||||||
id="defs7">
|
id="defs7"><linearGradient
|
||||||
<linearGradient
|
id="swatch14"
|
||||||
id="linearGradient1"
|
inkscape:swatch="solid"><stop
|
||||||
inkscape:collect="always">
|
style="stop-color:#66003b;stop-opacity:1;"
|
||||||
<stop
|
offset="0"
|
||||||
style="stop-color:#ff2e88;stop-opacity:0.5;"
|
id="stop14" /></linearGradient><linearGradient
|
||||||
offset="0"
|
id="linearGradient1"
|
||||||
id="stop3" />
|
inkscape:collect="always"><stop
|
||||||
<stop
|
style="stop-color:#ffffff;stop-opacity:0.50980395;"
|
||||||
style="stop-color:#bf42f6;stop-opacity:0.5;"
|
offset="0"
|
||||||
offset="0.44631511"
|
id="stop1" /><stop
|
||||||
id="stop4" />
|
style="stop-color:#000000;stop-opacity:0;"
|
||||||
<stop
|
offset="1"
|
||||||
style="stop-color:#5da5ed;stop-opacity:0.5;"
|
id="stop2" /></linearGradient><linearGradient
|
||||||
offset="0.90088946"
|
id="linearGradient11"
|
||||||
id="stop2" />
|
inkscape:collect="always"><stop
|
||||||
</linearGradient>
|
style="stop-color:#9523a7;stop-opacity:0.50980395;"
|
||||||
<linearGradient
|
offset="0"
|
||||||
id="linearGradient138"
|
id="stop11" /><stop
|
||||||
inkscape:collect="always">
|
style="stop-color:#ffabad;stop-opacity:1;"
|
||||||
<stop
|
offset="0.99898213"
|
||||||
style="stop-color:#ff2e88;stop-opacity:1;"
|
id="stop20" /><stop
|
||||||
offset="0"
|
style="stop-color:#ffffff;stop-opacity:0;"
|
||||||
id="stop152" />
|
offset="0.99898213"
|
||||||
<stop
|
id="stop12" /></linearGradient><linearGradient
|
||||||
style="stop-color:#bf42f6;stop-opacity:1;"
|
inkscape:collect="always"
|
||||||
offset="0.44971901"
|
xlink:href="#linearGradient11"
|
||||||
id="stop137" />
|
id="linearGradient12"
|
||||||
<stop
|
x1="109.74531"
|
||||||
style="stop-color:#5da5ed;stop-opacity:1;"
|
y1="106.54533"
|
||||||
offset="0.89793283"
|
x2="431.05463"
|
||||||
id="stop138" />
|
y2="427.85461"
|
||||||
</linearGradient>
|
gradientUnits="userSpaceOnUse"
|
||||||
<linearGradient
|
spreadMethod="reflect"
|
||||||
id="swatch37"
|
gradientTransform="matrix(1.0945321,0,0,1.0945321,-39.661525,-35.159057)" /><linearGradient
|
||||||
inkscape:swatch="solid">
|
inkscape:collect="always"
|
||||||
<stop
|
xlink:href="#linearGradient1"
|
||||||
style="stop-color:#ffffff;stop-opacity:1;"
|
id="linearGradient2"
|
||||||
offset="0"
|
x1="125.40197"
|
||||||
id="stop37" />
|
y1="271.834"
|
||||||
</linearGradient>
|
x2="431.02424"
|
||||||
<linearGradient
|
y2="271.834"
|
||||||
id="swatch28"
|
gradientUnits="userSpaceOnUse"
|
||||||
inkscape:swatch="solid">
|
gradientTransform="matrix(1.0964243,0,0,1.0253208,-40.187969,-20.060025)" /><filter
|
||||||
<stop
|
inkscape:label="Light Contour"
|
||||||
style="stop-color:#252525;stop-opacity:1;"
|
inkscape:menu="Image Paint and Draw"
|
||||||
offset="0"
|
inkscape:menu-tooltip="Uses vertical specular light to draw lines"
|
||||||
id="stop28" />
|
style="color-interpolation-filters:sRGB"
|
||||||
</linearGradient>
|
id="filter11"
|
||||||
<linearGradient
|
x="-0.01907517"
|
||||||
id="swatch27"
|
y="-0.054959154"
|
||||||
inkscape:swatch="solid">
|
width="1.0379885"
|
||||||
<stop
|
height="1.1092314"><feGaussianBlur
|
||||||
style="stop-color:#000000;stop-opacity:1;"
|
in="SourceGraphic"
|
||||||
offset="0"
|
stdDeviation="0.38250006"
|
||||||
id="stop27" />
|
result="result3"
|
||||||
</linearGradient>
|
id="feGaussianBlur9" /><feComponentTransfer
|
||||||
<linearGradient
|
result="result1"
|
||||||
id="swatch15"
|
in="result3"
|
||||||
inkscape:swatch="solid">
|
id="feComponentTransfer9"><feFuncR
|
||||||
<stop
|
type="discrete"
|
||||||
style="stop-color:#ffffff;stop-opacity:1;"
|
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||||
offset="0"
|
id="feFuncR9" /><feFuncG
|
||||||
id="stop16" />
|
type="discrete"
|
||||||
</linearGradient>
|
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||||
<linearGradient
|
id="feFuncG9" /><feFuncB
|
||||||
id="linearGradient14"
|
type="discrete"
|
||||||
inkscape:swatch="gradient">
|
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||||
<stop
|
id="feFuncB9" /></feComponentTransfer><feGaussianBlur
|
||||||
style="stop-color:#ffffff;stop-opacity:1;"
|
result="result5"
|
||||||
offset="0"
|
stdDeviation="0.01"
|
||||||
id="stop14" />
|
id="feGaussianBlur10" /><feBlend
|
||||||
<stop
|
in2="result5"
|
||||||
style="stop-color:#ffffff;stop-opacity:0;"
|
result="result6"
|
||||||
offset="1"
|
mode="lighten"
|
||||||
id="stop15" />
|
in="result5"
|
||||||
</linearGradient>
|
id="feBlend10" /><feColorMatrix
|
||||||
<linearGradient
|
in="result6"
|
||||||
id="swatch9"
|
type="luminanceToAlpha"
|
||||||
inkscape:swatch="solid">
|
result="result2"
|
||||||
<stop
|
id="feColorMatrix10" /><feSpecularLighting
|
||||||
style="stop-color:#ffffff;stop-opacity:1;"
|
surfaceScale="5"
|
||||||
offset="0"
|
result="result9"
|
||||||
id="stop10" />
|
specularExponent="20"
|
||||||
</linearGradient>
|
in="result2"
|
||||||
<linearGradient
|
specularConstant="1"
|
||||||
id="swatch8"
|
id="feSpecularLighting10"><feDistantLight
|
||||||
inkscape:swatch="solid">
|
azimuth="180"
|
||||||
<stop
|
elevation="90"
|
||||||
style="stop-color:#ffffff;stop-opacity:1;"
|
id="feDistantLight10" /></feSpecularLighting><feComposite
|
||||||
offset="0"
|
in2="result6"
|
||||||
id="stop9" />
|
operator="arithmetic"
|
||||||
</linearGradient>
|
in="result9"
|
||||||
<rect
|
k1="0.4"
|
||||||
x="22.627417"
|
k3="0.7"
|
||||||
y="402.76802"
|
result="result3"
|
||||||
width="521.34025"
|
id="feComposite10"
|
||||||
height="248.94868"
|
k2="0"
|
||||||
id="rect24" />
|
k4="0" /><feBlend
|
||||||
<linearGradient
|
in2="result1"
|
||||||
id="linearGradient11"
|
in="result3"
|
||||||
inkscape:collect="always">
|
mode="normal"
|
||||||
<stop
|
result="result8"
|
||||||
style="stop-color:#ff2e88;stop-opacity:1;"
|
id="feBlend11" /><feComposite
|
||||||
offset="0"
|
in2="SourceGraphic"
|
||||||
id="stop11" />
|
in="result8"
|
||||||
<stop
|
operator="in"
|
||||||
style="stop-color:#bf42f6;stop-opacity:1;"
|
result="result7"
|
||||||
offset="0.44971901"
|
id="feComposite11" /></filter></defs><sodipodi:namedview
|
||||||
id="stop154" />
|
id="namedview7"
|
||||||
<stop
|
pagecolor="#ffffff"
|
||||||
style="stop-color:#5da5ed;stop-opacity:1;"
|
bordercolor="#000000"
|
||||||
offset="0.89793283"
|
borderopacity="0.25"
|
||||||
id="stop12" />
|
inkscape:showpageshadow="2"
|
||||||
</linearGradient>
|
inkscape:pageopacity="0.0"
|
||||||
<linearGradient
|
inkscape:pagecheckerboard="0"
|
||||||
inkscape:collect="always"
|
inkscape:deskcolor="#d1d1d1"
|
||||||
xlink:href="#linearGradient138"
|
inkscape:zoom="1.35"
|
||||||
id="linearGradient6"
|
inkscape:cx="254.81481"
|
||||||
gradientUnits="userSpaceOnUse"
|
inkscape:cy="260.37037"
|
||||||
gradientTransform="matrix(1.118028,0,0,1.116699,-46.314723,-42.388667)"
|
inkscape:window-width="1920"
|
||||||
x1="270.39996"
|
inkscape:window-height="1001"
|
||||||
y1="40.000019"
|
inkscape:window-x="-9"
|
||||||
x2="270.39996"
|
inkscape:window-y="-9"
|
||||||
y2="494.39996"
|
inkscape:window-maximized="1"
|
||||||
spreadMethod="pad" />
|
inkscape:current-layer="svg7"
|
||||||
<clipPath
|
showguides="false" /><circle
|
||||||
clipPathUnits="userSpaceOnUse"
|
style="fill:url(#linearGradient12);fill-opacity:1;stroke:#e4e4e4;stroke-width:14.0448;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
id="clipPath18">
|
id="path8"
|
||||||
<circle
|
cx="256.2999"
|
||||||
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
cy="257.2999"
|
||||||
id="circle18"
|
r="248.67769" /><path
|
||||||
cx="-246.8315"
|
id="path15"
|
||||||
cy="246.8338"
|
style="fill:url(#linearGradient2);fill-opacity:1;stroke:#ffffff;stroke-width:16.9642;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.52156866;paint-order:stroke fill markers"
|
||||||
inkscape:label="Circle"
|
d="m 306.72111,24.233031 c 0,0 -11.98397,40.08696 -18.0546,60.431848 -12.96613,9.503601 -21.49377,18.397701 -21.49377,18.397701 0,0 -23.41313,-31.029398 -45.74145,-43.934598 -22.32833,-12.905201 -52.42065,-11.242483 -52.42065,-11.242483 0,0 -12.50052,4e-4 -27.63117,5.537132 -15.13066,5.536732 -21.27107,9.227888 -21.27107,9.227888 0,0 15.35165,-0.410529 37.93799,6.766716 22.58635,7.177243 32.45374,11.484796 32.45374,11.484796 l 31.02752,-6.562453 -8.44161,11.074275 c 0,0 14.80259,8.920284 22.80648,16.917787 8.0039,7.9975 11.73088,12.50812 11.73088,12.50812 0,0 -13.92373,-5.43341 -56.68427,-1.74226 -42.76055,3.69116 -84.86368,56.39265 -84.86368,56.39265 0,0 41.22428,-15.9958 65.5649,-21.32747 24.34062,-5.33166 47.58524,-7.9983 47.58524,-7.9983 0,0 -18.41865,7.3827 -38.15428,38.3474 -19.73564,30.96468 -14.0351,80.18128 -14.0351,80.18128 0,0 31.35774,-59.05848 61.39977,-78.94969 30.04203,-19.89124 36.182,-20.50642 36.182,-20.50642 0,0 -24.1209,48.39514 -33.55015,126.11445 -9.42924,77.71931 30.26089,207.72959 30.26089,207.72959 l 47.80367,-6.97298 c 0,0 -45.61041,-42.24281 -49.55753,-151.33695 -3.94713,-109.09413 16.66479,-174.30453 16.66479,-174.30453 0,0 17.10508,1.23039 42.54213,32.81027 25.43704,31.57987 40.34713,57.41795 40.34713,57.41795 0,0 9.65024,-51.26683 -11.4011,-74.64415 -21.05135,-23.3773 -53.50637,-33.62931 -53.50637,-33.62931 0,0 13.70573,-6.66419 42.10313,-4.71609 28.39738,1.94813 87.30278,27.12897 87.30278,27.12896 0,0 -15.8158,-25.5214 -52.87463,-43.21167 -37.05881,-17.69028 -81.35597,0.29238 -81.35597,0.29238 0,0 4.13589,-15.37277 29.10021,-32.628037 24.96432,-17.25527 56.907,-34.36427 56.907,-34.36427 0,0 -26.3595,1.160335 -55.20025,12.035504 -7.176,2.7059 -14.064,6.299542 -20.36309,10.173104 l 17.40574,-51.051762 z" /><path
|
||||||
r="191.89999" />
|
id="path4-2-6"
|
||||||
</clipPath>
|
style="fill:#ffffff;fill-opacity:0.509804;stroke:#ffffff;stroke-width:8.49614;stroke-dasharray:none;stroke-opacity:0.521569"
|
||||||
<clipPath
|
d="m 105.64857,363.95957 a 27.851731,25.309928 0 0 0 -7.115581,35.20471 27.851731,25.309928 0 0 0 5.656921,5.48617 c 7.16052,5.83605 21.58543,14.65841 45.88391,17.847 37.57172,4.93039 41.7105,10.38005 41.71122,10.381 -4.5e-4,-6e-4 -4.13529,-5.45309 4.14459,-39.11953 5.35491,-21.77281 1.40624,-37.16078 -2.05217,-45.31698 a 27.851731,25.309928 0 0 0 -3.63281,-6.75471 27.851731,25.309928 0 0 0 -38.74027,-6.4662 27.851731,25.309928 0 0 0 -7.11556,35.20472 27.851731,25.309928 0 0 0 -38.74025,-6.46618 z" /><path
|
||||||
clipPathUnits="userSpaceOnUse"
|
id="path4-2-6-1"
|
||||||
id="clipPath22">
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
<circle
|
d="m 351.29524,378.32915 a 20.862787,22.283365 87.929759 0 0 -28.94663,11.7882 20.862787,22.283365 87.929759 0 0 -1.50914,6.04125 c -1.09835,7.13663 -1.16134,20.16231 7.28339,36.72931 13.0577,25.61689 10.90177,30.69793 10.90138,30.69882 2.4e-4,-5.6e-4 2.16,-5.08045 30.49632,-15.43688 18.32576,-6.69765 27.84648,-16.23659 32.287,-22.14109 a 20.862787,22.283365 87.929759 0 0 3.33646,-5.36755 20.862787,22.283365 87.929759 0 0 -12.45108,-27.05014 20.862787,22.283365 87.929759 0 0 -28.94664,11.78822 20.862787,22.283365 87.929759 0 0 -12.45106,-27.05014 z" /><path
|
||||||
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
id="path4-2-6-1-5"
|
||||||
id="circle22"
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.52156866"
|
||||||
cx="256"
|
d="m 83.024352,249.4105 a 22.283365,20.862787 0 0 0 -29.353581,10.73482 22.283365,20.862787 0 0 0 -1.72639,5.98278 c -1.35544,7.0923 -1.88894,20.10721 5.951801,36.96846 12.12378,26.07187 9.7857,31.07171 9.78528,31.07259 2.6e-4,-5.5e-4 2.34212,-4.99911 31.03406,-14.32513 18.555748,-6.03127 28.414858,-15.22005 33.065768,-20.96029 a 22.283365,20.862787 0 0 0 3.52818,-5.24352 22.283365,20.862787 0 0 0 -11.46577,-27.48227 22.283365,20.862787 0 0 0 -29.353588,10.73483 22.283365,20.862787 0 0 0 -11.46576,-27.48227 z" /><path
|
||||||
cy="256"
|
id="path4-2-6-1-9"
|
||||||
inkscape:label="Circle"
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:5.01078;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
r="191.89999" />
|
d="m 320.97602,291.36362 a 16.625347,14.748181 0 0 0 -21.90036,7.58859 16.625347,14.748181 0 0 0 -1.28804,4.2293 c -1.01128,5.01364 -1.40932,14.21406 4.44057,26.1335 9.0454,18.43055 7.30098,21.965 7.30067,21.96562 2e-4,-3.9e-4 1.74743,-3.53394 23.15415,-10.12663 13.84423,-4.26358 21.19999,-10.75925 24.66998,-14.8171 a 16.625347,14.748181 0 0 0 2.63233,-3.70671 16.625347,14.748181 0 0 0 -8.55447,-19.42758 16.625347,14.748181 0 0 0 -21.90037,7.58859 16.625347,14.748181 0 0 0 -8.55446,-19.42758 z" /><path
|
||||||
</clipPath>
|
id="path4-2-6-1-9-8"
|
||||||
<linearGradient
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:4.22313;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
inkscape:collect="always"
|
d="m 416.90426,193.13811 a 12.322476,14.134158 82.30909 0 0 -17.56469,8.83612 12.322476,14.134158 82.30909 0 0 -0.59553,3.65007 c -0.27175,4.26676 0.45709,11.92642 6.76182,21.10665 9.74867,14.19503 8.68847,17.32338 8.68827,17.3239 1.2e-4,-3.3e-4 1.06282,-3.12827 18.32699,-11.08266 11.16516,-5.14424 16.60821,-11.37802 19.06101,-15.14093 a 12.322476,14.134158 82.30909 0 0 1.788,-3.37453 12.322476,14.134158 82.30909 0 0 -9.45059,-15.07737 12.322476,14.134158 82.30909 0 0 -17.5647,8.83612 12.322476,14.134158 82.30909 0 0 -9.45058,-15.07737 z" /><path
|
||||||
xlink:href="#linearGradient11"
|
id="path4-2-6-1-9-8-4"
|
||||||
id="linearGradient27"
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.48342;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
gradientUnits="userSpaceOnUse"
|
d="m 96.169666,99.754795 a 10.296362,11.508677 62.365085 0 0 -7.330189,13.841365 10.296362,11.508677 62.365085 0 0 1.473186,2.6805 c 2.008889,2.93989 6.437543,7.66269 15.415927,10.84633 13.88288,4.92276 14.77391,7.47086 14.77407,7.4713 -1e-4,-2.8e-4 -0.88925,-2.54921 6.69094,-15.67164 4.90232,-8.48655 5.37758,-15.08279 5.10162,-18.6847 a 10.296362,11.508677 62.365085 0 0 -0.5257,-3.042454 10.296362,11.508677 62.365085 0 0 -14.1348,-5.641051 10.296362,11.508677 62.365085 0 0 -7.33021,13.841385 10.296362,11.508677 62.365085 0 0 -14.134844,-5.641035 z" /><path
|
||||||
gradientTransform="translate(-6.9401139e-5,-2.8678628)"
|
id="path4-2-6-1-9-8-4-9-2"
|
||||||
x1="256.00012"
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.05139;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
y1="102.94693"
|
d="m 296.64657,233.26347 a 8.8114666,10.319195 80.445391 0 0 -11.58972,8.06989 8.8114666,10.319195 80.445391 0 0 0.0366,2.62543 c 0.35019,3.02392 1.86017,8.32306 7.60386,14.09672 8.8812,8.92759 8.51432,11.23624 8.51426,11.23663 5e-5,-2.5e-4 0.36876,-2.30885 11.85385,-9.72788 7.4277,-4.79799 10.57103,-9.75243 11.86523,-12.65455 a 8.8114666,10.319195 80.445391 0 0 0.86244,-2.55882 8.8114666,10.319195 80.445391 0 0 -8.77837,-9.57865 8.8114666,10.319195 80.445391 0 0 -11.58975,8.06989 8.8114666,10.319195 80.445391 0 0 -8.77842,-9.57866 z" /><path
|
||||||
x2="256.00012"
|
id="path4-2-6-1-9-8-4-9-2-6"
|
||||||
y2="409.05307" />
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:2.49738;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
<clipPath
|
d="m 403.95446,91.44744 a 7.0950375,8.5844443 82.142743 0 0 -9.64888,6.492875 7.0950375,8.5844443 82.142743 0 0 0.0305,2.112375 c 0.29155,2.43298 1.54866,6.69657 6.33049,11.34195 7.39392,7.18298 7.08848,9.04046 7.08843,9.04078 4e-5,-2.1e-4 0.307,-1.85765 9.86876,-7.82686 6.18383,-3.86038 8.80077,-7.84663 9.87824,-10.18161 a 7.0950375,8.5844443 82.142743 0 0 0.718,-2.05879 7.0950375,8.5844443 82.142743 0 0 -7.30831,-7.706798 7.0950375,8.5844443 82.142743 0 0 -9.64889,6.492875 7.0950375,8.5844443 82.142743 0 0 -7.30834,-7.706797 z" /><path
|
||||||
clipPathUnits="userSpaceOnUse"
|
id="path4-2-6-1-9-8-4-9-5"
|
||||||
id="clipPath128">
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:7.54176;stroke-dasharray:none;stroke-opacity:0.521569"
|
||||||
<circle
|
d="m 410.46352,265.86621 a 24.802737,22.39469 2.0523303 0 0 -30.17074,15.95063 24.802737,22.39469 2.0523303 0 0 -0.74427,6.61415 c -0.12337,7.7333 1.79614,21.62064 13.65297,38.28529 18.33368,25.76802 16.72835,31.4347 16.72811,31.43572 1.4e-4,-6.3e-4 1.60998,-5.66652 31.32518,-20.02007 19.21759,-9.28266 28.27643,-20.56192 32.27921,-27.37361 a 24.802737,22.39469 2.0523303 0 0 2.8654,-6.11021 24.802737,22.39469 2.0523303 0 0 -17.88248,-27.36631 24.802737,22.39469 2.0523303 0 0 -30.17081,15.95066 24.802737,22.39469 2.0523303 0 0 -17.88257,-27.36625 z" /><path
|
||||||
style="fill:none;fill-opacity:1;stroke:#03ffff;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
|
id="path4-2-6-1-9-8-5"
|
||||||
id="circle128"
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.6405;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
cx="256"
|
d="m 114.43099,189.33754 a 10.333135,12.525309 79.004057 0 0 -14.00848,9.75499 10.333135,12.525309 79.004057 0 0 0.0547,3.08382 c 0.43602,3.54457 2.28588,9.73496 9.26636,16.38295 10.79359,10.27954 10.35819,13.00063 10.3581,13.00111 6e-5,-3e-4 0.4377,-2.72141 14.32197,-11.70923 8.9793,-5.8126 12.76786,-11.70785 14.32433,-15.14812 a 10.333135,12.525309 79.004057 0 0 1.03481,-3.02677 10.333135,12.525309 79.004057 0 0 -10.67161,-11.04688 10.333135,12.525309 79.004057 0 0 -14.00848,9.75501 10.333135,12.525309 79.004057 0 0 -10.6716,-11.04688 z" /><path
|
||||||
cy="256"
|
id="path4-2-6-1-9-8-4-9-2-2"
|
||||||
r="192" />
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.62674;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
</clipPath>
|
d="m 178.56055,273.32338 a 10.656883,12.053184 66.089768 0 0 -7.97821,14.16205 10.656883,12.053184 66.089768 0 0 1.49012,2.79504 c 2.04675,3.07265 6.5954,8.03049 15.94965,11.48124 14.46412,5.33577 15.34612,7.98353 15.34628,7.98398 -8e-5,-2.8e-4 -0.88012,-2.64887 7.3455,-16.0639 5.31973,-8.67576 5.95524,-15.47956 5.74045,-19.20452 a 10.656883,12.053184 66.089768 0 0 -0.48843,-3.15169 10.656883,12.053184 66.089768 0 0 -14.7135,-6.08217 10.656883,12.053184 66.089768 0 0 -7.97826,14.1621 10.656883,12.053184 66.089768 0 0 -14.71355,-6.08215 z" /></svg>
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient1"
|
|
||||||
id="linearGradient2"
|
|
||||||
x1="256"
|
|
||||||
y1="64"
|
|
||||||
x2="256"
|
|
||||||
y2="448"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="matrix(1.3229974,0,0,1.3214002,-82.687336,-82.290326)" />
|
|
||||||
</defs>
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview7"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#000000"
|
|
||||||
borderopacity="0.25"
|
|
||||||
inkscape:showpageshadow="2"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:zoom="1.4142136"
|
|
||||||
inkscape:cx="261.62951"
|
|
||||||
inkscape:cy="230.87036"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1008"
|
|
||||||
inkscape:window-x="1080"
|
|
||||||
inkscape:window-y="351"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg7" />
|
|
||||||
<path
|
|
||||||
id="path8-7"
|
|
||||||
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient6);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2);stroke-width:3.9666;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
|
||||||
inkscape:label="Circle"
|
|
||||||
d="M 256,2.2792898 A 254.0155,253.71401 0 0 0 150.68475,25.115202 c 19.54414,1.070775 38.74692,5.250294 51.56848,11.647658 14.14361,7.056691 28.63804,19.185961 39.4212,29.347551 h 40.60981 c 1.03847,-0.68139 2.10297,-1.36938 3.1938,-2.05957 5.45602,-15.78533 14.79164,-43.183497 19.49612,-57.0097682 A 254.0155,253.71401 0 0 0 256,2.2792898 Z m 61.57106,7.567234 -18.26098,46.1544672 c 7.79702,-4.13918 16.35655,-7.87447 25.20671,-10.87081 23.1229,-7.828433 43.96931,-10.170904 54.94058,-10.868226 A 254.0155,253.71401 0 0 0 317.57106,9.8465238 Z m 65.39277,26.4001532 c -9.68256,4.806644 -33.05532,16.642034 -55.68217,29.863734 H 424.4677 A 254.0155,253.71401 0 0 0 382.96383,36.246677 Z M 113.90698,45.690231 A 254.0155,253.71401 0 0 0 87.532302,66.110411 H 194.2739 c -1.47402,-0.80231 -2.35141,-1.25949 -2.35141,-1.25949 l 10.4496,-11.83348 -38.40568,7.01234 c 0,1e-5 -12.21537,-4.60266 -40.17313,-12.27223 -3.45336,-0.94731 -6.75329,-1.61824 -9.8863,-2.06732 z m -36.803618,30.18635 a 254.0155,253.71401 0 0 0 -34.88372,43.090929 h 59.976738 c 18.11461,-12.04145 40.14252,-22.882149 62.31266,-24.534159 52.93006,-3.9444 70.16538,1.86342 70.16538,1.86342 0,0 -4.612,-4.8206 -14.51938,-13.36656 -2.72366,-2.34942 -6.0844,-4.77373 -9.52455,-7.05363 z m 174.472868,0 c 4.57322,4.7186 7.29716,7.83565 7.29716,7.83565 0,0 3.53501,-3.18484 9.62532,-7.83565 z m 60.27649,0 c -21.56573,15.45339 -25.4703,27.979669 -25.4703,27.979669 0,0 54.83326,-19.215729 100.70543,-0.31228 11.63986,4.79661 21.58481,10.13159 29.94832,15.42354 h 52.74419 A 254.0155,253.71401 0 0 0 434.89664,75.876581 Z M 36.250648,128.73367 A 254.0155,253.71401 0 0 0 16.372095,171.82459 H 147.45478 c 1.45695,-2.5815 3.06539,-5.08648 4.83979,-7.48982 14.23694,-19.28301 27.92088,-30.0088 36.86047,-35.6011 h -30.25323 c -5.87346,0.93472 -12.04945,1.99094 -18.28166,3.16937 -30.12936,5.69727 -81.157618,22.78945 -81.157618,22.78945 0,0 11.47125,-12.39249 29.11369,-25.95882 z m 265.630492,0 c 33.48676,11.2434 52.42799,26.78443 62.7752,43.09092 h 130.97157 a 254.0155,253.71401 0 0 0 -19.87856,-43.09092 h -44.81136 c 14.85233,11.5863 21.59948,20.9854 21.59948,20.9854 0,0 -33.5226,-12.37087 -66.0646,-20.9854 z m -45.96641,16.27007 c -1.00419,0.0106 -10.12705,0.72026 -44.98966,20.64729 -3.12132,1.78406 -6.25434,3.86182 -9.37468,6.17356 h 41.81911 c 7.17181,-17.34774 12.64083,-26.82085 12.64083,-26.82085 0,0 -0.0287,-7.1e-4 -0.0957,0 z m 14.18088,0.0465 c 0,0 -3.31228,9.32762 -7.30492,26.77438 h 51.78554 C 287.6577,146.14158 270.09561,145.0502 270.09561,145.0502 Z M 13.152456,181.59075 A 254.0155,253.71401 0 0 0 3.927651,224.68167 H 134.1447 c 0.56161,-12.72411 2.67825,-28.50188 8.61499,-43.09092 z m 176.661504,0 c -14.27121,13.10564 -27.60733,29.58761 -37.56073,43.09092 h 73.3721 c 4.47018,-16.79061 9.35068,-31.26371 13.86562,-43.09092 z m 70.85787,0 c -2.41384,11.76417 -4.9032,26.20707 -6.94831,43.09092 H 360.4832 c -8.32133,-10.88917 -20.66988,-26.17008 -36.35141,-43.09092 z m 109.17313,0 c 6.63611,15.24089 6.92441,30.5373 5.57882,43.09092 h 132.64857 a 254.0155,253.71401 0 0 0 -9.22481,-43.09092 z M 2.90181,234.44783 A 254.0155,253.71401 0 0 0 1.984498,255.9933 254.0155,253.71401 0 0 0 2.90181,277.53876 h 211.89923 c 2.25762,-15.52555 5.14325,-29.93448 8.3385,-43.09093 h -77.8863 c -6.46396,9.27617 -10.33076,15.56549 -10.33076,15.56549 0,0 -0.82623,-6.14945 -0.9354,-15.56549 z m 249.72093,0 c -1.3692,13.09684 -2.4456,27.49209 -3.02068,43.09093 h 259.49613 a 254.0155,253.71401 0 0 0 0.91731,-21.54546 254.0155,253.71401 0 0 0 -0.91731,-21.54547 H 374.02584 c -0.445,2.5469 -0.90878,4.89768 -1.32817,7.01751 0,0 -1.69726,-2.53821 -4.94056,-7.01751 z M 3.927651,287.30493 a 254.0155,253.71401 0 0 0 9.224805,43.09091 H 214.04393 c -1.29238,-15.40742 -1.57503,-30.04388 -0.41861,-43.09091 z m 245.385009,0 c -0.30355,13.54349 -0.22032,27.92598 0.36951,43.09091 h 249.16537 a 254.0155,253.71401 0 0 0 9.22481,-43.09091 z M 16.369511,340.16201 a 254.0155,253.71401 0 0 0 19.878554,43.09091 H 221.4677 c -2.69781,-14.4523 -4.96108,-29.01285 -6.4832,-43.09091 z m 233.842379,0 c 1.15864,15.47765 3.81286,29.83979 7.51679,43.09091 h 218.02325 a 254.0155,253.71401 0 0 0 19.87856,-43.09091 z M 42.217052,393.01909 a 254.0155,253.71401 0 0 0 34.88372,43.09093 H 233.09561 c -3.40902,-13.67281 -6.76794,-28.2531 -9.73902,-43.09093 z m 218.490958,0 c 5.34985,16.15926 12.22007,30.51982 19.68733,43.09093 h 154.50389 a 254.0155,253.71401 0 0 0 34.88371,-43.09093 z M 87.529722,445.87618 a 254.0155,253.71401 0 0 0 166.229968,63.8208 c -3.67805,-12.0825 -10.85464,-35.49828 -18.18088,-63.8208 z m 199.010328,0 c 17.5887,26.43772 36.99259,43.60598 47.33592,51.61309 a 254.0155,253.71401 0 0 0 90.59431,-51.61309 z" />
|
|
||||||
<path
|
|
||||||
id="path27"
|
|
||||||
style="display:inline;mix-blend-mode:multiply;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient27);stroke-width:3;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
|
|
||||||
d="m 318.98012,441.7375 c -9.87518,-6.73978 -64.39137,-49.0272 -67.68975,-127.81978 -3.69298,-88.21893 15.36468,-141.91029 15.36468,-141.91029 0,0 16.00378,0.99513 39.80316,26.53195 23.79939,25.53753 37.74965,46.43102 37.74965,46.43102 3.91262,-19.79992 12.84563,-66.32402 -60.72865,-87.55523 0,0 12.82326,-5.38883 39.3925,-3.81382 26.56907,1.57572 81.6822,21.93799 81.6822,21.93799 0,0 -14.79766,-20.63773 -49.47063,-34.94295 -34.67291,-14.30533 -76.1182,0.23644 -76.1182,0.23644 0,0 3.86959,-12.43127 27.22669,-26.38478 23.35718,-13.9537 49.27409,-26.501533 49.27409,-26.501533 0,0 -21.97854,-0.26548 -47.67725,8.44535 -6.68948,2.267506 -13.15863,5.094213 -19.05208,8.226563 l 16.05803,-40.634103 -4.4617,-1.89059 -5.1305,-0.95965 c 0,0 -11.24072,33.12428 -16.92051,49.576513 -12.13137,7.68489 -20.11005,14.87735 -20.11005,14.87735 0,0 -21.90573,-25.09227 -42.79668,-35.527803 -26.03412,-13.00525 -86.88249,-13.90359 -94.0044,10.401173 0,0 13.56804,-7.884703 34.70032,-2.080917 21.13214,5.803997 30.3644,9.287307 30.3644,9.287307 l 29.02989,-5.30681 -7.89811,8.95527 c 0,0 13.8496,7.21324 21.33822,13.68063 7.48859,6.46722 10.9757,10.11472 10.9757,10.11472 0,0 -13.02739,-4.39388 -53.03507,-1.40893 -40.00771,2.98473 -79.40016,45.60209 -79.40016,45.60209 0,0 38.57037,-12.93531 61.34393,-17.24677 22.77354,-4.31126 44.52166,-6.46757 44.52166,-6.46757 0,0 -17.23298,5.97003 -35.69792,31.00932 -18.46522,25.03987 -13.13146,64.83866 -13.13146,64.83866 0,0 29.33874,-47.7577 57.44675,-63.84249 28.10798,-16.08527 34.0799,-15.6238 34.0799,-15.6238 0,0 -22.56785,39.13486 -31.39017,101.98268 -8.03005,57.2039 26.77689,163.75449 31.1572,178.89699"
|
|
||||||
sodipodi:nodetypes="cscsccscscscsccccccscscccscscscscscsc"
|
|
||||||
inkscape:label="MainOutline"
|
|
||||||
clip-path="url(#clipPath128)"
|
|
||||||
transform="matrix(1.3229974,0,0,1.3214002,-82.687282,-82.278451)" />
|
|
||||||
</svg>
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 332 KiB After Width: | Height: | Size: 379 KiB |
@@ -0,0 +1,211 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg7"
|
||||||
|
sodipodi:docname="EdenLogoLoveWhiteV3.svg"
|
||||||
|
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:export-filename="dev.eden_emu.eden.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<metadata
|
||||||
|
id="metadata1">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>Madeline_Dev</dc:title>
|
||||||
|
<dc:identifier>mailto:madelvidel@gmail.com</dc:identifier>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
<dc:date>2025</dc:date>
|
||||||
|
<dc:license
|
||||||
|
rdf:resource="https://www.gnu.org/licenses/gpl-3.0.html" />
|
||||||
|
<dc:rights>2025 Eden Emulator Project</dc:rights>
|
||||||
|
<dc:source>https://git.eden-emu.dev</dc:source>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs7"><linearGradient
|
||||||
|
id="swatch14"
|
||||||
|
inkscape:swatch="solid"><stop
|
||||||
|
style="stop-color:#66003b;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop14" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient1"
|
||||||
|
inkscape:collect="always"><stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0.50980395;"
|
||||||
|
offset="0"
|
||||||
|
id="stop1" /><stop
|
||||||
|
style="stop-color:#000000;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient11"
|
||||||
|
inkscape:collect="always"><stop
|
||||||
|
style="stop-color:#9523a7;stop-opacity:0.50980395;"
|
||||||
|
offset="0"
|
||||||
|
id="stop11" /><stop
|
||||||
|
style="stop-color:#ffabad;stop-opacity:1;"
|
||||||
|
offset="0.99898213"
|
||||||
|
id="stop20" /><stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0;"
|
||||||
|
offset="0.99898213"
|
||||||
|
id="stop12" /></linearGradient><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient11"
|
||||||
|
id="linearGradient12"
|
||||||
|
x1="109.74531"
|
||||||
|
y1="106.54533"
|
||||||
|
x2="431.05463"
|
||||||
|
y2="427.85461"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
spreadMethod="reflect"
|
||||||
|
gradientTransform="matrix(1.0945321,0,0,1.0945321,-39.661525,-35.159057)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient1"
|
||||||
|
id="linearGradient2"
|
||||||
|
x1="125.40197"
|
||||||
|
y1="271.834"
|
||||||
|
x2="431.02424"
|
||||||
|
y2="271.834"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.0964243,0,0,1.0253208,-40.187969,-20.060025)" /><filter
|
||||||
|
inkscape:label="Light Contour"
|
||||||
|
inkscape:menu="Image Paint and Draw"
|
||||||
|
inkscape:menu-tooltip="Uses vertical specular light to draw lines"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter11"
|
||||||
|
x="-0.01907517"
|
||||||
|
y="-0.054959154"
|
||||||
|
width="1.0379885"
|
||||||
|
height="1.1092314"><feGaussianBlur
|
||||||
|
in="SourceGraphic"
|
||||||
|
stdDeviation="0.38250006"
|
||||||
|
result="result3"
|
||||||
|
id="feGaussianBlur9" /><feComponentTransfer
|
||||||
|
result="result1"
|
||||||
|
in="result3"
|
||||||
|
id="feComponentTransfer9"><feFuncR
|
||||||
|
type="discrete"
|
||||||
|
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||||
|
id="feFuncR9" /><feFuncG
|
||||||
|
type="discrete"
|
||||||
|
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||||
|
id="feFuncG9" /><feFuncB
|
||||||
|
type="discrete"
|
||||||
|
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||||
|
id="feFuncB9" /></feComponentTransfer><feGaussianBlur
|
||||||
|
result="result5"
|
||||||
|
stdDeviation="0.01"
|
||||||
|
id="feGaussianBlur10" /><feBlend
|
||||||
|
in2="result5"
|
||||||
|
result="result6"
|
||||||
|
mode="lighten"
|
||||||
|
in="result5"
|
||||||
|
id="feBlend10" /><feColorMatrix
|
||||||
|
in="result6"
|
||||||
|
type="luminanceToAlpha"
|
||||||
|
result="result2"
|
||||||
|
id="feColorMatrix10" /><feSpecularLighting
|
||||||
|
surfaceScale="5"
|
||||||
|
result="result9"
|
||||||
|
specularExponent="20"
|
||||||
|
in="result2"
|
||||||
|
specularConstant="1"
|
||||||
|
id="feSpecularLighting10"><feDistantLight
|
||||||
|
azimuth="180"
|
||||||
|
elevation="90"
|
||||||
|
id="feDistantLight10" /></feSpecularLighting><feComposite
|
||||||
|
in2="result6"
|
||||||
|
operator="arithmetic"
|
||||||
|
in="result9"
|
||||||
|
k1="0.4"
|
||||||
|
k3="0.7"
|
||||||
|
result="result3"
|
||||||
|
id="feComposite10"
|
||||||
|
k2="0"
|
||||||
|
k4="0" /><feBlend
|
||||||
|
in2="result1"
|
||||||
|
in="result3"
|
||||||
|
mode="normal"
|
||||||
|
result="result8"
|
||||||
|
id="feBlend11" /><feComposite
|
||||||
|
in2="SourceGraphic"
|
||||||
|
in="result8"
|
||||||
|
operator="in"
|
||||||
|
result="result7"
|
||||||
|
id="feComposite11" /></filter></defs><sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="1.35"
|
||||||
|
inkscape:cx="254.81481"
|
||||||
|
inkscape:cy="260.37037"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1001"
|
||||||
|
inkscape:window-x="-9"
|
||||||
|
inkscape:window-y="-9"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg7"
|
||||||
|
showguides="false" /><circle
|
||||||
|
style="fill:url(#linearGradient12);fill-opacity:1;stroke:#e4e4e4;stroke-width:14.0448;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
id="path8"
|
||||||
|
cx="256.2999"
|
||||||
|
cy="257.2999"
|
||||||
|
r="248.67769" /><path
|
||||||
|
id="path15"
|
||||||
|
style="fill:url(#linearGradient2);fill-opacity:1;stroke:#ffffff;stroke-width:16.9642;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.52156866;paint-order:stroke fill markers"
|
||||||
|
d="m 306.72111,24.233031 c 0,0 -11.98397,40.08696 -18.0546,60.431848 -12.96613,9.503601 -21.49377,18.397701 -21.49377,18.397701 0,0 -23.41313,-31.029398 -45.74145,-43.934598 -22.32833,-12.905201 -52.42065,-11.242483 -52.42065,-11.242483 0,0 -12.50052,4e-4 -27.63117,5.537132 -15.13066,5.536732 -21.27107,9.227888 -21.27107,9.227888 0,0 15.35165,-0.410529 37.93799,6.766716 22.58635,7.177243 32.45374,11.484796 32.45374,11.484796 l 31.02752,-6.562453 -8.44161,11.074275 c 0,0 14.80259,8.920284 22.80648,16.917787 8.0039,7.9975 11.73088,12.50812 11.73088,12.50812 0,0 -13.92373,-5.43341 -56.68427,-1.74226 -42.76055,3.69116 -84.86368,56.39265 -84.86368,56.39265 0,0 41.22428,-15.9958 65.5649,-21.32747 24.34062,-5.33166 47.58524,-7.9983 47.58524,-7.9983 0,0 -18.41865,7.3827 -38.15428,38.3474 -19.73564,30.96468 -14.0351,80.18128 -14.0351,80.18128 0,0 31.35774,-59.05848 61.39977,-78.94969 30.04203,-19.89124 36.182,-20.50642 36.182,-20.50642 0,0 -24.1209,48.39514 -33.55015,126.11445 -9.42924,77.71931 30.26089,207.72959 30.26089,207.72959 l 47.80367,-6.97298 c 0,0 -45.61041,-42.24281 -49.55753,-151.33695 -3.94713,-109.09413 16.66479,-174.30453 16.66479,-174.30453 0,0 17.10508,1.23039 42.54213,32.81027 25.43704,31.57987 40.34713,57.41795 40.34713,57.41795 0,0 9.65024,-51.26683 -11.4011,-74.64415 -21.05135,-23.3773 -53.50637,-33.62931 -53.50637,-33.62931 0,0 13.70573,-6.66419 42.10313,-4.71609 28.39738,1.94813 87.30278,27.12897 87.30278,27.12896 0,0 -15.8158,-25.5214 -52.87463,-43.21167 -37.05881,-17.69028 -81.35597,0.29238 -81.35597,0.29238 0,0 4.13589,-15.37277 29.10021,-32.628037 24.96432,-17.25527 56.907,-34.36427 56.907,-34.36427 0,0 -26.3595,1.160335 -55.20025,12.035504 -7.176,2.7059 -14.064,6.299542 -20.36309,10.173104 l 17.40574,-51.051762 z" /><path
|
||||||
|
id="path4-2-6"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.509804;stroke:#ffffff;stroke-width:8.49614;stroke-dasharray:none;stroke-opacity:0.521569"
|
||||||
|
d="m 105.64857,363.95957 a 27.851731,25.309928 0 0 0 -7.115581,35.20471 27.851731,25.309928 0 0 0 5.656921,5.48617 c 7.16052,5.83605 21.58543,14.65841 45.88391,17.847 37.57172,4.93039 41.7105,10.38005 41.71122,10.381 -4.5e-4,-6e-4 -4.13529,-5.45309 4.14459,-39.11953 5.35491,-21.77281 1.40624,-37.16078 -2.05217,-45.31698 a 27.851731,25.309928 0 0 0 -3.63281,-6.75471 27.851731,25.309928 0 0 0 -38.74027,-6.4662 27.851731,25.309928 0 0 0 -7.11556,35.20472 27.851731,25.309928 0 0 0 -38.74025,-6.46618 z" /><path
|
||||||
|
id="path4-2-6-1"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 351.29524,378.32915 a 20.862787,22.283365 87.929759 0 0 -28.94663,11.7882 20.862787,22.283365 87.929759 0 0 -1.50914,6.04125 c -1.09835,7.13663 -1.16134,20.16231 7.28339,36.72931 13.0577,25.61689 10.90177,30.69793 10.90138,30.69882 2.4e-4,-5.6e-4 2.16,-5.08045 30.49632,-15.43688 18.32576,-6.69765 27.84648,-16.23659 32.287,-22.14109 a 20.862787,22.283365 87.929759 0 0 3.33646,-5.36755 20.862787,22.283365 87.929759 0 0 -12.45108,-27.05014 20.862787,22.283365 87.929759 0 0 -28.94664,11.78822 20.862787,22.283365 87.929759 0 0 -12.45106,-27.05014 z" /><path
|
||||||
|
id="path4-2-6-1-5"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.52156866"
|
||||||
|
d="m 83.024352,249.4105 a 22.283365,20.862787 0 0 0 -29.353581,10.73482 22.283365,20.862787 0 0 0 -1.72639,5.98278 c -1.35544,7.0923 -1.88894,20.10721 5.951801,36.96846 12.12378,26.07187 9.7857,31.07171 9.78528,31.07259 2.6e-4,-5.5e-4 2.34212,-4.99911 31.03406,-14.32513 18.555748,-6.03127 28.414858,-15.22005 33.065768,-20.96029 a 22.283365,20.862787 0 0 0 3.52818,-5.24352 22.283365,20.862787 0 0 0 -11.46577,-27.48227 22.283365,20.862787 0 0 0 -29.353588,10.73483 22.283365,20.862787 0 0 0 -11.46576,-27.48227 z" /><path
|
||||||
|
id="path4-2-6-1-9"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:5.01078;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 320.97602,291.36362 a 16.625347,14.748181 0 0 0 -21.90036,7.58859 16.625347,14.748181 0 0 0 -1.28804,4.2293 c -1.01128,5.01364 -1.40932,14.21406 4.44057,26.1335 9.0454,18.43055 7.30098,21.965 7.30067,21.96562 2e-4,-3.9e-4 1.74743,-3.53394 23.15415,-10.12663 13.84423,-4.26358 21.19999,-10.75925 24.66998,-14.8171 a 16.625347,14.748181 0 0 0 2.63233,-3.70671 16.625347,14.748181 0 0 0 -8.55447,-19.42758 16.625347,14.748181 0 0 0 -21.90037,7.58859 16.625347,14.748181 0 0 0 -8.55446,-19.42758 z" /><path
|
||||||
|
id="path4-2-6-1-9-8"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:4.22313;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 416.90426,193.13811 a 12.322476,14.134158 82.30909 0 0 -17.56469,8.83612 12.322476,14.134158 82.30909 0 0 -0.59553,3.65007 c -0.27175,4.26676 0.45709,11.92642 6.76182,21.10665 9.74867,14.19503 8.68847,17.32338 8.68827,17.3239 1.2e-4,-3.3e-4 1.06282,-3.12827 18.32699,-11.08266 11.16516,-5.14424 16.60821,-11.37802 19.06101,-15.14093 a 12.322476,14.134158 82.30909 0 0 1.788,-3.37453 12.322476,14.134158 82.30909 0 0 -9.45059,-15.07737 12.322476,14.134158 82.30909 0 0 -17.5647,8.83612 12.322476,14.134158 82.30909 0 0 -9.45058,-15.07737 z" /><path
|
||||||
|
id="path4-2-6-1-9-8-4"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.48342;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 96.169666,99.754795 a 10.296362,11.508677 62.365085 0 0 -7.330189,13.841365 10.296362,11.508677 62.365085 0 0 1.473186,2.6805 c 2.008889,2.93989 6.437543,7.66269 15.415927,10.84633 13.88288,4.92276 14.77391,7.47086 14.77407,7.4713 -1e-4,-2.8e-4 -0.88925,-2.54921 6.69094,-15.67164 4.90232,-8.48655 5.37758,-15.08279 5.10162,-18.6847 a 10.296362,11.508677 62.365085 0 0 -0.5257,-3.042454 10.296362,11.508677 62.365085 0 0 -14.1348,-5.641051 10.296362,11.508677 62.365085 0 0 -7.33021,13.841385 10.296362,11.508677 62.365085 0 0 -14.134844,-5.641035 z" /><path
|
||||||
|
id="path4-2-6-1-9-8-4-9-2"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.05139;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 296.64657,233.26347 a 8.8114666,10.319195 80.445391 0 0 -11.58972,8.06989 8.8114666,10.319195 80.445391 0 0 0.0366,2.62543 c 0.35019,3.02392 1.86017,8.32306 7.60386,14.09672 8.8812,8.92759 8.51432,11.23624 8.51426,11.23663 5e-5,-2.5e-4 0.36876,-2.30885 11.85385,-9.72788 7.4277,-4.79799 10.57103,-9.75243 11.86523,-12.65455 a 8.8114666,10.319195 80.445391 0 0 0.86244,-2.55882 8.8114666,10.319195 80.445391 0 0 -8.77837,-9.57865 8.8114666,10.319195 80.445391 0 0 -11.58975,8.06989 8.8114666,10.319195 80.445391 0 0 -8.77842,-9.57866 z" /><path
|
||||||
|
id="path4-2-6-1-9-8-4-9-2-6"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:2.49738;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 403.95446,91.44744 a 7.0950375,8.5844443 82.142743 0 0 -9.64888,6.492875 7.0950375,8.5844443 82.142743 0 0 0.0305,2.112375 c 0.29155,2.43298 1.54866,6.69657 6.33049,11.34195 7.39392,7.18298 7.08848,9.04046 7.08843,9.04078 4e-5,-2.1e-4 0.307,-1.85765 9.86876,-7.82686 6.18383,-3.86038 8.80077,-7.84663 9.87824,-10.18161 a 7.0950375,8.5844443 82.142743 0 0 0.718,-2.05879 7.0950375,8.5844443 82.142743 0 0 -7.30831,-7.706798 7.0950375,8.5844443 82.142743 0 0 -9.64889,6.492875 7.0950375,8.5844443 82.142743 0 0 -7.30834,-7.706797 z" /><path
|
||||||
|
id="path4-2-6-1-9-8-4-9-5"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:7.54176;stroke-dasharray:none;stroke-opacity:0.521569"
|
||||||
|
d="m 410.46352,265.86621 a 24.802737,22.39469 2.0523303 0 0 -30.17074,15.95063 24.802737,22.39469 2.0523303 0 0 -0.74427,6.61415 c -0.12337,7.7333 1.79614,21.62064 13.65297,38.28529 18.33368,25.76802 16.72835,31.4347 16.72811,31.43572 1.4e-4,-6.3e-4 1.60998,-5.66652 31.32518,-20.02007 19.21759,-9.28266 28.27643,-20.56192 32.27921,-27.37361 a 24.802737,22.39469 2.0523303 0 0 2.8654,-6.11021 24.802737,22.39469 2.0523303 0 0 -17.88248,-27.36631 24.802737,22.39469 2.0523303 0 0 -30.17081,15.95066 24.802737,22.39469 2.0523303 0 0 -17.88257,-27.36625 z" /><path
|
||||||
|
id="path4-2-6-1-9-8-5"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.6405;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 114.43099,189.33754 a 10.333135,12.525309 79.004057 0 0 -14.00848,9.75499 10.333135,12.525309 79.004057 0 0 0.0547,3.08382 c 0.43602,3.54457 2.28588,9.73496 9.26636,16.38295 10.79359,10.27954 10.35819,13.00063 10.3581,13.00111 6e-5,-3e-4 0.4377,-2.72141 14.32197,-11.70923 8.9793,-5.8126 12.76786,-11.70785 14.32433,-15.14812 a 10.333135,12.525309 79.004057 0 0 1.03481,-3.02677 10.333135,12.525309 79.004057 0 0 -10.67161,-11.04688 10.333135,12.525309 79.004057 0 0 -14.00848,9.75501 10.333135,12.525309 79.004057 0 0 -10.6716,-11.04688 z" /><path
|
||||||
|
id="path4-2-6-1-9-8-4-9-2-2"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.62674;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||||
|
d="m 178.56055,273.32338 a 10.656883,12.053184 66.089768 0 0 -7.97821,14.16205 10.656883,12.053184 66.089768 0 0 1.49012,2.79504 c 2.04675,3.07265 6.5954,8.03049 15.94965,11.48124 14.46412,5.33577 15.34612,7.98353 15.34628,7.98398 -8e-5,-2.8e-4 -0.88012,-2.64887 7.3455,-16.0639 5.31973,-8.67576 5.95524,-15.47956 5.74045,-19.20452 a 10.656883,12.053184 66.089768 0 0 -0.48843,-3.15169 10.656883,12.053184 66.089768 0 0 -14.7135,-6.08217 10.656883,12.053184 66.089768 0 0 -7.97826,14.1621 10.656883,12.053184 66.089768 0 0 -14.71355,-6.08215 z" /></svg>
|
||||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1 @@
|
|||||||
|
#e48cc9ff
|
||||||
|
After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 79 KiB |
@@ -27,11 +27,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
|
|||||||
|
|
||||||
# Xbyak
|
# Xbyak
|
||||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||||
if (PLATFORM_SUN OR PLATFORM_OPENBSD OR PLATFORM_NETBSD OR PLATFORM_DRAGONFLY)
|
AddJsonPackage(xbyak)
|
||||||
AddJsonPackage(xbyak_sun)
|
|
||||||
else()
|
|
||||||
AddJsonPackage(xbyak)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# enet
|
# enet
|
||||||
|
|||||||
@@ -48,23 +48,12 @@
|
|||||||
"0001-fix-missing-decl.patch"
|
"0001-fix-missing-decl.patch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"xbyak_sun": {
|
|
||||||
"package": "xbyak",
|
|
||||||
"repo": "herumi/xbyak",
|
|
||||||
"tag": "v%VERSION%",
|
|
||||||
"hash": "b40dade90fb0e46a2bd52934f7ce461e37be931b571e58cbe2203bc08ed5b54c7ff1a29026c74c7f9805e4e3f6c9636deca528e6b4a8093ce7eae145218599f1",
|
|
||||||
"git_version": "7.29",
|
|
||||||
"bundled": true,
|
|
||||||
"skip_updates": true
|
|
||||||
},
|
|
||||||
"xbyak": {
|
"xbyak": {
|
||||||
"package": "xbyak",
|
"package": "xbyak",
|
||||||
"repo": "herumi/xbyak",
|
"repo": "herumi/xbyak",
|
||||||
"tag": "v%VERSION%",
|
"tag": "v%VERSION%",
|
||||||
"hash": "1042090405c426e339506c179d53e91d4d545ce9c9f53d8f797caa092d589f913a9bcb9c8f31c4c60870acb954c556e305fb6732c66bc3c8f1cd924f9172def9",
|
"hash": "ac333d7bea1d61865bebebb116201a58db431946aa2f11aa042ef5795c390ff30af4d6c90ed3b3d24443a1d430703b08f14fc13b2fa405c155a241456ed78a47",
|
||||||
"git_version": "7.22",
|
"git_version": "7.33.2"
|
||||||
"bundled": true,
|
|
||||||
"skip_updates": true
|
|
||||||
},
|
},
|
||||||
"oaknut": {
|
"oaknut": {
|
||||||
"repo": "eden-emulator/oaknut",
|
"repo": "eden-emulator/oaknut",
|
||||||
@@ -161,7 +150,7 @@
|
|||||||
"package": "SDL2",
|
"package": "SDL2",
|
||||||
"name": "SDL2",
|
"name": "SDL2",
|
||||||
"repo": "crueter-ci/SDL2",
|
"repo": "crueter-ci/SDL2",
|
||||||
"version": "2.32.10-a65111bd2d",
|
"version": "2.32.10-cf5dabd6ea",
|
||||||
"min_version": "2.26.4"
|
"min_version": "2.26.4"
|
||||||
},
|
},
|
||||||
"catch2": {
|
"catch2": {
|
||||||
@@ -195,7 +184,6 @@
|
|||||||
"repo": "libsdl-org/SDL",
|
"repo": "libsdl-org/SDL",
|
||||||
"tag": "release-%VERSION%",
|
"tag": "release-%VERSION%",
|
||||||
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
|
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
|
||||||
"key": "generic",
|
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"git_version": "2.32.10",
|
"git_version": "2.32.10",
|
||||||
"skip_updates": true
|
"skip_updates": true
|
||||||
@@ -205,7 +193,6 @@
|
|||||||
"repo": "libsdl-org/SDL",
|
"repo": "libsdl-org/SDL",
|
||||||
"sha": "cc016b0046",
|
"sha": "cc016b0046",
|
||||||
"hash": "b8d9873446cdb922387471df9968e078714683046674ef0d0edddf8e25da65a539a3bae83d635496b970237f90b07b36a69f8d7855d450de59311d6d6e8c3dbc",
|
"hash": "b8d9873446cdb922387471df9968e078714683046674ef0d0edddf8e25da65a539a3bae83d635496b970237f90b07b36a69f8d7855d450de59311d6d6e8c3dbc",
|
||||||
"key": "steamdeck",
|
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"skip_updates": "true"
|
"skip_updates": "true"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -203,6 +203,24 @@ object NativeLibrary {
|
|||||||
|
|
||||||
external fun getDebugKnobAt(index: Int): Boolean
|
external fun getDebugKnobAt(index: Int): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current speed limit to the configured turbo speed.
|
||||||
|
*/
|
||||||
|
external fun setTurboSpeedLimit(enabled: Boolean)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current speed limit to the configured slow speed.
|
||||||
|
*/
|
||||||
|
external fun setSlowSpeedLimit(enabled: Boolean)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current speed limit to the configured standard speed.
|
||||||
|
*/
|
||||||
|
external fun setStandardSpeedLimit(enabled: Boolean)
|
||||||
|
|
||||||
|
external fun isTurboMode(): Boolean
|
||||||
|
external fun isSlowMode(): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns Vulkan driver version / API version / GPU model
|
* Returns Vulkan driver version / API version / GPU model
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import android.widget.RadioGroup
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
|
import com.google.android.material.materialswitch.MaterialSwitch
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
@@ -135,6 +136,39 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
container.addView(itemView)
|
container.addView(itemView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addCustomToggle(
|
||||||
|
name: Int,
|
||||||
|
isChecked: Boolean,
|
||||||
|
isEnabled: Boolean,
|
||||||
|
|
||||||
|
container: ViewGroup,
|
||||||
|
callback: (Boolean) -> Unit
|
||||||
|
): MaterialSwitch? {
|
||||||
|
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||||
|
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
||||||
|
|
||||||
|
val switchContainer = itemView.findViewById<ViewGroup>(R.id.switch_container)
|
||||||
|
val titleView = itemView.findViewById<TextView>(R.id.switch_title)
|
||||||
|
val switchView = itemView.findViewById<MaterialSwitch>(R.id.setting_switch)
|
||||||
|
|
||||||
|
titleView.text = YuzuApplication.appContext.getString(name)
|
||||||
|
switchContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
switchView.isChecked = isChecked
|
||||||
|
|
||||||
|
switchView.setOnCheckedChangeListener { _, checked ->
|
||||||
|
callback(checked)
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
switchContainer.setOnClickListener {
|
||||||
|
switchView.toggle()
|
||||||
|
}
|
||||||
|
container.addView(itemView)
|
||||||
|
|
||||||
|
return switchView
|
||||||
|
}
|
||||||
|
|
||||||
fun addSliderSetting(
|
fun addSliderSetting(
|
||||||
name: Int,
|
name: Int,
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_PROVOKING_VERTEX("provoking_vertex"),
|
RENDERER_PROVOKING_VERTEX("provoking_vertex"),
|
||||||
RENDERER_DESCRIPTOR_INDEXING("descriptor_indexing"),
|
RENDERER_DESCRIPTOR_INDEXING("descriptor_indexing"),
|
||||||
RENDERER_SAMPLE_SHADING("sample_shading"),
|
RENDERER_SAMPLE_SHADING("sample_shading"),
|
||||||
|
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
|
||||||
PICTURE_IN_PICTURE("picture_in_picture"),
|
PICTURE_IN_PICTURE("picture_in_picture"),
|
||||||
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
||||||
BLACK_BACKGROUNDS("black_backgrounds"),
|
BLACK_BACKGROUNDS("black_backgrounds"),
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||||||
|
|
||||||
RENDERER_DYNA_STATE("dyna_state"),
|
RENDERER_DYNA_STATE("dyna_state"),
|
||||||
DMA_ACCURACY("dma_accuracy"),
|
DMA_ACCURACY("dma_accuracy"),
|
||||||
|
FRAME_PACING_MODE("frame_pacing_mode"),
|
||||||
AUDIO_OUTPUT_ENGINE("output_engine"),
|
AUDIO_OUTPUT_ENGINE("output_engine"),
|
||||||
MAX_ANISOTROPY("max_anisotropy"),
|
MAX_ANISOTROPY("max_anisotropy"),
|
||||||
THEME("theme"),
|
THEME("theme"),
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,7 +9,10 @@ package org.yuzu.yuzu_emu.features.settings.model
|
|||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
|
||||||
enum class ShortSetting(override val key: String) : AbstractShortSetting {
|
enum class ShortSetting(override val key: String) : AbstractShortSetting {
|
||||||
RENDERER_SPEED_LIMIT("speed_limit");
|
RENDERER_SPEED_LIMIT("speed_limit"),
|
||||||
|
RENDERER_TURBO_SPEED_LIMIT("turbo_speed_limit"),
|
||||||
|
RENDERER_SLOW_SPEED_LIMIT("slow_speed_limit"),
|
||||||
|
;
|
||||||
|
|
||||||
override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal)
|
override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||||
|
|
||||||
|
import androidx.annotation.ArrayRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
|
|
||||||
|
class GpuUnswizzleSetting(
|
||||||
|
@StringRes titleId: Int = 0,
|
||||||
|
titleString: String = "",
|
||||||
|
@StringRes descriptionId: Int = 0,
|
||||||
|
descriptionString: String = "",
|
||||||
|
@ArrayRes val textureSizeChoicesId: Int,
|
||||||
|
@ArrayRes val textureSizeValuesId: Int,
|
||||||
|
@ArrayRes val streamSizeChoicesId: Int,
|
||||||
|
@ArrayRes val streamSizeValuesId: Int,
|
||||||
|
@ArrayRes val chunkSizeChoicesId: Int,
|
||||||
|
@ArrayRes val chunkSizeValuesId: Int
|
||||||
|
) : SettingsItem(
|
||||||
|
object : AbstractSetting {
|
||||||
|
override val key: String = SettingsItem.GPU_UNSWIZZLE_COMBINED
|
||||||
|
override val defaultValue: Any = false
|
||||||
|
override val isSaveable = true
|
||||||
|
override val isRuntimeModifiable = true
|
||||||
|
override val isSwitchable = true
|
||||||
|
override fun getValueAsString(needsGlobal: Boolean): String = "combined"
|
||||||
|
override fun reset() {
|
||||||
|
BooleanSetting.GPU_UNSWIZZLE_ENABLED.reset()
|
||||||
|
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.reset()
|
||||||
|
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.reset()
|
||||||
|
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.reset()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
titleId,
|
||||||
|
titleString,
|
||||||
|
descriptionId,
|
||||||
|
descriptionString
|
||||||
|
) {
|
||||||
|
override val type = SettingsItem.TYPE_GPU_UNSWIZZLE
|
||||||
|
|
||||||
|
// Check if GPU unswizzle is enabled via the dedicated boolean setting
|
||||||
|
fun isEnabled(needsGlobal: Boolean = false): Boolean =
|
||||||
|
BooleanSetting.GPU_UNSWIZZLE_ENABLED.getBoolean(needsGlobal)
|
||||||
|
|
||||||
|
fun setEnabled(value: Boolean) =
|
||||||
|
BooleanSetting.GPU_UNSWIZZLE_ENABLED.setBoolean(value)
|
||||||
|
|
||||||
|
fun enable() = setEnabled(true)
|
||||||
|
|
||||||
|
fun disable() = setEnabled(false)
|
||||||
|
|
||||||
|
fun getTextureSize(needsGlobal: Boolean = false): Int =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.getInt(needsGlobal)
|
||||||
|
|
||||||
|
fun setTextureSize(value: Int) =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.setInt(value)
|
||||||
|
|
||||||
|
fun getStreamSize(needsGlobal: Boolean = false): Int =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.getInt(needsGlobal)
|
||||||
|
|
||||||
|
fun setStreamSize(value: Int) =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.setInt(value)
|
||||||
|
|
||||||
|
fun getChunkSize(needsGlobal: Boolean = false): Int =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.getInt(needsGlobal)
|
||||||
|
|
||||||
|
fun setChunkSize(value: Int) =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.setInt(value)
|
||||||
|
|
||||||
|
fun reset() = setting.reset()
|
||||||
|
}
|
||||||
@@ -104,8 +104,10 @@ abstract class SettingsItem(
|
|||||||
const val TYPE_SPINBOX = 12
|
const val TYPE_SPINBOX = 12
|
||||||
const val TYPE_LAUNCHABLE = 13
|
const val TYPE_LAUNCHABLE = 13
|
||||||
const val TYPE_PATH = 14
|
const val TYPE_PATH = 14
|
||||||
|
const val TYPE_GPU_UNSWIZZLE = 15
|
||||||
|
|
||||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||||
|
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
|
||||||
|
|
||||||
val emptySetting = object : AbstractSetting {
|
val emptySetting = object : AbstractSetting {
|
||||||
override val key: String = ""
|
override val key: String = ""
|
||||||
@@ -178,6 +180,26 @@ abstract class SettingsItem(
|
|||||||
units = "%"
|
units = "%"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SliderSetting(
|
||||||
|
ShortSetting.RENDERER_TURBO_SPEED_LIMIT,
|
||||||
|
titleId = R.string.turbo_speed_limit,
|
||||||
|
descriptionId = R.string.turbo_speed_limit_description,
|
||||||
|
min = 1,
|
||||||
|
max = 400,
|
||||||
|
units = "%"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
put(
|
||||||
|
SliderSetting(
|
||||||
|
ShortSetting.RENDERER_SLOW_SPEED_LIMIT,
|
||||||
|
titleId = R.string.slow_speed_limit,
|
||||||
|
descriptionId = R.string.slow_speed_limit_description,
|
||||||
|
min = 1,
|
||||||
|
max = 400,
|
||||||
|
units = "%"
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.CPU_BACKEND,
|
IntSetting.CPU_BACKEND,
|
||||||
@@ -641,6 +663,15 @@ abstract class SettingsItem(
|
|||||||
valuesId = R.array.dmaAccuracyValues
|
valuesId = R.array.dmaAccuracyValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SingleChoiceSetting(
|
||||||
|
IntSetting.FRAME_PACING_MODE,
|
||||||
|
titleId = R.string.frame_pacing_mode,
|
||||||
|
descriptionId = R.string.frame_pacing_mode_description,
|
||||||
|
choicesId = R.array.framePacingModeNames,
|
||||||
|
valuesId = R.array.framePacingModeValues
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
|
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
|
||||||
@@ -684,6 +715,18 @@ abstract class SettingsItem(
|
|||||||
valuesId = R.array.gpuSwizzleChunkValues
|
valuesId = R.array.gpuSwizzleChunkValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
GpuUnswizzleSetting(
|
||||||
|
titleId = R.string.gpu_unswizzle_settings,
|
||||||
|
descriptionId = R.string.gpu_unswizzle_settings_description,
|
||||||
|
textureSizeChoicesId = R.array.gpuTextureSizeSwizzleEntries,
|
||||||
|
textureSizeValuesId = R.array.gpuTextureSizeSwizzleValues,
|
||||||
|
streamSizeChoicesId = R.array.gpuSwizzleEntries,
|
||||||
|
streamSizeValuesId = R.array.gpuSwizzleValues,
|
||||||
|
chunkSizeChoicesId = R.array.gpuSwizzleChunkEntries,
|
||||||
|
chunkSizeValuesId = R.array.gpuSwizzleChunkValues
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.FAST_CPU_TIME,
|
IntSetting.FAST_CPU_TIME,
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.databinding.DialogGpuUnswizzleBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.GpuUnswizzleSetting
|
||||||
|
|
||||||
|
class GpuUnswizzleDialogFragment : DialogFragment() {
|
||||||
|
private var position = 0
|
||||||
|
private val settingsViewModel: SettingsViewModel by activityViewModels()
|
||||||
|
private lateinit var binding: DialogGpuUnswizzleBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
position = requireArguments().getInt(POSITION)
|
||||||
|
|
||||||
|
if (settingsViewModel.clickedItem == null) dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
binding = DialogGpuUnswizzleBinding.inflate(LayoutInflater.from(requireContext()))
|
||||||
|
val item = settingsViewModel.clickedItem as GpuUnswizzleSetting
|
||||||
|
|
||||||
|
// Setup texture size dropdown
|
||||||
|
val textureSizeEntries = resources.getStringArray(item.textureSizeChoicesId)
|
||||||
|
val textureSizeValues = resources.getIntArray(item.textureSizeValuesId)
|
||||||
|
val textureSizeAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
textureSizeEntries.toMutableList()
|
||||||
|
)
|
||||||
|
binding.dropdownTextureSize.setAdapter(textureSizeAdapter)
|
||||||
|
|
||||||
|
// Setup stream size dropdown
|
||||||
|
val streamSizeEntries = resources.getStringArray(item.streamSizeChoicesId)
|
||||||
|
val streamSizeValues = resources.getIntArray(item.streamSizeValuesId)
|
||||||
|
val streamSizeAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
streamSizeEntries.toMutableList()
|
||||||
|
)
|
||||||
|
binding.dropdownStreamSize.setAdapter(streamSizeAdapter)
|
||||||
|
|
||||||
|
// Setup chunk size dropdown
|
||||||
|
val chunkSizeEntries = resources.getStringArray(item.chunkSizeChoicesId)
|
||||||
|
val chunkSizeValues = resources.getIntArray(item.chunkSizeValuesId)
|
||||||
|
val chunkSizeAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
chunkSizeEntries.toMutableList()
|
||||||
|
)
|
||||||
|
binding.dropdownChunkSize.setAdapter(chunkSizeAdapter)
|
||||||
|
|
||||||
|
// Load current values
|
||||||
|
val isEnabled = item.isEnabled()
|
||||||
|
binding.switchEnable.isChecked = isEnabled
|
||||||
|
|
||||||
|
if (isEnabled) {
|
||||||
|
val textureSizeIndex = textureSizeValues.indexOf(item.getTextureSize())
|
||||||
|
if (textureSizeIndex >= 0) {
|
||||||
|
binding.dropdownTextureSize.setText(textureSizeEntries[textureSizeIndex], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val streamSizeIndex = streamSizeValues.indexOf(item.getStreamSize())
|
||||||
|
if (streamSizeIndex >= 0) {
|
||||||
|
binding.dropdownStreamSize.setText(streamSizeEntries[streamSizeIndex], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val chunkSizeIndex = chunkSizeValues.indexOf(item.getChunkSize())
|
||||||
|
if (chunkSizeIndex >= 0) {
|
||||||
|
binding.dropdownChunkSize.setText(chunkSizeEntries[chunkSizeIndex], false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set default/recommended values when disabling
|
||||||
|
binding.dropdownTextureSize.setText(textureSizeEntries[3], false)
|
||||||
|
binding.dropdownStreamSize.setText(streamSizeEntries[3], false)
|
||||||
|
binding.dropdownChunkSize.setText(chunkSizeEntries[3], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear adapter filters after setText to fix rotation bug
|
||||||
|
textureSizeAdapter.filter.filter(null)
|
||||||
|
streamSizeAdapter.filter.filter(null)
|
||||||
|
chunkSizeAdapter.filter.filter(null)
|
||||||
|
|
||||||
|
// Enable/disable dropdowns based on switch state
|
||||||
|
updateDropdownsState(isEnabled)
|
||||||
|
binding.switchEnable.setOnCheckedChangeListener { _, checked ->
|
||||||
|
updateDropdownsState(checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle(item.title)
|
||||||
|
.setView(binding.root)
|
||||||
|
.create()
|
||||||
|
|
||||||
|
// Setup button listeners
|
||||||
|
binding.btnDefault.setOnClickListener {
|
||||||
|
// Reset to defaults
|
||||||
|
item.reset()
|
||||||
|
// Refresh values with adapters reset
|
||||||
|
val textureSizeIndex = textureSizeValues.indexOf(item.getTextureSize())
|
||||||
|
if (textureSizeIndex >= 0) {
|
||||||
|
binding.dropdownTextureSize.setText(textureSizeEntries[textureSizeIndex], false)
|
||||||
|
}
|
||||||
|
val streamSizeIndex = streamSizeValues.indexOf(item.getStreamSize())
|
||||||
|
if (streamSizeIndex >= 0) {
|
||||||
|
binding.dropdownStreamSize.setText(streamSizeEntries[streamSizeIndex], false)
|
||||||
|
}
|
||||||
|
val chunkSizeIndex = chunkSizeValues.indexOf(item.getChunkSize())
|
||||||
|
if (chunkSizeIndex >= 0) {
|
||||||
|
binding.dropdownChunkSize.setText(chunkSizeEntries[chunkSizeIndex], false)
|
||||||
|
}
|
||||||
|
// Clear filters
|
||||||
|
textureSizeAdapter.filter.filter(null)
|
||||||
|
streamSizeAdapter.filter.filter(null)
|
||||||
|
chunkSizeAdapter.filter.filter(null)
|
||||||
|
|
||||||
|
settingsViewModel.setAdapterItemChanged(position)
|
||||||
|
settingsViewModel.setShouldReloadSettingsList(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnCancel.setOnClickListener {
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnOk.setOnClickListener {
|
||||||
|
if (binding.switchEnable.isChecked) {
|
||||||
|
item.enable()
|
||||||
|
// Save the selected values
|
||||||
|
val selectedTextureIndex = textureSizeEntries.indexOf(
|
||||||
|
binding.dropdownTextureSize.text.toString()
|
||||||
|
)
|
||||||
|
if (selectedTextureIndex >= 0) {
|
||||||
|
item.setTextureSize(textureSizeValues[selectedTextureIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
val selectedStreamIndex = streamSizeEntries.indexOf(
|
||||||
|
binding.dropdownStreamSize.text.toString()
|
||||||
|
)
|
||||||
|
if (selectedStreamIndex >= 0) {
|
||||||
|
item.setStreamSize(streamSizeValues[selectedStreamIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
val selectedChunkIndex = chunkSizeEntries.indexOf(
|
||||||
|
binding.dropdownChunkSize.text.toString()
|
||||||
|
)
|
||||||
|
if (selectedChunkIndex >= 0) {
|
||||||
|
item.setChunkSize(chunkSizeValues[selectedChunkIndex])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Disable GPU unswizzle
|
||||||
|
item.disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsViewModel.setAdapterItemChanged(position)
|
||||||
|
settingsViewModel.setShouldReloadSettingsList(true)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure filters are cleared after dialog is shown
|
||||||
|
binding.root.post {
|
||||||
|
textureSizeAdapter.filter.filter(null)
|
||||||
|
streamSizeAdapter.filter.filter(null)
|
||||||
|
chunkSizeAdapter.filter.filter(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateDropdownsState(enabled: Boolean) {
|
||||||
|
binding.layoutTextureSize.isEnabled = enabled
|
||||||
|
binding.dropdownTextureSize.isEnabled = enabled
|
||||||
|
binding.layoutStreamSize.isEnabled = enabled
|
||||||
|
binding.dropdownStreamSize.isEnabled = enabled
|
||||||
|
binding.layoutChunkSize.isEnabled = enabled
|
||||||
|
binding.dropdownChunkSize.isEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "GpuUnswizzleDialogFragment"
|
||||||
|
const val POSITION = "Position"
|
||||||
|
|
||||||
|
fun newInstance(
|
||||||
|
settingsViewModel: SettingsViewModel,
|
||||||
|
item: GpuUnswizzleSetting,
|
||||||
|
position: Int
|
||||||
|
): GpuUnswizzleDialogFragment {
|
||||||
|
val dialog = GpuUnswizzleDialogFragment()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putInt(POSITION, position)
|
||||||
|
dialog.arguments = args
|
||||||
|
settingsViewModel.clickedItem = item
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.ui
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
@@ -101,6 +101,11 @@ class SettingsAdapter(
|
|||||||
SettingsItem.TYPE_PATH -> {
|
SettingsItem.TYPE_PATH -> {
|
||||||
PathViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
PathViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsItem.TYPE_GPU_UNSWIZZLE -> {
|
||||||
|
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
@@ -474,6 +479,14 @@ class SettingsAdapter(
|
|||||||
settingsViewModel.setShouldShowPathResetDialog(true)
|
settingsViewModel.setShouldShowPathResetDialog(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onGpuUnswizzleClick(item: GpuUnswizzleSetting, position: Int) {
|
||||||
|
GpuUnswizzleDialogFragment.newInstance(
|
||||||
|
settingsViewModel,
|
||||||
|
item,
|
||||||
|
position
|
||||||
|
).show(fragment.childFragmentManager, GpuUnswizzleDialogFragment.TAG)
|
||||||
|
}
|
||||||
|
|
||||||
private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
|
private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
|
||||||
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
|
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
|
||||||
return oldItem.setting.key == newItem.setting.key
|
return oldItem.setting.key == newItem.setting.key
|
||||||
|
|||||||
@@ -227,6 +227,8 @@ class SettingsFragmentPresenter(
|
|||||||
add(StringSetting.DEVICE_NAME.key)
|
add(StringSetting.DEVICE_NAME.key)
|
||||||
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
||||||
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
||||||
|
add(ShortSetting.RENDERER_TURBO_SPEED_LIMIT.key)
|
||||||
|
add(ShortSetting.RENDERER_SLOW_SPEED_LIMIT.key)
|
||||||
add(BooleanSetting.USE_DOCKED_MODE.key)
|
add(BooleanSetting.USE_DOCKED_MODE.key)
|
||||||
add(IntSetting.REGION_INDEX.key)
|
add(IntSetting.REGION_INDEX.key)
|
||||||
add(IntSetting.LANGUAGE_INDEX.key)
|
add(IntSetting.LANGUAGE_INDEX.key)
|
||||||
@@ -265,6 +267,7 @@ class SettingsFragmentPresenter(
|
|||||||
|
|
||||||
add(IntSetting.RENDERER_ACCURACY.key)
|
add(IntSetting.RENDERER_ACCURACY.key)
|
||||||
add(IntSetting.DMA_ACCURACY.key)
|
add(IntSetting.DMA_ACCURACY.key)
|
||||||
|
add(IntSetting.FRAME_PACING_MODE.key)
|
||||||
add(IntSetting.MAX_ANISOTROPY.key)
|
add(IntSetting.MAX_ANISOTROPY.key)
|
||||||
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
|
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
|
||||||
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
|
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
|
||||||
@@ -282,9 +285,7 @@ class SettingsFragmentPresenter(
|
|||||||
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
||||||
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
||||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||||
add(IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.key)
|
add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
|
||||||
add(IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.key)
|
|
||||||
add(IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.key)
|
|
||||||
|
|
||||||
add(HeaderSetting(R.string.extensions))
|
add(HeaderSetting(R.string.extensions))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.GpuUnswizzleSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
|
class GpuUnswizzleViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||||
|
SettingViewHolder(binding.root, adapter) {
|
||||||
|
private lateinit var setting: GpuUnswizzleSetting
|
||||||
|
|
||||||
|
override fun bind(item: SettingsItem) {
|
||||||
|
setting = item as GpuUnswizzleSetting
|
||||||
|
binding.textSettingName.text = setting.title
|
||||||
|
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
|
||||||
|
binding.textSettingDescription.text = item.description
|
||||||
|
|
||||||
|
binding.textSettingValue.setVisible(true)
|
||||||
|
val resMgr = binding.root.context.resources
|
||||||
|
|
||||||
|
if (setting.isEnabled()) {
|
||||||
|
// Show a summary of current settings
|
||||||
|
val textureSizeEntries = resMgr.getStringArray(setting.textureSizeChoicesId)
|
||||||
|
val textureSizeValues = resMgr.getIntArray(setting.textureSizeValuesId)
|
||||||
|
val textureSizeIndex = textureSizeValues.indexOf(setting.getTextureSize())
|
||||||
|
val textureSizeLabel = if (textureSizeIndex >= 0) textureSizeEntries[textureSizeIndex] else "?"
|
||||||
|
|
||||||
|
val streamSizeEntries = resMgr.getStringArray(setting.streamSizeChoicesId)
|
||||||
|
val streamSizeValues = resMgr.getIntArray(setting.streamSizeValuesId)
|
||||||
|
val streamSizeIndex = streamSizeValues.indexOf(setting.getStreamSize())
|
||||||
|
val streamSizeLabel = if (streamSizeIndex >= 0) streamSizeEntries[streamSizeIndex] else "?"
|
||||||
|
|
||||||
|
val chunkSizeEntries = resMgr.getStringArray(setting.chunkSizeChoicesId)
|
||||||
|
val chunkSizeValues = resMgr.getIntArray(setting.chunkSizeValuesId)
|
||||||
|
val chunkSizeIndex = chunkSizeValues.indexOf(setting.getChunkSize())
|
||||||
|
val chunkSizeLabel = if (chunkSizeIndex >= 0) chunkSizeEntries[chunkSizeIndex] else "?"
|
||||||
|
|
||||||
|
binding.textSettingValue.text = "$textureSizeLabel ⋅ $streamSizeLabel ⋅ $chunkSizeLabel"
|
||||||
|
} else {
|
||||||
|
binding.textSettingValue.text = resMgr.getString(R.string.gpu_unswizzle_disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.buttonClear.setVisible(setting.clearable)
|
||||||
|
binding.buttonClear.setOnClickListener {
|
||||||
|
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyle(setting.isEditable, binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(clicked: View) {
|
||||||
|
if (!setting.isEditable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.onGpuUnswizzleClick(setting, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLongClick(clicked: View): Boolean {
|
||||||
|
if (setting.isEditable) {
|
||||||
|
return adapter.onLongClick(setting, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,7 @@ import androidx.window.layout.WindowInfoTracker
|
|||||||
import androidx.window.layout.WindowLayoutInfo
|
import androidx.window.layout.WindowLayoutInfo
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.materialswitch.MaterialSwitch
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -1055,11 +1056,47 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
quickSettings.addPerGameConfigStatusIndicator(container)
|
quickSettings.addPerGameConfigStatusIndicator(container)
|
||||||
}
|
}
|
||||||
|
|
||||||
quickSettings.addBooleanSetting(
|
lateinit var slowSpeed: MaterialSwitch
|
||||||
|
lateinit var turboSpeed: MaterialSwitch
|
||||||
|
|
||||||
|
turboSpeed = quickSettings.addCustomToggle(
|
||||||
|
R.string.turbo_speed_limit,
|
||||||
|
NativeLibrary.isTurboMode(),
|
||||||
|
BooleanSetting.RENDERER_USE_SPEED_LIMIT.getBoolean(false),
|
||||||
|
container
|
||||||
|
) { enabled ->
|
||||||
|
if (enabled)
|
||||||
|
slowSpeed.isChecked = false
|
||||||
|
NativeLibrary.setTurboSpeedLimit(enabled)
|
||||||
|
}!!
|
||||||
|
|
||||||
|
slowSpeed = quickSettings.addCustomToggle(
|
||||||
|
R.string.slow_speed_limit,
|
||||||
|
NativeLibrary.isSlowMode(),
|
||||||
|
BooleanSetting.RENDERER_USE_SPEED_LIMIT.getBoolean(false),
|
||||||
|
container
|
||||||
|
) { enabled ->
|
||||||
|
if (enabled)
|
||||||
|
turboSpeed.isChecked = false
|
||||||
|
NativeLibrary.setSlowSpeedLimit(enabled)
|
||||||
|
}!!
|
||||||
|
|
||||||
|
quickSettings.addCustomToggle(
|
||||||
R.string.frame_limit_enable,
|
R.string.frame_limit_enable,
|
||||||
container,
|
BooleanSetting.RENDERER_USE_SPEED_LIMIT.getBoolean(false),
|
||||||
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
true,
|
||||||
)
|
container
|
||||||
|
) { enabled ->
|
||||||
|
if (!enabled) {
|
||||||
|
turboSpeed.isChecked = false
|
||||||
|
slowSpeed.isChecked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
turboSpeed.isEnabled = enabled
|
||||||
|
slowSpeed.isEnabled = enabled
|
||||||
|
|
||||||
|
NativeLibrary.setStandardSpeedLimit(enabled)
|
||||||
|
}!!
|
||||||
|
|
||||||
quickSettings.addSliderSetting(
|
quickSettings.addSliderSetting(
|
||||||
R.string.frame_limit_slider,
|
R.string.frame_limit_slider,
|
||||||
|
|||||||
@@ -1233,6 +1233,39 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_getDebugKnobAt(JNIEnv* env, jobje
|
|||||||
return static_cast<jboolean>(Settings::getDebugKnobAt(static_cast<u8>(index)));
|
return static_cast<jboolean>(Settings::getDebugKnobAt(static_cast<u8>(index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setTurboSpeedLimit(JNIEnv *env, jobject jobj, jboolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
Settings::values.use_speed_limit.SetValue(true);
|
||||||
|
Settings::SetSpeedMode(Settings::SpeedMode::Turbo);
|
||||||
|
} else {
|
||||||
|
Settings::SetSpeedMode(Settings::SpeedMode::Standard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setSlowSpeedLimit(JNIEnv *env, jobject jobj, jboolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
Settings::values.use_speed_limit.SetValue(true);
|
||||||
|
Settings::SetSpeedMode(Settings::SpeedMode::Slow);
|
||||||
|
} else {
|
||||||
|
Settings::SetSpeedMode(Settings::SpeedMode::Standard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setStandardSpeedLimit(JNIEnv *env, jobject jobj, jboolean enabled) {
|
||||||
|
Settings::values.use_speed_limit.SetValue(enabled);
|
||||||
|
if (enabled) {
|
||||||
|
Settings::SetSpeedMode(Settings::SpeedMode::Standard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isTurboMode(JNIEnv *env, jobject jobj) {
|
||||||
|
return Settings::values.current_speed_mode.GetValue() == Settings::SpeedMode::Turbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isSlowMode(JNIEnv *env, jobject jobj) {
|
||||||
|
return Settings::values.current_speed_mode.GetValue() == Settings::SpeedMode::Slow;
|
||||||
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
|
||||||
jint j_program_index,
|
jint j_program_index,
|
||||||
jboolean j_frontend_initiated) {
|
jboolean j_frontend_initiated) {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 288 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 100 KiB |
@@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
android:id="@+id/switch_enable"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:text="@string/gpu_unswizzle_enable" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_texture_size"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:hint="@string/gpu_unswizzle_texture_size">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_texture_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_stream_size"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:hint="@string/gpu_unswizzle_stream_size">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_stream_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_chunk_size"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/gpu_unswizzle_chunk_size">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_chunk_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end"
|
||||||
|
android:spacing="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_default"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/gpu_unswizzle_default_button" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_cancel"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@android:string/cancel" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ok"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@android:string/ok" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 203 KiB |
@@ -530,6 +530,21 @@
|
|||||||
<item>2</item>
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
<string-array name="framePacingModeNames">
|
||||||
|
<item>@string/frame_pacing_mode_target_Auto</item>
|
||||||
|
<item>@string/frame_pacing_mode_target_30</item>
|
||||||
|
<item>@string/frame_pacing_mode_target_60</item>
|
||||||
|
<item>@string/frame_pacing_mode_target_120</item>
|
||||||
|
<item>@string/frame_pacing_mode_target_240</item>
|
||||||
|
</string-array>
|
||||||
|
<integer-array name="framePacingModeValues">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="appletEntries">
|
<string-array name="appletEntries">
|
||||||
<item>@string/applet_hle</item>
|
<item>@string/applet_hle</item>
|
||||||
<item>@string/applet_lle</item>
|
<item>@string/applet_lle</item>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#1F143C</color></resources>
|
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#e48cc9ff</color></resources>
|
||||||
|
|||||||
@@ -422,6 +422,10 @@
|
|||||||
<string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string>
|
<string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string>
|
||||||
<string name="frame_limit_slider">Limit speed percent</string>
|
<string name="frame_limit_slider">Limit speed percent</string>
|
||||||
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
|
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
|
||||||
|
<string name="turbo_speed_limit">Turbo speed</string>
|
||||||
|
<string name="turbo_speed_limit_description">When Turbo Mode is enabled, emulation will run at this speed.</string>
|
||||||
|
<string name="slow_speed_limit">Slow speed</string>
|
||||||
|
<string name="slow_speed_limit_description">When Slow Mode is enabled, emulation will run at this speed.</string>
|
||||||
<string name="cpu_backend">CPU backend</string>
|
<string name="cpu_backend">CPU backend</string>
|
||||||
<string name="cpu_accuracy">CPU accuracy</string>
|
<string name="cpu_accuracy">CPU accuracy</string>
|
||||||
<string name="value_with_units">%1$s%2$s</string>
|
<string name="value_with_units">%1$s%2$s</string>
|
||||||
@@ -473,6 +477,8 @@
|
|||||||
<string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string>
|
<string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string>
|
||||||
<string name="dma_accuracy">DMA Accuracy</string>
|
<string name="dma_accuracy">DMA Accuracy</string>
|
||||||
<string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string>
|
<string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string>
|
||||||
|
<string name="frame_pacing_mode">Frame Pacing Mode</string>
|
||||||
|
<string name="frame_pacing_mode_description">Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent.</string>
|
||||||
<string name="anisotropic_filtering">Anisotropic filtering</string>
|
<string name="anisotropic_filtering">Anisotropic filtering</string>
|
||||||
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
|
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
|
||||||
<string name="vram_usage_mode">VRAM Usage Mode</string>
|
<string name="vram_usage_mode">VRAM Usage Mode</string>
|
||||||
@@ -501,15 +507,20 @@
|
|||||||
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
||||||
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
||||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout</string>
|
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
||||||
|
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
||||||
|
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
|
||||||
|
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string>
|
||||||
|
<string name="gpu_unswizzle_disabled">Disabled</string>
|
||||||
<string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string>
|
<string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string>
|
||||||
<string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string>
|
<string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string>
|
||||||
<string name="gpu_unswizzle_stream_size">GPU Unswizzle Stream Size</string>
|
<string name="gpu_unswizzle_stream_size">GPU Unswizzle Stream Size</string>
|
||||||
<string name="gpu_unswizzle_stream_size_description">Sets the data limit per frame for unswizzling large textures. Higher values speed up texture loading at the cost of higher frame latency; lower values reduce GPU overhead but may cause visible texture pop-in.</string>
|
<string name="gpu_unswizzle_stream_size_description">Sets the data limit per frame for unswizzling large textures. Higher values speed up texture loading at the cost of higher frame latency; lower values reduce GPU overhead but may cause visible texture pop-in.</string>
|
||||||
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk Size</string>
|
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk Size</string>
|
||||||
<string name="gpu_unswizzle_chunk_size_description">Defines the number of depth slices processed per batch for 3D textures. Increasing this improves throughput efficiency on powerful GPUs but may cause stuttering or driver timeouts on weaker hardware.</string>
|
<string name="gpu_unswizzle_chunk_size_description">Defines the number of depth slices processed per batch for 3D textures. Increasing this improves throughput efficiency on powerful GPUs but may cause stuttering or driver timeouts on weaker hardware.</string>
|
||||||
|
<string name="gpu_unswizzle_default_button">Default</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="extensions">Extensions</string>
|
<string name="extensions">Extensions</string>
|
||||||
@@ -1023,6 +1034,13 @@
|
|||||||
<string name="dma_accuracy_unsafe">Unsafe</string>
|
<string name="dma_accuracy_unsafe">Unsafe</string>
|
||||||
<string name="dma_accuracy_safe">Safe</string>
|
<string name="dma_accuracy_safe">Safe</string>
|
||||||
|
|
||||||
|
<!-- Frame Pacing Mode -->
|
||||||
|
<string name="frame_pacing_mode_target_Auto">Auto</string>
|
||||||
|
<string name="frame_pacing_mode_target_30">30 FPS</string>
|
||||||
|
<string name="frame_pacing_mode_target_60">60 FPS</string>
|
||||||
|
<string name="frame_pacing_mode_target_120">120 FPS</string>
|
||||||
|
<string name="frame_pacing_mode_target_240">240 FPS</string>
|
||||||
|
|
||||||
<!-- ASTC Decoding Method Choices -->
|
<!-- ASTC Decoding Method Choices -->
|
||||||
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
||||||
<string name="accelerate_astc_gpu" translatable="false">GPU</string>
|
<string name="accelerate_astc_gpu" translatable="false">GPU</string>
|
||||||
|
|||||||
@@ -379,4 +379,52 @@ void SetConfiguringGlobal(bool is_global) {
|
|||||||
configuring_global = is_global;
|
configuring_global = is_global;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u16 SpeedLimit() {
|
||||||
|
switch (SpeedMode(values.current_speed_mode)) {
|
||||||
|
case SpeedMode::Standard:
|
||||||
|
return values.speed_limit.GetValue();
|
||||||
|
case SpeedMode::Turbo:
|
||||||
|
return values.turbo_speed_limit.GetValue();
|
||||||
|
case SpeedMode::Slow:
|
||||||
|
return values.slow_speed_limit.GetValue();
|
||||||
|
default:
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpeedMode(const SpeedMode& mode) {
|
||||||
|
values.current_speed_mode.SetValue(mode);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case SpeedMode::Turbo:
|
||||||
|
case SpeedMode::Slow:
|
||||||
|
values.use_speed_limit.SetValue(true);
|
||||||
|
break;
|
||||||
|
case SpeedMode::Standard:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleStandardMode() {
|
||||||
|
values.use_speed_limit.SetValue(!values.use_speed_limit.GetValue());
|
||||||
|
SetSpeedMode(SpeedMode::Standard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleTurboMode() {
|
||||||
|
if (values.current_speed_mode.GetValue() != SpeedMode::Turbo)
|
||||||
|
SetSpeedMode(SpeedMode::Turbo);
|
||||||
|
else
|
||||||
|
SetSpeedMode(SpeedMode::Standard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleSlowMode() {
|
||||||
|
if (values.current_speed_mode.GetValue() != SpeedMode::Slow)
|
||||||
|
SetSpeedMode(SpeedMode::Slow);
|
||||||
|
else
|
||||||
|
SetSpeedMode(SpeedMode::Standard);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Settings
|
} // namespace Settings
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ struct Values {
|
|||||||
true};
|
true};
|
||||||
SwitchableSetting<bool> use_speed_limit{
|
SwitchableSetting<bool> use_speed_limit{
|
||||||
linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, true, true};
|
linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, true, true};
|
||||||
|
|
||||||
SwitchableSetting<u16, true> speed_limit{linkage,
|
SwitchableSetting<u16, true> speed_limit{linkage,
|
||||||
100,
|
100,
|
||||||
0,
|
0,
|
||||||
@@ -214,6 +215,30 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
&use_speed_limit};
|
&use_speed_limit};
|
||||||
|
|
||||||
|
SwitchableSetting<u16, true> slow_speed_limit{linkage,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
9999,
|
||||||
|
"slow_speed_limit",
|
||||||
|
Category::Core,
|
||||||
|
Specialization::Countable | Specialization::Percentage,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
|
SwitchableSetting<u16, true> turbo_speed_limit{linkage,
|
||||||
|
200,
|
||||||
|
0,
|
||||||
|
9999,
|
||||||
|
"turbo_speed_limit",
|
||||||
|
Category::Core,
|
||||||
|
Specialization::Countable | Specialization::Percentage,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
|
// The currently used speed mode.
|
||||||
|
Setting<SpeedMode> current_speed_mode{linkage, SpeedMode::Standard, "current_speed_mode", Category::Core, Specialization::Default, false, true};
|
||||||
|
|
||||||
SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core,
|
SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core,
|
||||||
Specialization::Default};
|
Specialization::Default};
|
||||||
|
|
||||||
@@ -434,6 +459,13 @@ struct Values {
|
|||||||
"accelerate_astc",
|
"accelerate_astc",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
|
SwitchableSetting<FramePacingMode, true> frame_pacing_mode{linkage,
|
||||||
|
FramePacingMode::Target_Auto,
|
||||||
|
FramePacingMode::Target_Auto,
|
||||||
|
FramePacingMode::Target_240,
|
||||||
|
"frame_pacing_mode",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||||
AstcRecompression::Uncompressed,
|
AstcRecompression::Uncompressed,
|
||||||
"astc_recompression",
|
"astc_recompression",
|
||||||
@@ -532,14 +564,11 @@ struct Values {
|
|||||||
Category::RendererHacks,
|
Category::RendererHacks,
|
||||||
Specialization::Default};
|
Specialization::Default};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> gpu_unswizzle_enabled{linkage, false, "gpu_unswizzle_enabled",
|
||||||
|
Category::RendererHacks};
|
||||||
|
|
||||||
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
||||||
#if defined (_WIN32)
|
#if defined (ANDROID) || defined (__APPLE__)
|
||||||
ExtendedDynamicState::EDS3,
|
|
||||||
#elif defined (__FreeBSD__)
|
|
||||||
ExtendedDynamicState::EDS3,
|
|
||||||
#elif defined (ANDROID)
|
|
||||||
ExtendedDynamicState::Disabled,
|
|
||||||
#elif defined (__APPLE__)
|
|
||||||
ExtendedDynamicState::Disabled,
|
ExtendedDynamicState::Disabled,
|
||||||
#else
|
#else
|
||||||
ExtendedDynamicState::EDS2,
|
ExtendedDynamicState::EDS2,
|
||||||
@@ -814,6 +843,13 @@ bool IsDockedMode();
|
|||||||
|
|
||||||
float Volume();
|
float Volume();
|
||||||
|
|
||||||
|
// speed limit ops
|
||||||
|
u16 SpeedLimit();
|
||||||
|
void SetSpeedMode(const SpeedMode &mode);
|
||||||
|
void ToggleStandardMode();
|
||||||
|
void ToggleTurboMode();
|
||||||
|
void ToggleSlowMode();
|
||||||
|
|
||||||
std::string GetTimeZoneString(TimeZone time_zone);
|
std::string GetTimeZoneString(TimeZone time_zone);
|
||||||
|
|
||||||
void LogSettings();
|
void LogSettings();
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
|
|||||||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
|
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
|
||||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||||
|
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_120, Target_240);
|
||||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||||
@@ -156,6 +157,7 @@ ENUM(TemperatureUnits, Celsius, Fahrenheit)
|
|||||||
ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3);
|
ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3);
|
||||||
ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All)
|
ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All)
|
||||||
ENUM(GameListMode, TreeView, GridView);
|
ENUM(GameListMode, TreeView, GridView);
|
||||||
|
ENUM(SpeedMode, Standard, Turbo, Slow);
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
inline std::string_view CanonicalizeEnum(Type id) {
|
inline std::string_view CanonicalizeEnum(Type id) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -38,10 +38,16 @@ u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
|
|||||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||||
return m_memory.Read64(vaddr);
|
return m_memory.Read64(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||||
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return m_memory.Read32(vaddr);
|
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||||
|
if (last_code_addr != aligned_vaddr) {
|
||||||
|
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
|
||||||
|
last_code_addr = aligned_vaddr;
|
||||||
|
}
|
||||||
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <dynarmic/interface/A32/a32.h>
|
#include <dynarmic/interface/A32/a32.h>
|
||||||
|
#include <dynarmic/interface/code_page.h>
|
||||||
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
@@ -49,6 +50,9 @@ public:
|
|||||||
u64 GetTicksRemaining() override;
|
u64 GetTicksRemaining() override;
|
||||||
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
||||||
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
|
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
|
||||||
|
//
|
||||||
|
Dynarmic::CodePage cached_code_page;
|
||||||
|
u64 last_code_addr = 0;
|
||||||
ArmDynarmic32& m_parent;
|
ArmDynarmic32& m_parent;
|
||||||
Core::Memory::Memory& m_memory;
|
Core::Memory::Memory& m_memory;
|
||||||
Kernel::KProcess* m_process{};
|
Kernel::KProcess* m_process{};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -41,10 +41,17 @@ Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
|||||||
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
||||||
return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
|
return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
||||||
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return m_memory.Read32(vaddr);
|
// return m_memory.Read32(vaddr);
|
||||||
|
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||||
|
if (last_code_addr != aligned_vaddr) {
|
||||||
|
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
|
||||||
|
last_code_addr = aligned_vaddr;
|
||||||
|
}
|
||||||
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <ankerl/unordered_dense.h>
|
#include <ankerl/unordered_dense.h>
|
||||||
|
|
||||||
#include <dynarmic/interface/A64/a64.h>
|
#include <dynarmic/interface/A64/a64.h>
|
||||||
|
#include <dynarmic/interface/code_page.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
@@ -61,6 +62,8 @@ public:
|
|||||||
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
||||||
void ReturnException(u64 pc, Dynarmic::HaltReason hr);
|
void ReturnException(u64 pc, Dynarmic::HaltReason hr);
|
||||||
|
|
||||||
|
Dynarmic::CodePage cached_code_page;
|
||||||
|
u64 last_code_addr = 0;
|
||||||
ArmDynarmic64& m_parent;
|
ArmDynarmic64& m_parent;
|
||||||
Core::Memory::Memory& m_memory;
|
Core::Memory::Memory& m_memory;
|
||||||
u64 m_tpidrro_el0{};
|
u64 m_tpidrro_el0{};
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ u64 CoreTiming::GetClockTicks() const {
|
|||||||
|
|
||||||
if (Settings::values.sync_core_speed.GetValue()) {
|
if (Settings::values.sync_core_speed.GetValue()) {
|
||||||
const auto ticks = double(fres);
|
const auto ticks = double(fres);
|
||||||
const auto speed_limit = double(Settings::values.speed_limit.GetValue())*0.01;
|
const auto speed_limit = double(Settings::SpeedLimit())*0.01;
|
||||||
return u64(ticks/speed_limit);
|
return u64(ticks/speed_limit);
|
||||||
} else {
|
} else {
|
||||||
return fres;
|
return fres;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <boost/icl/interval_set.hpp>
|
#include <boost/icl/interval_set.hpp>
|
||||||
#include <dynarmic/interface/A64/a64.h>
|
#include <dynarmic/interface/A64/a64.h>
|
||||||
#include <dynarmic/interface/A64/config.h>
|
#include <dynarmic/interface/A64/config.h>
|
||||||
|
#include <dynarmic/interface/code_page.h>
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
@@ -46,6 +47,15 @@ public:
|
|||||||
: memory{memory_}, local_memory{local_memory_},
|
: memory{memory_}, local_memory{local_memory_},
|
||||||
mapped_ranges{mapped_ranges_}, parent{parent_} {}
|
mapped_ranges{mapped_ranges_}, parent{parent_} {}
|
||||||
|
|
||||||
|
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override {
|
||||||
|
static_assert(Core::Memory::YUZU_PAGESIZE == Dynarmic::CODE_PAGE_SIZE);
|
||||||
|
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||||
|
if (last_code_addr != aligned_vaddr) {
|
||||||
|
cached_code_page = ReadMemory<Dynarmic::CodePage>(aligned_vaddr);
|
||||||
|
last_code_addr = aligned_vaddr;
|
||||||
|
}
|
||||||
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
|
}
|
||||||
u8 MemoryRead8(u64 vaddr) override {
|
u8 MemoryRead8(u64 vaddr) override {
|
||||||
return ReadMemory<u8>(vaddr);
|
return ReadMemory<u8>(vaddr);
|
||||||
}
|
}
|
||||||
@@ -116,8 +126,7 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template<typename T> T ReadMemory(u64 vaddr) {
|
||||||
T ReadMemory(u64 vaddr) {
|
|
||||||
T ret{};
|
T ret{};
|
||||||
if (boost::icl::contains(mapped_ranges, vaddr)) {
|
if (boost::icl::contains(mapped_ranges, vaddr)) {
|
||||||
memory.ReadBlock(vaddr, &ret, sizeof(T));
|
memory.ReadBlock(vaddr, &ret, sizeof(T));
|
||||||
@@ -146,6 +155,9 @@ private:
|
|||||||
std::vector<u8>& local_memory;
|
std::vector<u8>& local_memory;
|
||||||
IntervalSet& mapped_ranges;
|
IntervalSet& mapped_ranges;
|
||||||
JITContextImpl& parent;
|
JITContextImpl& parent;
|
||||||
|
|
||||||
|
Dynarmic::CodePage cached_code_page;
|
||||||
|
u64 last_code_addr = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JITContextImpl {
|
class JITContextImpl {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -95,7 +95,7 @@ s64 Conductor::GetNextTicks() const {
|
|||||||
if (settings.use_speed_limit.GetValue()) {
|
if (settings.use_speed_limit.GetValue()) {
|
||||||
// Scales the speed based on speed_limit setting on MC. SC is handled by
|
// Scales the speed based on speed_limit setting on MC. SC is handled by
|
||||||
// SpeedLimiter::DoSpeedLimiting.
|
// SpeedLimiter::DoSpeedLimiting.
|
||||||
speed_scale = 100.f / settings.speed_limit.GetValue();
|
speed_scale = 100.f / Settings::SpeedLimit();
|
||||||
} else {
|
} else {
|
||||||
// Run at unlocked framerate.
|
// Run at unlocked framerate.
|
||||||
speed_scale = 0.01f;
|
speed_scale = 0.01f;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||||
@@ -36,8 +36,7 @@
|
|||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
|
|
||||||
static inline bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr,
|
static inline bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr, const std::size_t size) {
|
||||||
const std::size_t size) {
|
|
||||||
const Common::ProcessAddress max_addr = 1ULL << table.GetAddressSpaceBits();
|
const Common::ProcessAddress max_addr = 1ULL << table.GetAddressSpaceBits();
|
||||||
return addr + size >= addr && addr + size <= max_addr;
|
return addr + size >= addr && addr + size <= max_addr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
@@ -143,7 +143,7 @@ void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
|
|||||||
|
|
||||||
auto now = Clock::now();
|
auto now = Clock::now();
|
||||||
|
|
||||||
const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0;
|
const double sleep_scale = Settings::SpeedLimit() / 100.0;
|
||||||
|
|
||||||
// Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
|
// Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
|
||||||
// speed percent or it will clamp too much and prevent this from properly limiting to that
|
// speed percent or it will clamp too much and prevent this from properly limiting to that
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ add_library(dynarmic STATIC
|
|||||||
common/crypto/aes.h
|
common/crypto/aes.h
|
||||||
common/crypto/crc32.cpp
|
common/crypto/crc32.cpp
|
||||||
common/crypto/crc32.h
|
common/crypto/crc32.h
|
||||||
common/crypto/sm4.cpp
|
|
||||||
common/crypto/sm4.h
|
|
||||||
common/fp/fpcr.h
|
common/fp/fpcr.h
|
||||||
common/fp/fpsr.h
|
common/fp/fpsr.h
|
||||||
common/fp/fused.cpp
|
common/fp/fused.cpp
|
||||||
@@ -107,9 +105,6 @@ add_library(dynarmic STATIC
|
|||||||
frontend/A32/decoder/thumb32.inc
|
frontend/A32/decoder/thumb32.inc
|
||||||
frontend/A32/decoder/vfp.h
|
frontend/A32/decoder/vfp.h
|
||||||
frontend/A32/decoder/vfp.inc
|
frontend/A32/decoder/vfp.inc
|
||||||
frontend/A32/disassembler/disassembler.h
|
|
||||||
frontend/A32/disassembler/disassembler_arm.cpp
|
|
||||||
frontend/A32/disassembler/disassembler_thumb.cpp
|
|
||||||
frontend/A32/FPSCR.h
|
frontend/A32/FPSCR.h
|
||||||
frontend/A32/ITState.h
|
frontend/A32/ITState.h
|
||||||
frontend/A32/PSR.h
|
frontend/A32/PSR.h
|
||||||
@@ -124,7 +119,6 @@ add_library(dynarmic STATIC
|
|||||||
interface/A32/config.h
|
interface/A32/config.h
|
||||||
interface/A32/coprocessor.h
|
interface/A32/coprocessor.h
|
||||||
interface/A32/coprocessor_util.h
|
interface/A32/coprocessor_util.h
|
||||||
interface/A32/disassembler.h
|
|
||||||
# A64
|
# A64
|
||||||
frontend/A64/a64_ir_emitter.cpp
|
frontend/A64/a64_ir_emitter.cpp
|
||||||
frontend/A64/a64_ir_emitter.h
|
frontend/A64/a64_ir_emitter.h
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -164,10 +164,10 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
|
|||||||
EmitPrelude();
|
EmitPrelude();
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
ir_block.Reset(descriptor);
|
||||||
|
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
Optimization::Optimize(ir_block, conf, {});
|
||||||
return ir_block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32AddressSpace::InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges) {
|
void A32AddressSpace::InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2022 MerryMage
|
* Copyright (c) 2022 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
@@ -17,7 +20,7 @@ class A32AddressSpace final : public AddressSpace {
|
|||||||
public:
|
public:
|
||||||
explicit A32AddressSpace(const A32::UserConfig& conf);
|
explicit A32AddressSpace(const A32::UserConfig& conf);
|
||||||
|
|
||||||
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
void GenerateIR(IR::Block& ir_block, IR::LocationDescriptor) const override;
|
||||||
|
|
||||||
void InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges);
|
void InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -330,12 +330,11 @@ A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf)
|
|||||||
EmitPrelude();
|
EmitPrelude();
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block A64AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
void A64AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||||
|
ir_block.Reset(descriptor);
|
||||||
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
||||||
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{descriptor}, get_code,
|
A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
||||||
{conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
Optimization::Optimize(ir_block, conf, {});
|
||||||
return ir_block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64AddressSpace::InvalidateCacheRanges(const boost::icl::interval_set<u64>& ranges) {
|
void A64AddressSpace::InvalidateCacheRanges(const boost::icl::interval_set<u64>& ranges) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2022 MerryMage
|
* Copyright (c) 2022 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
@@ -17,7 +20,7 @@ class A64AddressSpace final : public AddressSpace {
|
|||||||
public:
|
public:
|
||||||
explicit A64AddressSpace(const A64::UserConfig& conf);
|
explicit A64AddressSpace(const A64::UserConfig& conf);
|
||||||
|
|
||||||
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
void GenerateIR(IR::Block& ir_block, IR::LocationDescriptor) const override;
|
||||||
|
|
||||||
void InvalidateCacheRanges(const boost::icl::interval_set<u64>& ranges);
|
void InvalidateCacheRanges(const boost::icl::interval_set<u64>& ranges);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -20,14 +20,17 @@
|
|||||||
#include "dynarmic/common/fp/fpcr.h"
|
#include "dynarmic/common/fp/fpcr.h"
|
||||||
#include "dynarmic/common/llvm_disassemble.h"
|
#include "dynarmic/common/llvm_disassemble.h"
|
||||||
#include "dynarmic/interface/exclusive_monitor.h"
|
#include "dynarmic/interface/exclusive_monitor.h"
|
||||||
|
#include "dynarmic/ir/location_descriptor.h"
|
||||||
|
|
||||||
namespace Dynarmic::Backend::Arm64 {
|
namespace Dynarmic::Backend::Arm64 {
|
||||||
|
|
||||||
AddressSpace::AddressSpace(size_t code_cache_size)
|
AddressSpace::AddressSpace(size_t code_cache_size)
|
||||||
: code_cache_size(code_cache_size)
|
: ir_block{IR::LocationDescriptor{0}}
|
||||||
, mem(code_cache_size)
|
, code_cache_size(code_cache_size)
|
||||||
, code(mem.ptr(), mem.ptr())
|
, mem(code_cache_size)
|
||||||
, fastmem_manager(exception_handler) {
|
, code(mem.ptr(), mem.ptr())
|
||||||
|
, fastmem_manager(exception_handler)
|
||||||
|
{
|
||||||
ASSERT(code_cache_size <= 128 * 1024 * 1024 && "code_cache_size > 128 MiB not currently supported");
|
ASSERT(code_cache_size <= 128 * 1024 * 1024 && "code_cache_size > 128 MiB not currently supported");
|
||||||
|
|
||||||
exception_handler.Register(mem, code_cache_size);
|
exception_handler.Register(mem, code_cache_size);
|
||||||
@@ -67,8 +70,7 @@ CodePtr AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) {
|
|||||||
if (CodePtr block_entry = Get(descriptor)) {
|
if (CodePtr block_entry = Get(descriptor)) {
|
||||||
return block_entry;
|
return block_entry;
|
||||||
}
|
}
|
||||||
|
GenerateIR(ir_block, descriptor);
|
||||||
IR::Block ir_block = GenerateIR(descriptor);
|
|
||||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
||||||
return block_info.entry_point;
|
return block_info.entry_point;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -29,7 +29,7 @@ public:
|
|||||||
explicit AddressSpace(size_t code_cache_size);
|
explicit AddressSpace(size_t code_cache_size);
|
||||||
virtual ~AddressSpace();
|
virtual ~AddressSpace();
|
||||||
|
|
||||||
virtual IR::Block GenerateIR(IR::LocationDescriptor) const = 0;
|
virtual void GenerateIR(IR::Block& ir_block, IR::LocationDescriptor) const = 0;
|
||||||
|
|
||||||
CodePtr Get(IR::LocationDescriptor descriptor);
|
CodePtr Get(IR::LocationDescriptor descriptor);
|
||||||
|
|
||||||
@@ -68,6 +68,7 @@ protected:
|
|||||||
|
|
||||||
FakeCall FastmemCallback(u64 host_pc);
|
FakeCall FastmemCallback(u64 host_pc);
|
||||||
|
|
||||||
|
IR::Block ir_block;
|
||||||
const size_t code_cache_size;
|
const size_t code_cache_size;
|
||||||
oaknut::CodeBlock mem;
|
oaknut::CodeBlock mem;
|
||||||
oaknut::CodeGenerator code;
|
oaknut::CodeGenerator code;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -26,10 +26,9 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
|
|||||||
EmitPrelude();
|
EmitPrelude();
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
Optimization::Optimize(ir_block, conf, {});
|
||||||
return ir_block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CodePtr A32AddressSpace::Get(IR::LocationDescriptor descriptor) {
|
CodePtr A32AddressSpace::Get(IR::LocationDescriptor descriptor) {
|
||||||
@@ -44,7 +43,8 @@ CodePtr A32AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) {
|
|||||||
return block_entry;
|
return block_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block ir_block = GenerateIR(descriptor);
|
IR::Block ir_block{descriptor};
|
||||||
|
GenerateIR(ir_block, descriptor);
|
||||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
||||||
|
|
||||||
block_infos.insert_or_assign(descriptor.Value(), block_info);
|
block_infos.insert_or_assign(descriptor.Value(), block_info);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2024 MerryMage
|
* Copyright (c) 2024 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
@@ -23,7 +26,7 @@ class A32AddressSpace final {
|
|||||||
public:
|
public:
|
||||||
explicit A32AddressSpace(const A32::UserConfig& conf);
|
explicit A32AddressSpace(const A32::UserConfig& conf);
|
||||||
|
|
||||||
IR::Block GenerateIR(IR::LocationDescriptor) const;
|
void GenerateIR(IR::Block& ir_block, IR::LocationDescriptor) const;
|
||||||
|
|
||||||
CodePtr Get(IR::LocationDescriptor descriptor);
|
CodePtr Get(IR::LocationDescriptor descriptor);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "dynarmic/backend/x64/devirtualize.h"
|
#include "dynarmic/backend/x64/devirtualize.h"
|
||||||
#include "dynarmic/backend/x64/jitstate_info.h"
|
#include "dynarmic/backend/x64/jitstate_info.h"
|
||||||
#include "dynarmic/common/atomic.h"
|
#include "dynarmic/common/atomic.h"
|
||||||
|
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
@@ -63,12 +64,13 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Jit::Impl {
|
struct Jit::Impl {
|
||||||
Impl(Jit* jit, A32::UserConfig conf)
|
Impl(Jit* jit, A32::UserConfig conf) noexcept
|
||||||
: block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
: block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
||||||
, emitter(block_of_code, conf, jit)
|
, emitter(block_of_code, conf, jit)
|
||||||
, polyfill_options(GenPolyfillOptions(block_of_code))
|
, polyfill_options(GenPolyfillOptions(block_of_code))
|
||||||
, conf(std::move(conf))
|
, conf(std::move(conf))
|
||||||
, jit_interface(jit) {}
|
, jit_interface(jit)
|
||||||
|
{}
|
||||||
|
|
||||||
~Impl() = default;
|
~Impl() = default;
|
||||||
|
|
||||||
@@ -201,8 +203,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
||||||
auto block = emitter.GetBasicBlock(descriptor);
|
if (auto block = emitter.GetBasicBlock(descriptor))
|
||||||
if (block)
|
|
||||||
return *block;
|
return *block;
|
||||||
|
|
||||||
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
||||||
@@ -212,7 +213,10 @@ private:
|
|||||||
}
|
}
|
||||||
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
|
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
|
||||||
|
|
||||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
// LocationDescriptor ctor() does important ops (like tflags) do not skip
|
||||||
|
auto const arch_descriptor = A32::LocationDescriptor{descriptor};
|
||||||
|
ir_block.Reset(arch_descriptor);
|
||||||
|
A32::Translate(ir_block, arch_descriptor, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||||
Optimization::Optimize(ir_block, conf, polyfill_options);
|
Optimization::Optimize(ir_block, conf, polyfill_options);
|
||||||
return emitter.Emit(ir_block);
|
return emitter.Emit(ir_block);
|
||||||
}
|
}
|
||||||
@@ -239,13 +243,13 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::Block ir_block = {LocationDescriptor(0, PSR(0), FPSCR(0), false)};
|
||||||
A32JitState jit_state;
|
A32JitState jit_state;
|
||||||
BlockOfCode block_of_code;
|
BlockOfCode block_of_code;
|
||||||
A32EmitX64 emitter;
|
A32EmitX64 emitter;
|
||||||
Optimization::PolyfillOptions polyfill_options;
|
Optimization::PolyfillOptions polyfill_options;
|
||||||
|
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
|
||||||
const A32::UserConfig conf;
|
const A32::UserConfig conf;
|
||||||
|
|
||||||
Jit* jit_interface;
|
Jit* jit_interface;
|
||||||
|
|
||||||
// Requests made during execution to invalidate the cache are queued up here.
|
// Requests made during execution to invalidate the cache are queued up here.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
#include <boost/icl/interval_set.hpp>
|
||||||
#include "dynarmic/common/assert.h"
|
#include "dynarmic/common/assert.h"
|
||||||
|
#include "dynarmic/common/fp/fpcr.h"
|
||||||
#include "dynarmic/common/llvm_disassemble.h"
|
#include "dynarmic/common/llvm_disassemble.h"
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <mcl/scope_exit.hpp>
|
#include <mcl/scope_exit.hpp>
|
||||||
@@ -61,10 +62,11 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
|
|||||||
struct Jit::Impl final {
|
struct Jit::Impl final {
|
||||||
public:
|
public:
|
||||||
Impl(Jit* jit, UserConfig conf)
|
Impl(Jit* jit, UserConfig conf)
|
||||||
: conf(conf)
|
: conf(conf)
|
||||||
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
||||||
, emitter(block_of_code, conf, jit)
|
, emitter(block_of_code, conf, jit)
|
||||||
, polyfill_options(GenPolyfillOptions(block_of_code)) {
|
, polyfill_options(GenPolyfillOptions(block_of_code))
|
||||||
|
{
|
||||||
ASSERT(conf.page_table_address_space_bits >= 12 && conf.page_table_address_space_bits <= 64);
|
ASSERT(conf.page_table_address_space_bits >= 12 && conf.page_table_address_space_bits <= 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,8 +256,8 @@ private:
|
|||||||
return GetBlock(A64::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true));
|
return GetBlock(A64::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
CodePtr GetBlock(IR::LocationDescriptor current_location) {
|
CodePtr GetBlock(IR::LocationDescriptor descriptor) {
|
||||||
if (auto block = emitter.GetBasicBlock(current_location))
|
if (auto block = emitter.GetBasicBlock(descriptor))
|
||||||
return block->entrypoint;
|
return block->entrypoint;
|
||||||
|
|
||||||
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
||||||
@@ -268,8 +270,10 @@ private:
|
|||||||
|
|
||||||
// JIT Compile
|
// JIT Compile
|
||||||
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
||||||
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, get_code,
|
// LocationDescriptor ctor() does important ops (like tflags) do not skip
|
||||||
{conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
auto const arch_descriptor = A64::LocationDescriptor{descriptor};
|
||||||
|
ir_block.Reset(arch_descriptor);
|
||||||
|
A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
||||||
Optimization::Optimize(ir_block, conf, polyfill_options);
|
Optimization::Optimize(ir_block, conf, polyfill_options);
|
||||||
return emitter.Emit(ir_block).entrypoint;
|
return emitter.Emit(ir_block).entrypoint;
|
||||||
}
|
}
|
||||||
@@ -296,14 +300,13 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_executing = false;
|
IR::Block ir_block = {LocationDescriptor(0, FP::FPCR(0), false)};
|
||||||
|
|
||||||
const UserConfig conf;
|
const UserConfig conf;
|
||||||
A64JitState jit_state;
|
A64JitState jit_state;
|
||||||
BlockOfCode block_of_code;
|
BlockOfCode block_of_code;
|
||||||
A64EmitX64 emitter;
|
A64EmitX64 emitter;
|
||||||
Optimization::PolyfillOptions polyfill_options;
|
Optimization::PolyfillOptions polyfill_options;
|
||||||
|
bool is_executing = false;
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
boost::icl::interval_set<u64> invalid_cache_ranges;
|
boost::icl::interval_set<u64> invalid_cache_ranges;
|
||||||
std::mutex invalidation_mutex;
|
std::mutex invalidation_mutex;
|
||||||
|
|||||||
@@ -71,11 +71,22 @@ void EmitX64::EmitBreakpoint(EmitContext&, IR::Inst*) {
|
|||||||
code.int3();
|
code.int3();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool IsWithin2G(uintptr_t ref, uintptr_t target) {
|
||||||
|
const u64 distance = target - (ref + 5);
|
||||||
|
return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitCallHostFunction(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitCallHostFunction(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
ctx.reg_alloc.HostCall(code, nullptr, args[1], args[2], args[3]);
|
ctx.reg_alloc.HostCall(code, nullptr, args[1], args[2], args[3]);
|
||||||
code.mov(rax, args[0].GetImmediateU64());
|
auto target = args[0].GetImmediateU64();
|
||||||
code.call(rax);
|
if (IsWithin2G(uintptr_t(code.getCurr()), target)) {
|
||||||
|
auto const f = std::bit_cast<void(*)(void)>(target);
|
||||||
|
code.call(f);
|
||||||
|
} else {
|
||||||
|
code.mov(rax, target);
|
||||||
|
code.call(rax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, IR::LocationDescriptor target) {
|
void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, IR::LocationDescriptor target) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -57,10 +57,9 @@ void EmitX64::EmitLeastSignificantWord(EmitContext& ctx, IR::Inst* inst) {
|
|||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
// TODO: DefineValue directly on Argument
|
// TODO: DefineValue directly on Argument
|
||||||
const Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr(code);
|
const Xbyak::Reg64 res = ctx.reg_alloc.UseScratchGpr(code, args[0]);
|
||||||
const Xbyak::Reg64 source = ctx.reg_alloc.UseGpr(code, args[0]);
|
code.mov(res.cvt32(), res.cvt32());
|
||||||
code.mov(result.cvt32(), source.cvt32());
|
ctx.reg_alloc.DefineValue(code, inst, res);
|
||||||
ctx.reg_alloc.DefineValue(code, inst, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitMostSignificantWord(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitMostSignificantWord(EmitContext& ctx, IR::Inst* inst) {
|
||||||
@@ -911,15 +910,15 @@ static Xbyak::Reg8 DoCarry(BlockOfCode& code, RegAlloc& reg_alloc, Argument& car
|
|||||||
|
|
||||||
// AL contains flags (after LAHF + SETO sequence)
|
// AL contains flags (after LAHF + SETO sequence)
|
||||||
static Xbyak::Reg64 DoNZCV(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* nzcv_out) {
|
static Xbyak::Reg64 DoNZCV(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* nzcv_out) {
|
||||||
if (!nzcv_out) {
|
if (nzcv_out) {
|
||||||
return Xbyak::Reg64{-1};
|
const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(code, HostLoc::RAX);
|
||||||
|
code.xor_(nzcv.cvt32(), nzcv.cvt32());
|
||||||
|
return nzcv;
|
||||||
}
|
}
|
||||||
const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(code, HostLoc::RAX);
|
return Xbyak::Reg64{-1};
|
||||||
code.xor_(nzcv.cvt32(), nzcv.cvt32());
|
|
||||||
return nzcv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bitsize) {
|
static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, size_t bitsize) {
|
||||||
const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
|
const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
|
||||||
const auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
|
const auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
|
||||||
const auto nzcv_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp);
|
const auto nzcv_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp);
|
||||||
@@ -930,19 +929,13 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
|||||||
// Consider using LEA.
|
// Consider using LEA.
|
||||||
if (!carry_inst && !overflow_inst && !nzcv_inst && carry_in.IsImmediate() && !carry_in.GetImmediateU1()) {
|
if (!carry_inst && !overflow_inst && !nzcv_inst && carry_in.IsImmediate() && !carry_in.GetImmediateU1()) {
|
||||||
if (args[1].IsImmediate() && args[1].FitsInImmediateS32()) {
|
if (args[1].IsImmediate() && args[1].FitsInImmediateS32()) {
|
||||||
const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(code, args[0]).changeBit(bitsize);
|
Xbyak::Reg const result = ctx.reg_alloc.UseScratchGpr(code, args[0]).changeBit(bitsize);
|
||||||
const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr(code).changeBit(bitsize);
|
code.lea(result, code.ptr[result + args[1].GetImmediateS32()]);
|
||||||
|
|
||||||
code.lea(result, code.ptr[op1 + args[1].GetImmediateS32()]);
|
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(code, inst, result);
|
ctx.reg_alloc.DefineValue(code, inst, result);
|
||||||
} else {
|
} else {
|
||||||
const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(code, args[0]).changeBit(bitsize);
|
Xbyak::Reg const result = ctx.reg_alloc.UseScratchGpr(code, args[0]).changeBit(bitsize);
|
||||||
const Xbyak::Reg op2 = ctx.reg_alloc.UseGpr(code, args[1]).changeBit(bitsize);
|
Xbyak::Reg const op2 = ctx.reg_alloc.UseGpr(code, args[1]).changeBit(bitsize);
|
||||||
const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr(code).changeBit(bitsize);
|
code.lea(result, code.ptr[result + op2]);
|
||||||
|
|
||||||
code.lea(result, code.ptr[op1 + op2]);
|
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(code, inst, result);
|
ctx.reg_alloc.DefineValue(code, inst, result);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -957,8 +950,14 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
|||||||
const u32 op_arg = args[1].GetImmediateU32();
|
const u32 op_arg = args[1].GetImmediateU32();
|
||||||
if (carry_in.IsImmediate()) {
|
if (carry_in.IsImmediate()) {
|
||||||
if (carry_in.GetImmediateU1()) {
|
if (carry_in.GetImmediateU1()) {
|
||||||
code.stc();
|
// In range for a valid LEA materialisation
|
||||||
code.adc(result, op_arg);
|
auto const in_range = s32(op_arg) >= -0x7ffffffe && s32(op_arg) <= 0x7ffffffe;
|
||||||
|
if (in_range && (carry_inst || nzcv_inst || overflow_inst)) {
|
||||||
|
code.stc();
|
||||||
|
code.adc(result, op_arg);
|
||||||
|
} else {
|
||||||
|
code.lea(result, code.ptr[result + op_arg + 1]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
code.add(result, op_arg);
|
code.add(result, op_arg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -8,17 +8,54 @@
|
|||||||
|
|
||||||
#include "dynarmic/backend/x64/block_of_code.h"
|
#include "dynarmic/backend/x64/block_of_code.h"
|
||||||
#include "dynarmic/backend/x64/emit_x64.h"
|
#include "dynarmic/backend/x64/emit_x64.h"
|
||||||
#include "dynarmic/common/crypto/sm4.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
#include "dynarmic/ir/microinstruction.h"
|
||||||
|
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend::X64 {
|
||||||
|
|
||||||
|
alignas(64) static constexpr std::array<u8, 256> substitution_box = {
|
||||||
|
0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7,
|
||||||
|
0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
|
||||||
|
0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3,
|
||||||
|
0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
||||||
|
0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A,
|
||||||
|
0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
|
||||||
|
0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95,
|
||||||
|
0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
|
||||||
|
0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA,
|
||||||
|
0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
|
||||||
|
0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B,
|
||||||
|
0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
|
||||||
|
0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2,
|
||||||
|
0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87,
|
||||||
|
0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,
|
||||||
|
0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E,
|
||||||
|
0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5,
|
||||||
|
0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,
|
||||||
|
0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55,
|
||||||
|
0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
|
||||||
|
0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60,
|
||||||
|
0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F,
|
||||||
|
0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F,
|
||||||
|
0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51,
|
||||||
|
0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F,
|
||||||
|
0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8,
|
||||||
|
0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD,
|
||||||
|
0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0,
|
||||||
|
0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E,
|
||||||
|
0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
|
||||||
|
0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20,
|
||||||
|
0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48
|
||||||
|
};
|
||||||
|
|
||||||
void EmitX64::EmitSM4AccessSubstitutionBox(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitSM4AccessSubstitutionBox(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
const Xbyak::Reg64 tmp0 = ctx.reg_alloc.UseScratchGpr(code, args[0]);
|
||||||
ctx.reg_alloc.HostCall(code, inst, args[0]);
|
const Xbyak::Reg tmp1 = ctx.reg_alloc.ScratchGpr(code);
|
||||||
code.CallFunction(&Common::Crypto::SM4::AccessSubstitutionBox);
|
// return subtitution_box[index * 1];
|
||||||
code.movzx(code.ABI_RETURN.cvt32(), code.ABI_RETURN.cvt8());
|
code.movzx(tmp0.cvt32(), tmp0.cvt8());
|
||||||
|
code.lea(tmp1, code.ptr[std::addressof(substitution_box)]);
|
||||||
|
code.movzx(tmp1, code.byte[tmp1 + tmp0 * 1]);
|
||||||
|
ctx.reg_alloc.DefineValue(code, inst, tmp1);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::X64
|
} // namespace Dynarmic::Backend::X64
|
||||||
|
|||||||
@@ -927,7 +927,21 @@ void EmitX64::EmitVectorCountLeadingZeros8(EmitContext& ctx, IR::Inst* inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitVectorCountLeadingZeros16(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitVectorCountLeadingZeros16(EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (code.HasHostFeature(HostFeature::AVX)) {
|
if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512CD)) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]);
|
||||||
|
auto const tmp1 = ctx.reg_alloc.ScratchXmm(code);
|
||||||
|
// 11-latency: unpack 16-bit(128-bit) XMM into 32-bit(256-bit) YMM vector
|
||||||
|
// then just lzcnt that, pack it back (unsigned) to 16-bit
|
||||||
|
// then subtract 16-bit cuz of the zext32
|
||||||
|
/*4*/ code.vpmovzxwd(tmp0.cvt256(), tmp0);
|
||||||
|
/*4*/ code.vplzcntd(tmp0.cvt256(), tmp0.cvt256());
|
||||||
|
/*1*/ code.vpxor(tmp1, tmp1, tmp1);
|
||||||
|
/*1*/ code.vpackusdw(tmp0, tmp0, tmp1);
|
||||||
|
/*1*/ code.vpaddw(tmp0, tmp0, code.BConst<16>(xword, 65520));
|
||||||
|
/*4*/ code.vzeroupper();
|
||||||
|
ctx.reg_alloc.DefineValue(code, inst, tmp0);
|
||||||
|
} else if (code.HasHostFeature(HostFeature::AVX)) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]);
|
auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]);
|
||||||
auto const result = ctx.reg_alloc.ScratchXmm(code);
|
auto const result = ctx.reg_alloc.ScratchXmm(code);
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2018 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "dynarmic/common/crypto/sm4.h"
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "dynarmic/common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Common::Crypto::SM4 {
|
|
||||||
|
|
||||||
using SubstitutionTable = std::array<u8, 256>;
|
|
||||||
|
|
||||||
constexpr SubstitutionTable substitution_box{
|
|
||||||
{0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7,
|
|
||||||
0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
|
|
||||||
0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3,
|
|
||||||
0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
|
||||||
0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A,
|
|
||||||
0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
|
|
||||||
0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95,
|
|
||||||
0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
|
|
||||||
0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA,
|
|
||||||
0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
|
|
||||||
0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B,
|
|
||||||
0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
|
|
||||||
0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2,
|
|
||||||
0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87,
|
|
||||||
0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,
|
|
||||||
0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E,
|
|
||||||
0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5,
|
|
||||||
0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,
|
|
||||||
0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55,
|
|
||||||
0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
|
|
||||||
0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60,
|
|
||||||
0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F,
|
|
||||||
0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F,
|
|
||||||
0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51,
|
|
||||||
0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F,
|
|
||||||
0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8,
|
|
||||||
0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD,
|
|
||||||
0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0,
|
|
||||||
0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E,
|
|
||||||
0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
|
|
||||||
0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20,
|
|
||||||
0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48}};
|
|
||||||
|
|
||||||
u8 AccessSubstitutionBox(u8 index) {
|
|
||||||
return substitution_box[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Common::Crypto::SM4
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2018 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "dynarmic/common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Common::Crypto::SM4 {
|
|
||||||
|
|
||||||
u8 AccessSubstitutionBox(u8 index);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Common::Crypto::SM4
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "dynarmic/common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
|
||||||
|
|
||||||
std::string DisassembleArm(u32 instruction);
|
|
||||||
std::string DisassembleThumb16(u16 instruction);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
|
||||||
@@ -1,397 +0,0 @@
|
|||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
#include <mcl/bit/bit_field.hpp>
|
|
||||||
|
|
||||||
#include "dynarmic/common/string_util.h"
|
|
||||||
#include "dynarmic/frontend/A32/a32_types.h"
|
|
||||||
#include "dynarmic/frontend/A32/decoder/thumb16.h"
|
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
#include "dynarmic/frontend/imm.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
|
||||||
|
|
||||||
class DisassemblerVisitor {
|
|
||||||
public:
|
|
||||||
using instruction_return_type = std::string;
|
|
||||||
|
|
||||||
std::string thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) {
|
|
||||||
return fmt::format("lsls {}, {}, #{}", d, m, imm5.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) {
|
|
||||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
|
||||||
return fmt::format("lsrs {}, {}, #{}", d, m, shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
|
|
||||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
|
||||||
return fmt::format("asrs {}, {}, #{}", d, m, shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
|
|
||||||
return fmt::format("adds {}, {}, {}", d, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_reg(Reg m, Reg n, Reg d) {
|
|
||||||
return fmt::format("subs {}, {}, {}", d, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
|
||||||
return fmt::format("adds {}, {}, #{}", d, n, imm3.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
|
||||||
return fmt::format("subs {}, {}, #{}", d, n, imm3.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MOV_imm(Reg d, Imm<8> imm8) {
|
|
||||||
return fmt::format("movs {}, #{}", d, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMP_imm(Reg n, Imm<8> imm8) {
|
|
||||||
return fmt::format("cmp {}, #{}", n, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) {
|
|
||||||
return fmt::format("adds {}, #{}", d_n, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8) {
|
|
||||||
return fmt::format("subs {}, #{}", d_n, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_AND_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("ands {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_EOR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("eors {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LSL_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("lsls {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LSR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("lsrs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ASR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("asrs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADC_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("adcs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SBC_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("sbcs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ROR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("rors {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_TST_reg(Reg m, Reg n) {
|
|
||||||
return fmt::format("tst {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_RSB_imm(Reg n, Reg d) {
|
|
||||||
// Pre-UAL syntax: NEGS <Rd>, <Rn>
|
|
||||||
return fmt::format("rsbs {}, {}, #0", d, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMP_reg_t1(Reg m, Reg n) {
|
|
||||||
return fmt::format("cmp {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMN_reg(Reg m, Reg n) {
|
|
||||||
return fmt::format("cmn {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ORR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("orrs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MUL_reg(Reg n, Reg d_m) {
|
|
||||||
return fmt::format("muls {}, {}, {}", d_m, n, d_m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BIC_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("bics {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MVN_reg(Reg m, Reg d) {
|
|
||||||
return fmt::format("mvns {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) {
|
|
||||||
const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo;
|
|
||||||
return fmt::format("add {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) {
|
|
||||||
const Reg n = n_hi ? (n_lo + 8) : n_lo;
|
|
||||||
return fmt::format("cmp {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) {
|
|
||||||
const Reg d = d_hi ? (d_lo + 8) : d_lo;
|
|
||||||
return fmt::format("mov {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_literal(Reg t, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("ldr {}, [pc, #{}]", t, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STR_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("str {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRH_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("strh {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRB_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("strb {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrsb {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldr {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrh {}, [%s, %s]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrb {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrsh {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
|
||||||
return fmt::format("str {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
|
||||||
return fmt::format("ldr {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend();
|
|
||||||
return fmt::format("strb {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend();
|
|
||||||
return fmt::format("ldrb {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
|
||||||
return fmt::format("strh {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
|
||||||
return fmt::format("ldrh {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STR_imm_t2(Reg t, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("str {}, [sp, #{}]", t, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("ldr {}, [sp, #{}]", t, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADR(Reg d, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("adr {}, +#{}", d, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_sp_t1(Reg d, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("add {}, sp, #{}", d, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_sp_t2(Imm<7> imm7) {
|
|
||||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
|
||||||
return fmt::format("add sp, sp, #{}", imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_sp(Imm<7> imm7) {
|
|
||||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
|
||||||
return fmt::format("sub sp, sp, #{}", imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_NOP() {
|
|
||||||
return "nop";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SEV() {
|
|
||||||
return "sev";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SEVL() {
|
|
||||||
return "sevl";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_WFE() {
|
|
||||||
return "wfe";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_WFI() {
|
|
||||||
return "wfi";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_YIELD() {
|
|
||||||
return "yield";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_IT(Imm<8> imm8) {
|
|
||||||
const Cond firstcond = imm8.Bits<4, 7, Cond>();
|
|
||||||
const bool firstcond0 = imm8.Bit<4>();
|
|
||||||
const auto [x, y, z] = [&] {
|
|
||||||
if (imm8.Bits<0, 3>() == 0b1000) {
|
|
||||||
return std::make_tuple("", "", "");
|
|
||||||
}
|
|
||||||
if (imm8.Bits<0, 2>() == 0b100) {
|
|
||||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", "", "");
|
|
||||||
}
|
|
||||||
if (imm8.Bits<0, 1>() == 0b10) {
|
|
||||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", "");
|
|
||||||
}
|
|
||||||
// Sanity note: Here imm8.Bit<0>() is guaranteed to be == 1. (imm8 can never be 0bxxxx0000)
|
|
||||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", imm8.Bit<1>() == firstcond0 ? "t" : "e");
|
|
||||||
}();
|
|
||||||
return fmt::format("it{}{}{} {}", x, y, z, CondToString(firstcond));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SXTH(Reg m, Reg d) {
|
|
||||||
return fmt::format("sxth {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SXTB(Reg m, Reg d) {
|
|
||||||
return fmt::format("sxtb {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_UXTH(Reg m, Reg d) {
|
|
||||||
return fmt::format("uxth {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_UXTB(Reg m, Reg d) {
|
|
||||||
return fmt::format("uxtb {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_PUSH(bool M, RegList reg_list) {
|
|
||||||
if (M)
|
|
||||||
reg_list |= 1 << 14;
|
|
||||||
return fmt::format("push {{{}}}", RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_POP(bool P, RegList reg_list) {
|
|
||||||
if (P)
|
|
||||||
reg_list |= 1 << 15;
|
|
||||||
return fmt::format("pop {{{}}}", RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SETEND(bool E) {
|
|
||||||
return fmt::format("setend {}", E ? "BE" : "LE");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CPS(bool im, bool a, bool i, bool f) {
|
|
||||||
return fmt::format("cps{} {}{}{}", im ? "id" : "ie", a ? "a" : "", i ? "i" : "", f ? "f" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_REV(Reg m, Reg d) {
|
|
||||||
return fmt::format("rev {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_REV16(Reg m, Reg d) {
|
|
||||||
return fmt::format("rev16 {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_REVSH(Reg m, Reg d) {
|
|
||||||
return fmt::format("revsh {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BKPT(Imm<8> imm8) {
|
|
||||||
return fmt::format("bkpt #{}", imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STMIA(Reg n, RegList reg_list) {
|
|
||||||
return fmt::format("stm {}!, {{{}}}", n, RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDMIA(Reg n, RegList reg_list) {
|
|
||||||
const bool write_back = !mcl::bit::get_bit(static_cast<size_t>(n), reg_list);
|
|
||||||
return fmt::format("ldm {}{}, {{{}}}", n, write_back ? "!" : "", RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BX(Reg m) {
|
|
||||||
return fmt::format("bx {}", m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BLX_reg(Reg m) {
|
|
||||||
return fmt::format("blx {}", m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
|
|
||||||
const char* const name = nonzero ? "cbnz" : "cbz";
|
|
||||||
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
|
|
||||||
|
|
||||||
return fmt::format("{} {}, #{}", name, n, imm);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_UDF() {
|
|
||||||
return fmt::format("udf");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SVC(Imm<8> imm8) {
|
|
||||||
return fmt::format("svc #{}", imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_B_t1(Cond cond, Imm<8> imm8) {
|
|
||||||
const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
|
|
||||||
return fmt::format("b{} {}#{}",
|
|
||||||
CondToString(cond),
|
|
||||||
Common::SignToChar(imm32),
|
|
||||||
abs(imm32));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_B_t2(Imm<11> imm11) {
|
|
||||||
const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
|
|
||||||
return fmt::format("b {}#{}",
|
|
||||||
Common::SignToChar(imm32),
|
|
||||||
abs(imm32));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string DisassembleThumb16(u16 instruction) {
|
|
||||||
DisassemblerVisitor visitor;
|
|
||||||
auto decoder = DecodeThumb16<DisassemblerVisitor>(instruction);
|
|
||||||
return !decoder ? fmt::format("UNKNOWN: {:x}", instruction) : decoder->get().call(visitor, instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2016 MerryMage
|
* Copyright (c) 2016 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
@@ -10,11 +13,11 @@
|
|||||||
|
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
|
|
||||||
IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||||
IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||||
|
|
||||||
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, tcb, options);
|
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, tcb, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -41,7 +41,7 @@ struct TranslationOptions {
|
|||||||
* @param options Configures how certain instructions are translated.
|
* @param options Configures how certain instructions are translated.
|
||||||
* @return A translated basic block in the intermediate representation.
|
* @return A translated basic block in the intermediate representation.
|
||||||
*/
|
*/
|
||||||
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function translates a single provided instruction into our intermediate representation.
|
* This function translates a single provided instruction into our intermediate representation.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -22,12 +22,9 @@
|
|||||||
|
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
|
|
||||||
IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||||
const bool single_step = descriptor.SingleStepping();
|
const bool single_step = descriptor.SingleStepping();
|
||||||
|
|
||||||
IR::Block block{descriptor};
|
|
||||||
TranslatorVisitor visitor{block, descriptor, options};
|
TranslatorVisitor visitor{block, descriptor, options};
|
||||||
|
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
do {
|
do {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||||
@@ -76,12 +73,8 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
||||||
|
|
||||||
block.SetEndLocation(visitor.ir.current_location);
|
block.SetEndLocation(visitor.ir.current_location);
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) {
|
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||||
#include "dynarmic/frontend/imm.h"
|
#include "dynarmic/frontend/imm.h"
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
|
#include "dynarmic/ir/basic_block.h"
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -103,12 +104,9 @@ inline bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) noexcept {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||||
const bool single_step = descriptor.SingleStepping();
|
const bool single_step = descriptor.SingleStepping();
|
||||||
|
|
||||||
IR::Block block{descriptor};
|
|
||||||
TranslatorVisitor visitor{block, descriptor, options};
|
TranslatorVisitor visitor{block, descriptor, options};
|
||||||
|
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
do {
|
do {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||||
@@ -175,12 +173,8 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
||||||
|
|
||||||
block.SetEndLocation(visitor.ir.current_location);
|
block.SetEndLocation(visitor.ir.current_location);
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) {
|
bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
namespace Dynarmic::A64 {
|
namespace Dynarmic::A64 {
|
||||||
|
|
||||||
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) {
|
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) {
|
||||||
const bool single_step = descriptor.SingleStepping();
|
const bool single_step = descriptor.SingleStepping();
|
||||||
|
|
||||||
IR::Block block{descriptor};
|
|
||||||
TranslatorVisitor visitor{block, descriptor, std::move(options)};
|
TranslatorVisitor visitor{block, descriptor, std::move(options)};
|
||||||
|
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
@@ -43,12 +41,8 @@ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory
|
|||||||
if (single_step && should_continue) {
|
if (single_step && should_continue) {
|
||||||
visitor.ir.SetTerm(IR::Term::LinkBlock{*visitor.ir.current_location});
|
visitor.ir.SetTerm(IR::Term::LinkBlock{*visitor.ir.current_location});
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
||||||
|
|
||||||
block.SetEndLocation(*visitor.ir.current_location);
|
block.SetEndLocation(*visitor.ir.current_location);
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
|
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -47,7 +47,7 @@ struct TranslationOptions {
|
|||||||
* @param options Configures how certain instructions are translated.
|
* @param options Configures how certain instructions are translated.
|
||||||
* @return A translated basic block in the intermediate representation.
|
* @return A translated basic block in the intermediate representation.
|
||||||
*/
|
*/
|
||||||
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options);
|
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function translates a single provided instruction into our intermediate representation.
|
* This function translates a single provided instruction into our intermediate representation.
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
namespace A32 {
|
|
||||||
|
|
||||||
std::string DisassembleArm(std::uint32_t instruction);
|
|
||||||
std::string DisassembleThumb16(std::uint16_t instruction);
|
|
||||||
|
|
||||||
} // namespace A32
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
|
||||||
|
/// @brief Smallest valid page (may change for Apple?)
|
||||||
|
constexpr inline uint64_t CODE_PAGE_SIZE = 4096;
|
||||||
|
struct CodePage {
|
||||||
|
uint32_t inst[CODE_PAGE_SIZE / sizeof(uint32_t)];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,13 +22,10 @@
|
|||||||
|
|
||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
|
|
||||||
Block::Block(const LocationDescriptor& location)
|
Block::Block(LocationDescriptor location) noexcept
|
||||||
: location{location},
|
: location{location}
|
||||||
end_location{location},
|
, end_location{location}
|
||||||
cond{Cond::AL}
|
{}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepends a new instruction to this basic block before the insertion point,
|
/// Prepends a new instruction to this basic block before the insertion point,
|
||||||
/// handling any allocations necessary to do so.
|
/// handling any allocations necessary to do so.
|
||||||
@@ -60,6 +57,21 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, s
|
|||||||
return instructions.insert_before(insertion_point, inst);
|
return instructions.insert_before(insertion_point, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Block::Reset(LocationDescriptor location_) noexcept {
|
||||||
|
mcl::intrusive_list<IR::Inst> tmp = {};
|
||||||
|
instructions.swap(tmp);
|
||||||
|
inlined_inst.clear();
|
||||||
|
pooled_inst.clear();
|
||||||
|
cond_failed.reset();
|
||||||
|
location = location_;
|
||||||
|
end_location = location_;
|
||||||
|
cond = Cond::AL;
|
||||||
|
terminal = Term::Invalid{};
|
||||||
|
cond_failed_cycle_count = 0;
|
||||||
|
cycle_count = 0;
|
||||||
|
ASSERT(instructions.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
||||||
struct : boost::static_visitor<std::string> {
|
struct : boost::static_visitor<std::string> {
|
||||||
std::string operator()(const Term::Invalid&) const {
|
std::string operator()(const Term::Invalid&) const {
|
||||||
@@ -123,11 +135,11 @@ std::string DumpBlock(const IR::Block& block) noexcept {
|
|||||||
case Type::A32ExtReg: return A32::ExtRegToString(arg.GetA32ExtRegRef());
|
case Type::A32ExtReg: return A32::ExtRegToString(arg.GetA32ExtRegRef());
|
||||||
case Type::A64Reg: return A64::RegToString(arg.GetA64RegRef());
|
case Type::A64Reg: return A64::RegToString(arg.GetA64RegRef());
|
||||||
case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef());
|
case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef());
|
||||||
case Type::CoprocInfo: return fmt::format("#<coproc>");
|
case Type::CoprocInfo: return fmt::format("$coproc{}", arg.GetCoprocInfo()[0]);
|
||||||
case Type::NZCVFlags: return fmt::format("#<NZCV flags>");
|
case Type::NZCVFlags: return fmt::format("$nzcv");
|
||||||
case Type::Cond: return fmt::format("#<cond={}>", A32::CondToString(arg.GetCond()));
|
case Type::Cond: return fmt::format("$cond={}", A32::CondToString(arg.GetCond()));
|
||||||
case Type::Table: return fmt::format("#<table>");
|
case Type::Table: return fmt::format("$table");
|
||||||
case Type::AccType: return fmt::format("#<acc-type={}>", u32(arg.GetAccType()));
|
case Type::AccType: return fmt::format("$acc-type={}", u32(arg.GetAccType()));
|
||||||
default: return fmt::format("<unknown immediate type {}>", arg.GetType());
|
default: return fmt::format("<unknown immediate type {}>", arg.GetType());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
using reverse_iterator = instruction_list_type::reverse_iterator;
|
using reverse_iterator = instruction_list_type::reverse_iterator;
|
||||||
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
||||||
|
|
||||||
explicit Block(const LocationDescriptor& location);
|
Block(LocationDescriptor location) noexcept;
|
||||||
~Block() = default;
|
~Block() = default;
|
||||||
Block(const Block&) = delete;
|
Block(const Block&) = delete;
|
||||||
Block& operator=(const Block&) = delete;
|
Block& operator=(const Block&) = delete;
|
||||||
@@ -58,6 +58,7 @@ public:
|
|||||||
return PrependNewInst(instructions.end(), opcode, args);
|
return PrependNewInst(instructions.end(), opcode, args);
|
||||||
}
|
}
|
||||||
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
||||||
|
void Reset(LocationDescriptor location_) noexcept;
|
||||||
|
|
||||||
/// Gets a mutable reference to the instruction list for this basic block.
|
/// Gets a mutable reference to the instruction list for this basic block.
|
||||||
inline instruction_list_type& Instructions() noexcept {
|
inline instruction_list_type& Instructions() noexcept {
|
||||||
@@ -153,7 +154,7 @@ public:
|
|||||||
/// Description of the end location of this block
|
/// Description of the end location of this block
|
||||||
LocationDescriptor end_location;
|
LocationDescriptor end_location;
|
||||||
/// Conditional to pass in order to execute this block
|
/// Conditional to pass in order to execute this block
|
||||||
Cond cond;
|
Cond cond = Cond::AL;
|
||||||
/// Terminal instruction of this block.
|
/// Terminal instruction of this block.
|
||||||
Terminal terminal = Term::Invalid{};
|
Terminal terminal = Term::Invalid{};
|
||||||
/// Number of cycles this block takes to execute if the conditional fails.
|
/// Number of cycles this block takes to execute if the conditional fails.
|
||||||
|
|||||||
@@ -485,6 +485,16 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tiny helper to avoid the need to store based off the opcode
|
||||||
|
// bit size all over the place within folding functions.
|
||||||
|
static void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) {
|
||||||
|
if (is_32_bit) {
|
||||||
|
inst.ReplaceUsesWith(IR::Value{u32(value)});
|
||||||
|
} else {
|
||||||
|
inst.ReplaceUsesWith(IR::Value{value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void A64GetSetElimination(IR::Block& block) {
|
static void A64GetSetElimination(IR::Block& block) {
|
||||||
using Iterator = IR::Block::iterator;
|
using Iterator = IR::Block::iterator;
|
||||||
|
|
||||||
@@ -501,8 +511,8 @@ static void A64GetSetElimination(IR::Block& block) {
|
|||||||
struct RegisterInfo {
|
struct RegisterInfo {
|
||||||
IR::Value register_value;
|
IR::Value register_value;
|
||||||
TrackingType tracking_type;
|
TrackingType tracking_type;
|
||||||
bool set_instruction_present = false;
|
|
||||||
Iterator last_set_instruction;
|
Iterator last_set_instruction;
|
||||||
|
bool set_instruction_present = false;
|
||||||
};
|
};
|
||||||
std::array<RegisterInfo, 31> reg_info;
|
std::array<RegisterInfo, 31> reg_info;
|
||||||
std::array<RegisterInfo, 32> vec_info;
|
std::array<RegisterInfo, 32> vec_info;
|
||||||
@@ -514,59 +524,58 @@ static void A64GetSetElimination(IR::Block& block) {
|
|||||||
info.last_set_instruction->Invalidate();
|
info.last_set_instruction->Invalidate();
|
||||||
block.Instructions().erase(info.last_set_instruction);
|
block.Instructions().erase(info.last_set_instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.register_value = value;
|
info.register_value = value;
|
||||||
info.tracking_type = tracking_type;
|
info.tracking_type = tracking_type;
|
||||||
info.set_instruction_present = true;
|
info.set_instruction_present = true;
|
||||||
info.last_set_instruction = set_inst;
|
info.last_set_instruction = set_inst;
|
||||||
};
|
};
|
||||||
|
const auto do_get = [&block](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
|
||||||
const auto do_get = [](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
|
if (!info.register_value.IsEmpty() && info.tracking_type == tracking_type) {
|
||||||
const auto do_nothing = [&] {
|
get_inst->ReplaceUsesWith(info.register_value);
|
||||||
|
} else if (!info.register_value.IsEmpty()
|
||||||
|
&& tracking_type == TrackingType::W
|
||||||
|
&& info.tracking_type == TrackingType::X) {
|
||||||
|
// A sequence like
|
||||||
|
// SetX r1 -> GetW r1, is just reading off the lowest 32-bits of the register
|
||||||
|
if (info.register_value.IsImmediate()) {
|
||||||
|
ReplaceUsesWith(*get_inst, true, u32(info.register_value.GetImmediateAsU64()));
|
||||||
|
} else {
|
||||||
|
A64::IREmitter ir{block};
|
||||||
|
ir.SetInsertionPointBefore(&*get_inst);
|
||||||
|
get_inst->ReplaceUsesWith(ir.LeastSignificantWord(IR::U64{info.register_value}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
info = {};
|
info = {};
|
||||||
info.register_value = IR::Value(&*get_inst);
|
info.register_value = IR::Value(&*get_inst);
|
||||||
info.tracking_type = tracking_type;
|
info.tracking_type = tracking_type;
|
||||||
};
|
|
||||||
|
|
||||||
if (info.register_value.IsEmpty()) {
|
|
||||||
do_nothing();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.tracking_type == tracking_type) {
|
|
||||||
get_inst->ReplaceUsesWith(info.register_value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_nothing();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
||||||
auto const opcode = inst->GetOpcode();
|
auto const opcode = inst->GetOpcode();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case IR::Opcode::A64GetW: {
|
case IR::Opcode::A64GetW: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_get(reg_info.at(index), inst, TrackingType::W);
|
do_get(reg_info[index], inst, TrackingType::W);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetX: {
|
case IR::Opcode::A64GetX: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_get(reg_info.at(index), inst, TrackingType::X);
|
do_get(reg_info[index], inst, TrackingType::X);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetS: {
|
case IR::Opcode::A64GetS: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst, TrackingType::S);
|
do_get(vec_info[index], inst, TrackingType::S);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetD: {
|
case IR::Opcode::A64GetD: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst, TrackingType::D);
|
do_get(vec_info[index], inst, TrackingType::D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetQ: {
|
case IR::Opcode::A64GetQ: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst, TrackingType::Q);
|
do_get(vec_info[index], inst, TrackingType::Q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetSP: {
|
case IR::Opcode::A64GetSP: {
|
||||||
@@ -579,27 +588,27 @@ static void A64GetSetElimination(IR::Block& block) {
|
|||||||
}
|
}
|
||||||
case IR::Opcode::A64SetW: {
|
case IR::Opcode::A64SetW: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::W);
|
do_set(reg_info[index], inst->GetArg(1), inst, TrackingType::W);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetX: {
|
case IR::Opcode::A64SetX: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::X);
|
do_set(reg_info[index], inst->GetArg(1), inst, TrackingType::X);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetS: {
|
case IR::Opcode::A64SetS: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::S);
|
do_set(vec_info[index], inst->GetArg(1), inst, TrackingType::S);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetD: {
|
case IR::Opcode::A64SetD: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::D);
|
do_set(vec_info[index], inst->GetArg(1), inst, TrackingType::D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetQ: {
|
case IR::Opcode::A64SetQ: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::Q);
|
do_set(vec_info[index], inst->GetArg(1), inst, TrackingType::Q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetSP: {
|
case IR::Opcode::A64SetSP: {
|
||||||
@@ -668,16 +677,6 @@ static void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb
|
|||||||
|
|
||||||
using Op = Dynarmic::IR::Opcode;
|
using Op = Dynarmic::IR::Opcode;
|
||||||
|
|
||||||
// Tiny helper to avoid the need to store based off the opcode
|
|
||||||
// bit size all over the place within folding functions.
|
|
||||||
static void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) {
|
|
||||||
if (is_32_bit) {
|
|
||||||
inst.ReplaceUsesWith(IR::Value{u32(value)});
|
|
||||||
} else {
|
|
||||||
inst.ReplaceUsesWith(IR::Value{value});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static IR::Value Value(bool is_32_bit, u64 value) {
|
static IR::Value Value(bool is_32_bit, u64 value) {
|
||||||
return is_32_bit ? IR::Value{u32(value)} : IR::Value{value};
|
return is_32_bit ? IR::Value{u32(value)} : IR::Value{value};
|
||||||
}
|
}
|
||||||
@@ -1043,6 +1042,11 @@ static void FoldZeroExtendXToLong(IR::Inst& inst) {
|
|||||||
static void ConstantPropagation(IR::Block& block) {
|
static void ConstantPropagation(IR::Block& block) {
|
||||||
for (auto& inst : block.instructions) {
|
for (auto& inst : block.instructions) {
|
||||||
auto const opcode = inst.GetOpcode();
|
auto const opcode = inst.GetOpcode();
|
||||||
|
// skip NZCV so we dont end up discarding side effects :)
|
||||||
|
// TODO(lizzie): hey stupid maybe fix the A64 codegen for folded constants AND
|
||||||
|
// redirect the mfer properly?!??! just saying :)
|
||||||
|
if (IR::MayGetNZCVFromOp(opcode) && inst.GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp))
|
||||||
|
continue;
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case Op::LeastSignificantWord:
|
case Op::LeastSignificantWord:
|
||||||
FoldLeastSignificantWord(inst);
|
FoldLeastSignificantWord(inst);
|
||||||
@@ -1473,11 +1477,11 @@ static void VerificationPass(const IR::Block& block) {
|
|||||||
void Optimize(IR::Block& block, const A32::UserConfig& conf, const Optimization::PolyfillOptions& polyfill_options) {
|
void Optimize(IR::Block& block, const A32::UserConfig& conf, const Optimization::PolyfillOptions& polyfill_options) {
|
||||||
Optimization::PolyfillPass(block, polyfill_options);
|
Optimization::PolyfillPass(block, polyfill_options);
|
||||||
Optimization::NamingPass(block);
|
Optimization::NamingPass(block);
|
||||||
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) [[likely]] {
|
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
|
||||||
Optimization::A32GetSetElimination(block, {.convert_nzc_to_nz = true});
|
Optimization::A32GetSetElimination(block, {.convert_nzc_to_nz = true});
|
||||||
Optimization::DeadCodeElimination(block);
|
Optimization::DeadCodeElimination(block);
|
||||||
}
|
}
|
||||||
if (conf.HasOptimization(OptimizationFlag::ConstProp)) [[likely]] {
|
if (conf.HasOptimization(OptimizationFlag::ConstProp)) {
|
||||||
Optimization::ConstantMemoryReads(block, conf.callbacks);
|
Optimization::ConstantMemoryReads(block, conf.callbacks);
|
||||||
Optimization::ConstantPropagation(block);
|
Optimization::ConstantPropagation(block);
|
||||||
Optimization::DeadCodeElimination(block);
|
Optimization::DeadCodeElimination(block);
|
||||||
@@ -1492,17 +1496,18 @@ void Optimize(IR::Block& block, const A64::UserConfig& conf, const Optimization:
|
|||||||
Optimization::PolyfillPass(block, polyfill_options);
|
Optimization::PolyfillPass(block, polyfill_options);
|
||||||
Optimization::A64CallbackConfigPass(block, conf);
|
Optimization::A64CallbackConfigPass(block, conf);
|
||||||
Optimization::NamingPass(block);
|
Optimization::NamingPass(block);
|
||||||
if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) [[likely]] {
|
if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) {
|
||||||
Optimization::A64GetSetElimination(block);
|
Optimization::A64GetSetElimination(block);
|
||||||
Optimization::DeadCodeElimination(block);
|
Optimization::DeadCodeElimination(block);
|
||||||
}
|
}
|
||||||
if (conf.HasOptimization(OptimizationFlag::ConstProp)) [[likely]] {
|
if (conf.HasOptimization(OptimizationFlag::ConstProp)) {
|
||||||
Optimization::ConstantPropagation(block);
|
Optimization::ConstantPropagation(block);
|
||||||
Optimization::DeadCodeElimination(block);
|
Optimization::DeadCodeElimination(block);
|
||||||
}
|
}
|
||||||
if (conf.HasOptimization(OptimizationFlag::MiscIROpt)) [[likely]] {
|
if (conf.HasOptimization(OptimizationFlag::MiscIROpt)) {
|
||||||
Optimization::A64MergeInterpretBlocksPass(block, conf.callbacks);
|
Optimization::A64MergeInterpretBlocksPass(block, conf.callbacks);
|
||||||
}
|
}
|
||||||
|
Optimization::IdentityRemovalPass(block);
|
||||||
if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
||||||
Optimization::VerificationPass(block);
|
Optimization::VerificationPass(block);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||||
#include "dynarmic/frontend/A32/PSR.h"
|
#include "dynarmic/frontend/A32/PSR.h"
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
|
|||||||
@@ -1,381 +0,0 @@
|
|||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
|
|
||||||
using Dynarmic::A32::DisassembleArm;
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble branch instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xEAFFFFFE) == "b +#0");
|
|
||||||
REQUIRE(DisassembleArm(0xEB000008) == "bl +#40");
|
|
||||||
REQUIRE(DisassembleArm(0xFBFFFFFE) == "blx +#2");
|
|
||||||
REQUIRE(DisassembleArm(0xFAFFFFFF) == "blx +#4");
|
|
||||||
REQUIRE(DisassembleArm(0xFBE1E7FE) == "blx -#7888894");
|
|
||||||
REQUIRE(DisassembleArm(0xE12FFF3D) == "blx sp");
|
|
||||||
REQUIRE(DisassembleArm(0x312FFF13) == "bxcc r3");
|
|
||||||
REQUIRE(DisassembleArm(0x012FFF29) == "bxjeq r9");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble data processing instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE2A21004) == "adc r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21143) == "adc r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21103) == "adc r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21123) == "adc r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21163) == "adc r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21003) == "adc r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21063) == "adc r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21453) == "adc r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21413) == "adc r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21433) == "adc r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21473) == "adc r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2B21004) == "adcs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21143) == "adcs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21103) == "adcs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21123) == "adcs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21163) == "adcs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21003) == "adcs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21063) == "adcs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21453) == "adcs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21413) == "adcs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21433) == "adcs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21473) == "adcs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2853004) == "add r3, r5, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821143) == "add r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821103) == "add r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821123) == "add r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821163) == "add r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821003) == "add r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821453) == "add r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821413) == "add r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821433) == "add r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821473) == "add r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821063) == "add r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE2953004) == "adds r3, r5, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921143) == "adds r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921103) == "adds r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921123) == "adds r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921163) == "adds r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921003) == "adds r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921063) == "adds r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921453) == "adds r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921413) == "adds r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921433) == "adds r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921473) == "adds r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2021004) == "and r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021143) == "and r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021103) == "and r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021123) == "and r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021163) == "and r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021003) == "and r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021453) == "and r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021413) == "and r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021433) == "and r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021473) == "and r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021063) == "and r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE2121004) == "ands r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121143) == "ands r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121103) == "ands r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121123) == "ands r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121163) == "ands r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121003) == "ands r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121063) == "ands r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121453) == "ands r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121413) == "ands r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121433) == "ands r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121473) == "ands r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3C21004) == "bic r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21143) == "bic r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21103) == "bic r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21123) == "bic r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21163) == "bic r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21003) == "bic r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21453) == "bic r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21413) == "bic r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21433) == "bic r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21473) == "bic r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21063) == "bic r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE3D21004) == "bics r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21143) == "bics r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21103) == "bics r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21123) == "bics r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21163) == "bics r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21003) == "bics r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21063) == "bics r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21453) == "bics r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21413) == "bics r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21433) == "bics r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21473) == "bics r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3710004) == "cmn r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710142) == "cmn r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710102) == "cmn r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710122) == "cmn r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710162) == "cmn r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710002) == "cmn r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710062) == "cmn r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710352) == "cmn r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710312) == "cmn r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710332) == "cmn r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710372) == "cmn r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3510004) == "cmp r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510142) == "cmp r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510102) == "cmp r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510122) == "cmp r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510162) == "cmp r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510002) == "cmp r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510062) == "cmp r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510352) == "cmp r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510312) == "cmp r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510332) == "cmp r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510372) == "cmp r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2221004) == "eor r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221243) == "eor r1, r2, r3, asr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221203) == "eor r1, r2, r3, lsl #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221223) == "eor r1, r2, r3, lsr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221263) == "eor r1, r2, r3, ror #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221003) == "eor r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221453) == "eor r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221413) == "eor r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221433) == "eor r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221473) == "eor r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221063) == "eor r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE2321004) == "eors r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321243) == "eors r1, r2, r3, asr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321203) == "eors r1, r2, r3, lsl #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321223) == "eors r1, r2, r3, lsr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321263) == "eors r1, r2, r3, ror #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321003) == "eors r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321453) == "eors r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321413) == "eors r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321433) == "eors r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321473) == "eors r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321063) == "eors r1, r2, r3, rrx");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3A010FF) == "mov r1, #255");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01142) == "mov r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01102) == "mov r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01122) == "mov r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01162) == "mov r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01062) == "mov r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A0E00F) == "mov lr, pc");
|
|
||||||
REQUIRE(DisassembleArm(0xE3B010FF) == "movs r1, #255");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B0E00F) == "movs lr, pc");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01142) == "movs r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01102) == "movs r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01122) == "movs r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01162) == "movs r1, r2, ror #2");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3E01004) == "mvn r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01142) == "mvn r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01102) == "mvn r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01122) == "mvn r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01162) == "mvn r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01062) == "mvn r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01002) == "mvn r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01352) == "mvn r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01312) == "mvn r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01332) == "mvn r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01372) == "mvn r1, r2, ror r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE3F01004) == "mvns r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01142) == "mvns r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01102) == "mvns r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01122) == "mvns r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01162) == "mvns r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01062) == "mvns r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01002) == "mvns r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01352) == "mvns r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01312) == "mvns r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01332) == "mvns r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01372) == "mvns r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3821004) == "orr r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821143) == "orr r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821103) == "orr r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821123) == "orr r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821163) == "orr r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821063) == "orr r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821003) == "orr r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821453) == "orr r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821413) == "orr r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821433) == "orr r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821473) == "orr r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE3921004) == "orrs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921143) == "orrs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921103) == "orrs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921123) == "orrs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921163) == "orrs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921063) == "orrs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921003) == "orrs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921453) == "orrs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921413) == "orrs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921433) == "orrs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921473) == "orrs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2621004) == "rsb r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621143) == "rsb r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621103) == "rsb r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621123) == "rsb r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621163) == "rsb r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621063) == "rsb r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621003) == "rsb r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621453) == "rsb r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621413) == "rsb r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621433) == "rsb r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621473) == "rsb r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2721004) == "rsbs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721143) == "rsbs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721103) == "rsbs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721123) == "rsbs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721163) == "rsbs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721063) == "rsbs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721003) == "rsbs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721453) == "rsbs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721413) == "rsbs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721433) == "rsbs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721473) == "rsbs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2E21004) == "rsc r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21143) == "rsc r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21103) == "rsc r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21123) == "rsc r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21163) == "rsc r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21063) == "rsc r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21003) == "rsc r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21453) == "rsc r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21413) == "rsc r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21433) == "rsc r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21473) == "rsc r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2F21004) == "rscs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21143) == "rscs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21103) == "rscs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21123) == "rscs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21163) == "rscs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21063) == "rscs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21003) == "rscs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21453) == "rscs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21413) == "rscs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21433) == "rscs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21473) == "rscs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2C21004) == "sbc r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21143) == "sbc r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21103) == "sbc r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21123) == "sbc r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21163) == "sbc r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21063) == "sbc r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21003) == "sbc r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21453) == "sbc r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21413) == "sbc r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21433) == "sbc r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21473) == "sbc r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2D21004) == "sbcs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21143) == "sbcs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21103) == "sbcs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21123) == "sbcs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21163) == "sbcs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21063) == "sbcs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21003) == "sbcs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21453) == "sbcs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21413) == "sbcs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21433) == "sbcs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21473) == "sbcs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3310004) == "teq r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310142) == "teq r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310102) == "teq r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310122) == "teq r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310162) == "teq r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310002) == "teq r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310062) == "teq r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310352) == "teq r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310312) == "teq r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310332) == "teq r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310372) == "teq r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3110004) == "tst r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110142) == "tst r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110102) == "tst r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110122) == "tst r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110162) == "tst r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110002) == "tst r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110062) == "tst r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110352) == "tst r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110312) == "tst r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110332) == "tst r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110372) == "tst r1, r2, ror r3");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble half-word multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE1003281) == "smlabb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE10032C1) == "smlabt r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE10032A1) == "smlatb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE10032E1) == "smlatt r0, r1, r2, r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1203281) == "smlawb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE12032C1) == "smlawt r0, r1, r2, r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE12002A1) == "smulwb r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE12002E1) == "smulwt r0, r1, r2");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1410382) == "smlalbb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE14103C2) == "smlalbt r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE14103A2) == "smlaltb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE14103E2) == "smlaltt r0, r1, r2, r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1600281) == "smulbb r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE16002C1) == "smulbt r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE16002A1) == "smultb r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE16002E1) == "smultt r0, r1, r2");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE0214392) == "mla r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0314392) == "mlas r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0010392) == "mul r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0110392) == "muls r1, r2, r3");
|
|
||||||
|
|
||||||
// TODO: MLS should be here whenever it's supported.
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21493) == "smlal r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21493) == "smlals r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21493) == "smull r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21493) == "smulls r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0421493) == "umaal r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21493) == "umlal r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21493) == "umlals r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0821493) == "umull r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921493) == "umulls r1, r2, r3, r4");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble synchronization primitive instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE1921F9F) == "ldrex r1, [r2]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21F9F) == "ldrexb r1, [r2]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B31F9F) == "ldrexd r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F21F9F) == "ldrexh r1, [r2]");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1831F92) == "strex r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C31F92) == "strexb r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A41F92) == "strexd r1, r2, r3, [r4]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E31F92) == "strexh r1, r2, [r3]");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1031092) == "swp r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1431092) == "swpb r1, r2, [r3]");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble load / store multiple instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE92D500F) == "stmdb sp!, {r0, r1, r2, r3, r12, lr}");
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
include(TargetArchitectureSpecificSources)
|
include(TargetArchitectureSpecificSources)
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@ add_executable(dynarmic_tests
|
|||||||
fp/unpacked_tests.cpp
|
fp/unpacked_tests.cpp
|
||||||
rand_int.h
|
rand_int.h
|
||||||
# A32
|
# A32
|
||||||
A32/test_arm_disassembler.cpp
|
|
||||||
A32/test_arm_instructions.cpp
|
A32/test_arm_instructions.cpp
|
||||||
A32/test_coprocessor.cpp
|
A32/test_coprocessor.cpp
|
||||||
A32/test_svc.cpp
|
A32/test_svc.cpp
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -34,7 +34,6 @@
|
|||||||
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
#include "dynarmic/interface/A32/disassembler.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
#include "dynarmic/ir/opt_passes.h"
|
#include "dynarmic/ir/opt_passes.h"
|
||||||
|
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||||||
Settings,
|
Settings,
|
||||||
memory_layout_mode,
|
memory_layout_mode,
|
||||||
tr("Memory Layout"),
|
tr("Memory Layout"),
|
||||||
tr("Increases the amount of emulated RAM from 4GB of the board to the "
|
tr("Increases the amount of emulated RAM.\nDoesn't affect performance/stability but may allow HD texture "
|
||||||
"devkit 8/6GB.\nDoesn't affect performance/stability but may allow HD texture "
|
|
||||||
"mods to load."));
|
"mods to load."));
|
||||||
INSERT(Settings, use_speed_limit, QString(), QString());
|
INSERT(Settings, use_speed_limit, QString(), QString());
|
||||||
|
INSERT(Settings, current_speed_mode, QString(), QString());
|
||||||
INSERT(Settings,
|
INSERT(Settings,
|
||||||
speed_limit,
|
speed_limit,
|
||||||
tr("Limit Speed Percent"),
|
tr("Limit Speed Percent"),
|
||||||
@@ -80,6 +80,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||||||
"faster or not.\n200% for a 30 FPS game is 60 FPS, and for a "
|
"faster or not.\n200% for a 30 FPS game is 60 FPS, and for a "
|
||||||
"60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the "
|
"60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the "
|
||||||
"maximum your PC can reach."));
|
"maximum your PC can reach."));
|
||||||
|
|
||||||
|
INSERT(Settings, turbo_speed_limit, tr("Turbo Speed"),
|
||||||
|
tr("When the Turbo Speed hotkey is pressed, the speed will be limited to this "
|
||||||
|
"percentage."));
|
||||||
|
INSERT(Settings, slow_speed_limit, tr("Slow Speed"),
|
||||||
|
tr("When the Slow Speed hotkey is pressed, the speed will be limited to this "
|
||||||
|
"percentage."));
|
||||||
|
|
||||||
INSERT(Settings,
|
INSERT(Settings,
|
||||||
sync_core_speed,
|
sync_core_speed,
|
||||||
tr("Synchronize Core Speed"),
|
tr("Synchronize Core Speed"),
|
||||||
@@ -225,6 +233,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||||||
"intermediate format: RGBA8.\n"
|
"intermediate format: RGBA8.\n"
|
||||||
"BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format,\n"
|
"BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format,\n"
|
||||||
" saving VRAM but degrading image quality."));
|
" saving VRAM but degrading image quality."));
|
||||||
|
INSERT(Settings, frame_pacing_mode, tr("Frame Pacing Mode (Vulkan only)"),
|
||||||
|
tr("Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent."));
|
||||||
INSERT(Settings,
|
INSERT(Settings,
|
||||||
vram_usage_mode,
|
vram_usage_mode,
|
||||||
tr("VRAM Usage Mode:"),
|
tr("VRAM Usage Mode:"),
|
||||||
@@ -284,6 +294,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||||||
tr("Fast GPU Time"),
|
tr("Fast GPU Time"),
|
||||||
tr("Overclocks the emulated GPU to increase dynamic resolution and render "
|
tr("Overclocks the emulated GPU to increase dynamic resolution and render "
|
||||||
"distance.\nUse 256 for maximal performance and 512 for maximal graphics fidelity."));
|
"distance.\nUse 256 for maximal performance and 512 for maximal graphics fidelity."));
|
||||||
|
INSERT(Settings,
|
||||||
|
gpu_unswizzle_enabled,
|
||||||
|
tr("GPU Unswizzle"),
|
||||||
|
tr("Accelerates BCn 3D texture decoding using GPU compute.\n"
|
||||||
|
"Disable if experiencing crashes or graphical glitches."));
|
||||||
INSERT(Settings,
|
INSERT(Settings,
|
||||||
gpu_unswizzle_texture_size,
|
gpu_unswizzle_texture_size,
|
||||||
tr("GPU Unswizzle Max Texture Size"),
|
tr("GPU Unswizzle Max Texture Size"),
|
||||||
@@ -497,6 +512,14 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
|||||||
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
|
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
|
||||||
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
|
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
|
||||||
}});
|
}});
|
||||||
|
translations->insert({Settings::EnumMetadata<Settings::FramePacingMode>::Index(),
|
||||||
|
{
|
||||||
|
PAIR(FramePacingMode, Target_Auto, tr("Auto")),
|
||||||
|
PAIR(FramePacingMode, Target_30, tr("30 FPS")),
|
||||||
|
PAIR(FramePacingMode, Target_60, tr("60 FPS")),
|
||||||
|
PAIR(FramePacingMode, Target_120, tr("120 FPS")),
|
||||||
|
PAIR(FramePacingMode, Target_240, tr("240 FPS")),
|
||||||
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
||||||
{
|
{
|
||||||
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig);
|
|||||||
// This must be in alphabetical order according to action name as it must have the same order as
|
// This must be in alphabetical order according to action name as it must have the same order as
|
||||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const std::array<Shortcut, 30> default_hotkeys{{
|
const std::array<Shortcut, 32> default_hotkeys{{
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
||||||
@@ -265,11 +265,11 @@ const std::array<Shortcut, 30> default_hotkeys{{
|
|||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
@@ -277,6 +277,8 @@ const std::array<Shortcut, 30> default_hotkeys{{
|
|||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}},
|
||||||
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Turbo Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Z"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Slow Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+X"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
|
||||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}},
|
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}},
|
||||||
|
|||||||
@@ -304,17 +304,9 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
|||||||
Optimization::GlobalMemoryToStorageBufferPass(program, host_info);
|
Optimization::GlobalMemoryToStorageBufferPass(program, host_info);
|
||||||
Optimization::TexturePass(env, program, host_info);
|
Optimization::TexturePass(env, program, host_info);
|
||||||
|
|
||||||
bool should_rescale =
|
if (Settings::values.resolution_info.active) {
|
||||||
#ifdef __ANDROID__
|
|
||||||
Settings::values.resolution_info.active;
|
|
||||||
#else
|
|
||||||
true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (should_rescale) {
|
|
||||||
Optimization::RescalingPass(program);
|
Optimization::RescalingPass(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optimization::DeadCodeEliminationPass(program);
|
Optimization::DeadCodeEliminationPass(program);
|
||||||
if (Settings::values.renderer_debug) {
|
if (Settings::values.renderer_debug) {
|
||||||
Optimization::VerificationPass(program);
|
Optimization::VerificationPass(program);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -63,10 +66,11 @@ void VisitMark(IR::Block& block, IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
if (must_patch_outside) {
|
if (must_patch_outside) {
|
||||||
const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
|
const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
|
||||||
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
|
IR::IREmitter ir{block, it};
|
||||||
const IR::F32 new_inst{&*block.PrependNewInst(it, inst)};
|
IR::Inst* const new_inst{&*block.PrependNewInst(it, inst)};
|
||||||
|
const IR::F32 new_bitcast{ir.ConvertUToF(32, 32, IR::Value{new_inst})};
|
||||||
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
|
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
|
||||||
const IR::Value converted{ir.FPMul(new_inst, up_factor)};
|
const IR::Value converted{ir.FPMul(new_bitcast, up_factor)};
|
||||||
inst.ReplaceUsesWith(converted);
|
inst.ReplaceUsesWith(converted);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ void Scheduler::EndRenderPass()
|
|||||||
Record([num_images = num_renderpass_images,
|
Record([num_images = num_renderpass_images,
|
||||||
images = renderpass_images,
|
images = renderpass_images,
|
||||||
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
|
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
|
||||||
std::array<VkImageMemoryBarrier, 9> barriers;
|
std::vector<VkImageMemoryBarrier> barriers(num_images);
|
||||||
VkPipelineStageFlags src_stages = 0;
|
VkPipelineStageFlags src_stages = 0;
|
||||||
for (size_t i = 0; i < num_images; ++i) {
|
for (size_t i = 0; i < num_images; ++i) {
|
||||||
const VkImageSubresourceRange& range = ranges[i];
|
const VkImageSubresourceRange& range = ranges[i];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "common/polyfill_thread.h"
|
#include "common/polyfill_thread.h"
|
||||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
@@ -111,15 +112,34 @@ public:
|
|||||||
return master_semaphore->IsFree(tick);
|
return master_semaphore->IsFree(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits for the given tick to trigger on the GPU.
|
/// Waits for the given GPU tick, optionally pacing frames.
|
||||||
void Wait(u64 tick) {
|
void Wait(u64 tick, double target_fps = 0.0) {
|
||||||
if (tick >= master_semaphore->CurrentTick()) {
|
if (Settings::values.use_speed_limit.GetValue() && target_fps > 0.0) {
|
||||||
// Make sure we are not waiting for the current tick without signalling
|
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
if (now < next_frame_time) {
|
||||||
|
std::this_thread::sleep_until(next_frame_time);
|
||||||
|
next_frame_time += frame_duration;
|
||||||
|
} else {
|
||||||
|
next_frame_time = now + frame_duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tick > master_semaphore->CurrentTick() && !chunk->Empty()) {
|
||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
master_semaphore->Wait(tick);
|
master_semaphore->Wait(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resets the frame pacing state by setting the next frame time.
|
||||||
|
void ResetFramePacing(double target_fps = 0.0) {
|
||||||
|
if (target_fps > 0.0) {
|
||||||
|
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
|
||||||
|
next_frame_time = std::chrono::steady_clock::now() + frame_duration;
|
||||||
|
} else {
|
||||||
|
next_frame_time = std::chrono::steady_clock::time_point{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the master timeline semaphore.
|
/// Returns the master timeline semaphore.
|
||||||
[[nodiscard]] MasterSemaphore& GetMasterSemaphore() const noexcept {
|
[[nodiscard]] MasterSemaphore& GetMasterSemaphore() const noexcept {
|
||||||
return *master_semaphore;
|
return *master_semaphore;
|
||||||
@@ -261,6 +281,8 @@ private:
|
|||||||
std::mutex queue_mutex;
|
std::mutex queue_mutex;
|
||||||
std::condition_variable_any event_cv;
|
std::condition_variable_any event_cv;
|
||||||
std::jthread worker_thread;
|
std::jthread worker_thread;
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point next_frame_time{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
@@ -146,6 +146,25 @@ void Swapchain::Create(
|
|||||||
{
|
{
|
||||||
is_outdated = false;
|
is_outdated = false;
|
||||||
is_suboptimal = false;
|
is_suboptimal = false;
|
||||||
|
|
||||||
|
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||||
|
case Settings::FramePacingMode::Target_Auto:
|
||||||
|
scheduler.ResetFramePacing();
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_30:
|
||||||
|
scheduler.ResetFramePacing(30.0);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_60:
|
||||||
|
scheduler.ResetFramePacing(60.0);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_120:
|
||||||
|
scheduler.ResetFramePacing(120.0);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_240:
|
||||||
|
scheduler.ResetFramePacing(240.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
width = width_;
|
width = width_;
|
||||||
height = height_;
|
height = height_;
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
@@ -194,7 +213,26 @@ bool Swapchain::AcquireNextImage() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.Wait(resource_ticks[image_index]);
|
if (resource_ticks[image_index] != 0 && !scheduler.IsFree(resource_ticks[image_index])) {
|
||||||
|
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||||
|
case Settings::FramePacingMode::Target_Auto:
|
||||||
|
scheduler.Wait(resource_ticks[image_index]);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_30:
|
||||||
|
scheduler.Wait(resource_ticks[image_index], 30.0);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_60:
|
||||||
|
scheduler.Wait(resource_ticks[image_index], 60.0);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_120:
|
||||||
|
scheduler.Wait(resource_ticks[image_index], 120.0);
|
||||||
|
break;
|
||||||
|
case Settings::FramePacingMode::Target_240:
|
||||||
|
scheduler.Wait(resource_ticks[image_index], 240.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resource_ticks[image_index] = scheduler.CurrentTick();
|
resource_ticks[image_index] = scheduler.CurrentTick();
|
||||||
|
|
||||||
return is_suboptimal || is_outdated;
|
return is_suboptimal || is_outdated;
|
||||||
|
|||||||
@@ -893,8 +893,10 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
if (Settings::values.gpu_unswizzle_enabled.GetValue()) {
|
||||||
staging_buffer_pool, compute_pass_descriptor_queue);
|
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||||
|
staging_buffer_pool, compute_pass_descriptor_queue);
|
||||||
|
}
|
||||||
|
|
||||||
// --- Create swizzle table buffer ---
|
// --- Create swizzle table buffer ---
|
||||||
{
|
{
|
||||||
@@ -2538,6 +2540,14 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
|||||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Settings::values.gpu_unswizzle_enabled.GetValue() || !bl3d_unswizzle_pass) {
|
||||||
|
if (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) {
|
||||||
|
ASSERT_MSG(false, "GPU unswizzle is disabled for BCn 3D texture");
|
||||||
|
}
|
||||||
|
ASSERT(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (bl3d_unswizzle_pass &&
|
if (bl3d_unswizzle_pass &&
|
||||||
IsPixelFormatBCn(image.info.format) &&
|
IsPixelFormatBCn(image.info.format) &&
|
||||||
image.info.type == ImageType::e3D &&
|
image.info.type == ImageType::e3D &&
|
||||||
|
|||||||
@@ -80,31 +80,39 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
|
|||||||
lowmemorydevice = true;
|
lowmemorydevice = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Settings::values.gpu_unswizzle_texture_size.GetValue()) {
|
const bool gpu_unswizzle_enabled = Settings::values.gpu_unswizzle_enabled.GetValue();
|
||||||
case Settings::GpuUnswizzleSize::VerySmall: gpu_unswizzle_maxsize = 16_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::Small: gpu_unswizzle_maxsize = 32_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::Normal: gpu_unswizzle_maxsize = 128_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::Large: gpu_unswizzle_maxsize = 256_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::VeryLarge: gpu_unswizzle_maxsize = 512_MiB; break;
|
|
||||||
default: gpu_unswizzle_maxsize = 128_MiB; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Settings::values.gpu_unswizzle_stream_size.GetValue()) {
|
if (gpu_unswizzle_enabled) {
|
||||||
case Settings::GpuUnswizzle::VeryLow: swizzle_chunk_size = 4_MiB; break;
|
switch (Settings::values.gpu_unswizzle_texture_size.GetValue()) {
|
||||||
case Settings::GpuUnswizzle::Low: swizzle_chunk_size = 8_MiB; break;
|
case Settings::GpuUnswizzleSize::VerySmall: gpu_unswizzle_maxsize = 16_MiB; break;
|
||||||
case Settings::GpuUnswizzle::Normal: swizzle_chunk_size = 16_MiB; break;
|
case Settings::GpuUnswizzleSize::Small: gpu_unswizzle_maxsize = 32_MiB; break;
|
||||||
case Settings::GpuUnswizzle::Medium: swizzle_chunk_size = 32_MiB; break;
|
case Settings::GpuUnswizzleSize::Normal: gpu_unswizzle_maxsize = 128_MiB; break;
|
||||||
case Settings::GpuUnswizzle::High: swizzle_chunk_size = 64_MiB; break;
|
case Settings::GpuUnswizzleSize::Large: gpu_unswizzle_maxsize = 256_MiB; break;
|
||||||
default: swizzle_chunk_size = 16_MiB;
|
case Settings::GpuUnswizzleSize::VeryLarge: gpu_unswizzle_maxsize = 512_MiB; break;
|
||||||
}
|
default: gpu_unswizzle_maxsize = 128_MiB; break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (Settings::values.gpu_unswizzle_chunk_size.GetValue()) {
|
switch (Settings::values.gpu_unswizzle_stream_size.GetValue()) {
|
||||||
case Settings::GpuUnswizzleChunk::VeryLow: swizzle_slices_per_batch = 32; break;
|
case Settings::GpuUnswizzle::VeryLow: swizzle_chunk_size = 4_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::Low: swizzle_slices_per_batch = 64; break;
|
case Settings::GpuUnswizzle::Low: swizzle_chunk_size = 8_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::Normal: swizzle_slices_per_batch = 128; break;
|
case Settings::GpuUnswizzle::Normal: swizzle_chunk_size = 16_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::Medium: swizzle_slices_per_batch = 256; break;
|
case Settings::GpuUnswizzle::Medium: swizzle_chunk_size = 32_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::High: swizzle_slices_per_batch = 512; break;
|
case Settings::GpuUnswizzle::High: swizzle_chunk_size = 64_MiB; break;
|
||||||
default: swizzle_slices_per_batch = 128;
|
default: swizzle_chunk_size = 16_MiB;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Settings::values.gpu_unswizzle_chunk_size.GetValue()) {
|
||||||
|
case Settings::GpuUnswizzleChunk::VeryLow: swizzle_slices_per_batch = 32; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::Low: swizzle_slices_per_batch = 64; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::Normal: swizzle_slices_per_batch = 128; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::Medium: swizzle_slices_per_batch = 256; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::High: swizzle_slices_per_batch = 512; break;
|
||||||
|
default: swizzle_slices_per_batch = 128;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gpu_unswizzle_maxsize = 0;
|
||||||
|
swizzle_chunk_size = 0;
|
||||||
|
swizzle_slices_per_batch = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1161,7 +1169,11 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
|
|||||||
QueueAsyncDecode(image, image_id);
|
QueueAsyncDecode(image, image_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (IsPixelFormatBCn(image.info.format) &&
|
|
||||||
|
const bool gpu_unswizzle_enabled = Settings::values.gpu_unswizzle_enabled.GetValue();
|
||||||
|
|
||||||
|
if (gpu_unswizzle_enabled &&
|
||||||
|
IsPixelFormatBCn(image.info.format) &&
|
||||||
image.info.type == ImageType::e3D &&
|
image.info.type == ImageType::e3D &&
|
||||||
image.info.resources.levels == 1 &&
|
image.info.resources.levels == 1 &&
|
||||||
image.info.resources.layers == 1 &&
|
image.info.resources.layers == 1 &&
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <span>
|
#include <span>
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
#include "common/dynamic_library.h"
|
#include "common/dynamic_library.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "video_core/vulkan_common/vulkan_instance.h"
|
#include "video_core/vulkan_common/vulkan_instance.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
@@ -80,8 +82,13 @@ namespace {
|
|||||||
if (enable_validation && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
if (enable_validation && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
// VK_EXT_surface_maintenance1 is required for VK_EXT_swapchain_maintenance1
|
// VK_EXT_surface_maintenance1 is required for VK_EXT_swapchain_maintenance1
|
||||||
if (window_type != Core::Frontend::WindowSystemType::Headless && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME}))
|
if (window_type != Core::Frontend::WindowSystemType::Headless && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME})) {
|
||||||
extensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
|
||||||
|
// Some(which?) drivers dont like being told to load this extension(why?)
|
||||||
|
// NVIDIA on FreeBSD is totally fine with this through
|
||||||
|
if (AreExtensionsSupported(dld, *properties, std::array{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME}))
|
||||||
|
extensions.push_back(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
// Qt on macOS doesn't define VMA shit
|
// Qt on macOS doesn't define VMA shit
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include "common/settings.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
#include "frontend_common/settings_generator.h"
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "qt_common/qt_string_lookup.h"
|
#include "qt_common/qt_string_lookup.h"
|
||||||
@@ -1406,12 +1407,12 @@ void MainWindow::InitializeHotkeys() {
|
|||||||
LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true);
|
LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true);
|
||||||
LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true);
|
LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true);
|
||||||
LinkActionShortcut(ui->action_View_Lobby,
|
LinkActionShortcut(ui->action_View_Lobby,
|
||||||
QStringLiteral("Multiplayer Browse Public Game Lobby"));
|
QStringLiteral("Browse Public Game Lobby"));
|
||||||
LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room"));
|
LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Create Room"));
|
||||||
LinkActionShortcut(ui->action_Connect_To_Room,
|
LinkActionShortcut(ui->action_Connect_To_Room,
|
||||||
QStringLiteral("Multiplayer Direct Connect to Room"));
|
QStringLiteral("Direct Connect to Room"));
|
||||||
LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Multiplayer Show Current Room"));
|
LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Show Current Room"));
|
||||||
LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Multiplayer Leave Room"));
|
LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Leave Room"));
|
||||||
LinkActionShortcut(ui->action_Configure, QStringLiteral("Configure"));
|
LinkActionShortcut(ui->action_Configure, QStringLiteral("Configure"));
|
||||||
LinkActionShortcut(ui->action_Configure_Current_Game, QStringLiteral("Configure Current Game"));
|
LinkActionShortcut(ui->action_Configure_Current_Game, QStringLiteral("Configure Current Game"));
|
||||||
|
|
||||||
@@ -1440,9 +1441,25 @@ void MainWindow::InitializeHotkeys() {
|
|||||||
connect_shortcut(QStringLiteral("Audio Mute/Unmute"), &MainWindow::OnMute);
|
connect_shortcut(QStringLiteral("Audio Mute/Unmute"), &MainWindow::OnMute);
|
||||||
connect_shortcut(QStringLiteral("Audio Volume Down"), &MainWindow::OnDecreaseVolume);
|
connect_shortcut(QStringLiteral("Audio Volume Down"), &MainWindow::OnDecreaseVolume);
|
||||||
connect_shortcut(QStringLiteral("Audio Volume Up"), &MainWindow::OnIncreaseVolume);
|
connect_shortcut(QStringLiteral("Audio Volume Up"), &MainWindow::OnIncreaseVolume);
|
||||||
connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
|
|
||||||
Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
|
connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [this] {
|
||||||
|
Settings::ToggleStandardMode();
|
||||||
|
const bool limited = Settings::values.use_speed_limit.GetValue();
|
||||||
|
m_fpsSuffix = limited ? QString{} : tr("Unlocked");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect_shortcut(QStringLiteral("Toggle Turbo Speed"), [this] {
|
||||||
|
Settings::ToggleTurboMode();
|
||||||
|
const bool turbo = Settings::values.current_speed_mode.GetValue() == Settings::SpeedMode::Turbo;
|
||||||
|
m_fpsSuffix = turbo ? tr("Turbo") : QString{};
|
||||||
|
});
|
||||||
|
|
||||||
|
connect_shortcut(QStringLiteral("Toggle Slow Speed"), [this] {
|
||||||
|
Settings::ToggleSlowMode();
|
||||||
|
const bool slow = Settings::values.current_speed_mode.GetValue() == Settings::SpeedMode::Slow;
|
||||||
|
m_fpsSuffix = slow ? tr("Slow") : QString{};
|
||||||
|
});
|
||||||
|
|
||||||
connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [] {
|
connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [] {
|
||||||
if (Settings::values.enable_renderdoc_hotkey) {
|
if (Settings::values.enable_renderdoc_hotkey) {
|
||||||
QtCommon::system->GetRenderdocAPI().ToggleCapture();
|
QtCommon::system->GetRenderdocAPI().ToggleCapture();
|
||||||
@@ -4254,14 +4271,15 @@ void MainWindow::UpdateStatusBar() {
|
|||||||
if (Settings::values.use_speed_limit.GetValue()) {
|
if (Settings::values.use_speed_limit.GetValue()) {
|
||||||
emu_speed_label->setText(tr("Speed: %1% / %2%")
|
emu_speed_label->setText(tr("Speed: %1% / %2%")
|
||||||
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
|
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
|
||||||
.arg(Settings::values.speed_limit.GetValue()));
|
.arg(Settings::SpeedLimit()));
|
||||||
} else {
|
} else {
|
||||||
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
|
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
game_fps_label->setText(
|
QString fpsText = tr("Game: %1 FPS").arg(std::round(results.average_game_fps), 0, 'f', 0);
|
||||||
tr("Game: %1 FPS").arg(std::round(results.average_game_fps), 0, 'f', 0) +
|
if (!m_fpsSuffix.isEmpty()) fpsText = fpsText % QStringLiteral(" (%1)").arg(m_fpsSuffix);
|
||||||
tr(Settings::values.use_speed_limit ? "" : " (Unlocked)"));
|
|
||||||
|
game_fps_label->setText(fpsText);
|
||||||
|
|
||||||
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
||||||
|
|
||||||
|
|||||||
@@ -518,6 +518,9 @@ private:
|
|||||||
QSlider* volume_slider = nullptr;
|
QSlider* volume_slider = nullptr;
|
||||||
QTimer status_bar_update_timer;
|
QTimer status_bar_update_timer;
|
||||||
|
|
||||||
|
// Stores what suffix to add to the FPS counter, e.g. Unlocked.
|
||||||
|
QString m_fpsSuffix{};
|
||||||
|
|
||||||
UserDataMigrator user_data_migrator;
|
UserDataMigrator user_data_migrator;
|
||||||
std::unique_ptr<QtConfig> config;
|
std::unique_ptr<QtConfig> config;
|
||||||
|
|
||||||
|
|||||||